Skip to content

Commit 35b2fd9

Browse files
authoredFeb 1, 2025··
Implement EPUB/WebPub exemptions (#184)
1 parent d935e76 commit 35b2fd9

File tree

6 files changed

+53
-2
lines changed

6 files changed

+53
-2
lines changed
 

‎pkg/manifest/a11y.go

+23
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type A11y struct {
1919
AccessModesSufficient [][]A11yPrimaryAccessMode `json:"accessModeSufficient,omitempty"` // A list of single or combined accessModes that are sufficient to understand all the intellectual content of a resource.
2020
Features []A11yFeature `json:"feature,omitempty"` // Content features of the resource, such as accessible media, alternatives and supported enhancements for accessibility.
2121
Hazards []A11yHazard `json:"hazard,omitempty"` // A characteristic of the described resource that is physiologically dangerous to some users.
22+
Exemptions []A11yExemption `json:"exemption,omitempty"` // Justifications for non-conformance based on exemptions in a given jurisdiction.
2223
}
2324

2425
// NewA11y creates a new empty A11y.
@@ -29,6 +30,7 @@ func NewA11y() A11y {
2930
AccessModesSufficient: [][]A11yPrimaryAccessMode{},
3031
Features: []A11yFeature{},
3132
Hazards: []A11yHazard{},
33+
Exemptions: []A11yExemption{},
3234
}
3335
}
3436

@@ -130,6 +132,12 @@ func A11yFromJSON(rawJSON map[string]interface{}) (*A11y, error) {
130132
}
131133
a.Hazards = A11yHazardsFromStrings(hazards)
132134

135+
examptions, err := parseSliceOrString(rawJSON["exemption"], true)
136+
if err != nil {
137+
return nil, errors.Wrap(err, "failed unmarshalling 'exemption'")
138+
}
139+
a.Exemptions = A11yExemptionsFromStrings(examptions)
140+
133141
return a, nil
134142
}
135143

@@ -433,6 +441,21 @@ func A11yHazardsFromStrings(strings []string) []A11yHazard {
433441
})
434442
}
435443

