Skip to content

Commit

Permalink
Implement EPUB/WebPub exemptions (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
chocolatkey authored Feb 1, 2025
1 parent d935e76 commit 35b2fd9
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 2 deletions.
23 changes: 23 additions & 0 deletions pkg/manifest/a11y.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type A11y struct {
AccessModesSufficient [][]A11yPrimaryAccessMode `json:"accessModeSufficient,omitempty"` // A list of single or combined accessModes that are sufficient to understand all the intellectual content of a resource.
Features []A11yFeature `json:"feature,omitempty"` // Content features of the resource, such as accessible media, alternatives and supported enhancements for accessibility.
Hazards []A11yHazard `json:"hazard,omitempty"` // A characteristic of the described resource that is physiologically dangerous to some users.
Exemptions []A11yExemption `json:"exemption,omitempty"` // Justifications for non-conformance based on exemptions in a given jurisdiction.
}

// NewA11y creates a new empty A11y.
Expand All @@ -29,6 +30,7 @@ func NewA11y() A11y {
AccessModesSufficient: [][]A11yPrimaryAccessMode{},
Features: []A11yFeature{},
Hazards: []A11yHazard{},
Exemptions: []A11yExemption{},
}
}

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

examptions, err := parseSliceOrString(rawJSON["exemption"], true)
if err != nil {
return nil, errors.Wrap(err, "failed unmarshalling 'exemption'")
}
a.Exemptions = A11yExemptionsFromStrings(examptions)

return a, nil
}

Expand Down Expand Up @@ -433,6 +441,21 @@ func A11yHazardsFromStrings(strings []string) []A11yHazard {
})
}

// A11yExemption is a justification for non-conformance based on an exemption in a given jurisdiction.
type A11yExemption string

const (
A11yExemptionEAASisproportionateBurden A11yExemption = "eaa-disproportionate-burden"
A11yExemptionEAAFundamentalAlteration A11yExemption = "eaa-fundamental-alteration"
A11yExemptionEAAMicroenterprise A11yExemption = "eaa-microenterprise"
)

func A11yExemptionsFromStrings(strings []string) []A11yExemption {
return fromStrings(strings, func(str string) A11yExemption {
return A11yExemption(str)
})
}