444+
// A11yExemption is a justification for non-conformance based on an exemption in a given jurisdiction.
445+
type A11yExemption string
446+
447+
const (
448+
A11yExemptionEAASisproportionateBurden A11yExemption = "eaa-disproportionate-burden"
449+
A11yExemptionEAAFundamentalAlteration A11yExemption = "eaa-fundamental-alteration"
450+
A11yExemptionEAAMicroenterprise A11yExemption = "eaa-microenterprise"
451+
)
452+
453+
func A11yExemptionsFromStrings(strings []string) []A11yExemption {
454+
return fromStrings(strings, func(str string) A11yExemption {
455+
return A11yExemption(str)
456+
})
457+
}
458+
436459
func fromStrings[T any](strings []string, transform func(string) T) []T {
437460
res := make([]T, 0, len(strings))
438461
for _, s := range strings {

‎pkg/manifest/a11y_test.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ func TestA11yUnmarshalFullJSON(t *testing.T) {
2626
"accessMode": ["auditory", "chartOnVisual"],
2727
"accessModeSufficient": [["visual", "tactile"]],
2828
"feature": ["readingOrder", "alternativeText"],
29-
"hazard": ["flashing", "motionSimulation"]
29+
"hazard": ["flashing", "motionSimulation"],
30+
"exemption": ["eaa-fundamental-alteration", "eaa-microenterprise"]
3031
}`), &m))
3132
assert.Equal(t, A11y{
3233
ConformsTo: []A11yProfile{
@@ -57,6 +58,10 @@ func TestA11yUnmarshalFullJSON(t *testing.T) {
5758
A11yHazardFlashing,
5859
A11yHazardMotionSimulation,
5960
},
61+
Exemptions: []A11yExemption{
62+
A11yExemptionEAAFundamentalAlteration,
63+
A11yExemptionEAAMicroenterprise,
64+
},
6065
}, m, "unmarshalled JSON object should be equal to A11y object")
6166
}
6267

@@ -101,6 +106,7 @@ func TestA11yMarshalMinimalJSON(t *testing.T) {
101106
AccessModesSufficient: [][]A11yPrimaryAccessMode{},
102107
Features: []A11yFeature{},
103108
Hazards: []A11yHazard{},
109+
Exemptions: []A11yExemption{},
104110
}
105111
data, err := json.Marshal(m)
106112
assert.NoError(t, err)
@@ -139,12 +145,16 @@ func TestA11yMarshalFullJSON(t *testing.T) {
139145
A11yHazardFlashing,
140146
A11yHazardMotionSimulation,
141147
},
148+
Exemptions: []A11yExemption{
149+
A11yExemptionEAAFundamentalAlteration,
150+
A11yExemptionEAAMicroenterprise,
151+
},
142152
}
143153
data, err := json.Marshal(m)
144154
assert.NoError(t, err)
145155
assert.Equal(
146156
t,
147157
data,
148-
[]byte(`{"conformsTo":["http://www.idpf.org/epub/a11y/accessibility-20170105.html#wcag-a","https://profile2"],"certification":{"certifiedBy":"company1","credential":"credential1","report":"https://report1"},"summary":"Summary","accessMode":["auditory","chartOnVisual"],"accessModeSufficient":[["auditory"],["visual","tactile"],["visual"]],"feature":["readingOrder","alternativeText"],"hazard":["flashing","motionSimulation"]}`),
158+
[]byte(`{"conformsTo":["http://www.idpf.org/epub/a11y/accessibility-20170105.html#wcag-a","https://profile2"],"certification":{"certifiedBy":"company1","credential":"credential1","report":"https://report1"},"summary":"Summary","accessMode":["auditory","chartOnVisual"],"accessModeSufficient":[["auditory"],["visual","tactile"],["visual"]],"feature":["readingOrder","alternativeText"],"hazard":["flashing","motionSimulation"],"exemption":["eaa-fundamental-alteration","eaa-microenterprise"]}`),
149159
)
150160
}

‎pkg/parser/epub/metadata.go

+10
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,7 @@ func (m PubMetadataAdapter) Accessibility() *manifest.A11y {
646646
a11y.AccessModesSufficient = m.a11yAccessModesSufficient()
647647
a11y.Features = m.a11yFeatures()
648648
a11y.Hazards = m.a11yHazards()
649+
a11y.Exemptions = m.a11yExemptions()
649650

650651
if a11y.IsEmpty() {
651652
return nil
@@ -785,6 +786,15 @@ func (m PubMetadataAdapter) a11yHazards() []manifest.A11yHazard {
785786
return hazards
786787
}
787788

789+
func (m PubMetadataAdapter) a11yExemptions() []manifest.A11yExemption {
790+
values := m.Values(VocabularyA11Y + "exemption")
791+
hazards := make([]manifest.A11yExemption, len(values))
792+
for i, v := range values {
793+
hazards[i] = manifest.A11yExemption(v)
794+
}
795+
return hazards
796+
}
797+
788798
func (m *PubMetadataAdapter) seedBelongsToData() {
789799
if m._belongsToSeeded {
790800
return

‎pkg/parser/epub/metadata_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ func TestMetadataEPUB2Accessibility(t *testing.T) {
323323
}
324324
e.Features = []manifest.A11yFeature{manifest.A11yFeatureStructuralNavigation, manifest.A11yFeatureAlternativeText}
325325
e.Hazards = []manifest.A11yHazard{manifest.A11yHazardMotionSimulation, manifest.A11yHazardNoSoundHazard}
326+
e.Exemptions = []manifest.A11yExemption{manifest.A11yExemptionEAAMicroenterprise, manifest.A11yExemptionEAAFundamentalAlteration}
326327
assert.Equal(t, &e, m.Accessibility)
327328
assert.Nil(t, m.OtherMetadata["accessibility"])
328329
}
@@ -345,6 +346,7 @@ func TestMetadataEPUB3Accessibility(t *testing.T) {
345346
}
346347
e.Features = []manifest.A11yFeature{manifest.A11yFeatureStructuralNavigation, manifest.A11yFeatureAlternativeText}
347348
e.Hazards = []manifest.A11yHazard{manifest.A11yHazardMotionSimulation, manifest.A11yHazardNoSoundHazard}
349+
e.Exemptions = []manifest.A11yExemption{manifest.A11yExemptionEAAMicroenterprise, manifest.A11yExemptionEAAFundamentalAlteration}
348350
assert.Equal(t, &e, m.Accessibility)
349351
assert.Nil(t, m.OtherMetadata["accessibility"])
350352
}

‎pkg/parser/epub/testdata/package/accessibility-epub2.opf

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
<meta name="a11y:certifiedBy" content="Accessibility Testers Group"/>
2121
<meta name="a11y:certifierCredential" content="DAISY OK"/>
2222
<meta name="a11y:certifierReport" content="https://example.com/a11y-report/"/>
23+
24+
<meta property="a11y:exemption">eaa-microenterprise</meta>
25+
<meta property="a11y:exemption">eaa-fundamental-alteration</meta>
2326
</metadata>
2427
<manifest>
2528
<item id="titlepage" href="titlepage.xhtml"/>

‎pkg/parser/epub/testdata/package/accessibility-epub3.opf

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<link rel="a11y:certifierReport" refines="#certifier2" href="https://example.com/fakereport"/>
2525
<link rel="a11y:certifierReport" refines="#certifier" href="https://example.com/a11y-report/"/>
2626

27+
<meta property="a11y:exemption">eaa-microenterprise</meta>
28+
<meta property="a11y:exemption">eaa-fundamental-alteration</meta>
29+
2730
</metadata>
2831
<manifest>
2932
<item id="titlepage" href="titlepage.xhtml"/>

0 commit comments

Comments
 (0)
Please sign in to comment.