func fromStrings[T any](strings []string, transform func(string) T) []T {
res := make([]T, 0, len(strings))
for _, s := range strings {
Expand Down
14 changes: 12 additions & 2 deletions pkg/manifest/a11y_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ func TestA11yUnmarshalFullJSON(t *testing.T) {
"accessMode": ["auditory", "chartOnVisual"],
"accessModeSufficient": [["visual", "tactile"]],
"feature": ["readingOrder", "alternativeText"],
"hazard": ["flashing", "motionSimulation"]
"hazard": ["flashing", "motionSimulation"],
"exemption": ["eaa-fundamental-alteration", "eaa-microenterprise"]
}`), &m))
assert.Equal(t, A11y{
ConformsTo: []A11yProfile{
Expand Down Expand Up @@ -57,6 +58,10 @@ func TestA11yUnmarshalFullJSON(t *testing.T) {
A11yHazardFlashing,
A11yHazardMotionSimulation,
},
Exemptions: []A11yExemption{
A11yExemptionEAAFundamentalAlteration,
A11yExemptionEAAMicroenterprise,
},
}, m, "unmarshalled JSON object should be equal to A11y object")
}

Expand Down Expand Up @@ -101,6 +106,7 @@ func TestA11yMarshalMinimalJSON(t *testing.T) {
AccessModesSufficient: [][]A11yPrimaryAccessMode{},
Features: []A11yFeature{},
Hazards: []A11yHazard{},
Exemptions: []A11yExemption{},
}
data, err := json.Marshal(m)
assert.NoError(t, err)
Expand Down Expand Up @@ -139,12 +145,16 @@ func TestA11yMarshalFullJSON(t *testing.T) {
A11yHazardFlashing,
A11yHazardMotionSimulation,
},
Exemptions: []A11yExemption{
A11yExemptionEAAFundamentalAlteration,
A11yExemptionEAAMicroenterprise,
},
}
data, err := json.Marshal(m)
assert.NoError(t, err)
assert.Equal(
t,
data,
[]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"]}`),
[]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"]}`),
)
}
10 changes: 10 additions & 0 deletions pkg/parser/epub/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ func (m PubMetadataAdapter) Accessibility() *manifest.A11y {
a11y.AccessModesSufficient = m.a11yAccessModesSufficient()
a11y.Features = m.a11yFeatures()
a11y.Hazards = m.a11yHazards()
a11y.Exemptions = m.a11yExemptions()

if a11y.IsEmpty() {
return nil
Expand Down Expand Up @@ -785,6 +786,15 @@ func (m PubMetadataAdapter) a11yHazards() []manifest.A11yHazard {
return hazards
}

func (m PubMetadataAdapter) a11yExemptions() []manifest.A11yExemption {
values := m.Values(VocabularyA11Y + "exemption")
hazards := make([]manifest.A11yExemption, len(values))
for i, v := range values {
hazards[i] = manifest.A11yExemption(v)
}
return hazards
}

func (m *PubMetadataAdapter) seedBelongsToData() {
if m._belongsToSeeded {
return
Expand Down
2 changes: 2 additions & 0 deletions pkg/parser/epub/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ func TestMetadataEPUB2Accessibility(t *testing.T) {
}
e.Features = []manifest.A11yFeature{manifest.A11yFeatureStructuralNavigation, manifest.A11yFeatureAlternativeText}
e.Hazards = []manifest.A11yHazard{manifest.A11yHazardMotionSimulation, manifest.A11yHazardNoSoundHazard}
e.Exemptions = []manifest.A11yExemption{manifest.A11yExemptionEAAMicroenterprise, manifest.A11yExemptionEAAFundamentalAlteration}
assert.Equal(t, &e, m.Accessibility)
assert.Nil(t, m.OtherMetadata["accessibility"])
}
Expand All @@ -345,6 +346,7 @@ func TestMetadataEPUB3Accessibility(t *testing.T) {
}
e.Features = []manifest.A11yFeature{manifest.A11yFeatureStructuralNavigation, manifest.A11yFeatureAlternativeText}
e.Hazards = []manifest.A11yHazard{manifest.A11yHazardMotionSimulation, manifest.A11yHazardNoSoundHazard}
e.Exemptions = []manifest.A11yExemption{manifest.A11yExemptionEAAMicroenterprise, manifest.A11yExemptionEAAFundamentalAlteration}
assert.Equal(t, &e, m.Accessibility)
assert.Nil(t, m.OtherMetadata["accessibility"])
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/parser/epub/testdata/package/accessibility-epub2.opf
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
<meta name="a11y:certifiedBy" content="Accessibility Testers Group"/>
<meta name="a11y:certifierCredential" content="DAISY OK"/>
<meta name="a11y:certifierReport" content="https://example.com/a11y-report/"/>

<meta property="a11y:exemption">eaa-microenterprise</meta>
<meta property="a11y:exemption">eaa-fundamental-alteration</meta>
</metadata>
<manifest>
<item id="titlepage" href="titlepage.xhtml"/>
Expand Down
3 changes: 3 additions & 0 deletions pkg/parser/epub/testdata/package/accessibility-epub3.opf
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
<link rel="a11y:certifierReport" refines="#certifier2" href="https://example.com/fakereport"/>
<link rel="a11y:certifierReport" refines="#certifier" href="https://example.com/a11y-report/"/>

<meta property="a11y:exemption">eaa-microenterprise</meta>
<meta property="a11y:exemption">eaa-fundamental-alteration</meta>

</metadata>
<manifest>
<item id="titlepage" href="titlepage.xhtml"/>
Expand Down

0 comments on commit 35b2fd9

Please sign in to comment.