@surea11y/core 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +81 -7
- package/LICENSE +373 -21
- package/README.md +175 -35
- package/bin/surea11y-core.js +20 -0
- package/docs/API_STABILITY.md +27 -1
- package/docs/BINDING_AUTHORS_GUIDE.md +9 -9
- package/docs/CI_INTEGRATIONS.md +103 -0
- package/docs/ENGINE_OPTIONS.md +2 -0
- package/docs/I18N.md +12 -9
- package/docs/INTEGRATION.md +19 -1
- package/docs/LIMITATIONS.md +1 -1
- package/docs/OUTPUT_SCHEMA.md +1 -1
- package/docs/REPORT.md +1 -1
- package/docs/RULE_CATALOG.md +1 -1
- package/docs/SARIF.md +59 -0
- package/package.json +63 -18
- package/src/baseline.js +0 -0
- package/src/checks/automatic/area-alt-present.js +63 -31
- package/src/checks/automatic/aria-allowed-attr.js +204 -80
- package/src/checks/automatic/aria-allowed-role.js +23 -7
- package/src/checks/automatic/aria-braille-equivalent.js +34 -10
- package/src/checks/automatic/aria-conditional-attr.js +32 -14
- package/src/checks/automatic/aria-deprecated-role.js +26 -11
- package/src/checks/automatic/aria-hidden-body.js +48 -23
- package/src/checks/automatic/aria-hidden-focus.js +420 -66
- package/src/checks/automatic/aria-prohibited-attr.js +327 -60
- package/src/checks/automatic/aria-prohibited-children.js +111 -103
- package/src/checks/automatic/aria-required-attr.js +29 -15
- package/src/checks/automatic/aria-required-children.js +44 -24
- package/src/checks/automatic/aria-required-parent.js +64 -35
- package/src/checks/automatic/aria-role-name-present.js +49 -21
- package/src/checks/automatic/aria-roles-valid.js +24 -12
- package/src/checks/automatic/aria-valid-attr-value.js +46 -22
- package/src/checks/automatic/aria-valid-attr.js +19 -5
- package/src/checks/automatic/autocomplete-valid.js +76 -16
- package/src/checks/automatic/avoid-inline-spacing.js +23 -8
- package/src/checks/automatic/binary-control-name-present.js +62 -50
- package/src/checks/automatic/button-name-present.js +54 -24
- package/src/checks/automatic/bypass-blocks-present.js +51 -32
- package/src/checks/automatic/canvas-text-alternative-present.js +59 -26
- package/src/checks/automatic/combobox-name-present.js +40 -45
- package/src/checks/automatic/contrast-computable.js +363 -341
- package/src/checks/automatic/contrast-enhanced.js +489 -466
- package/src/checks/automatic/contrast-minimum.js +488 -465
- package/src/checks/automatic/css-orientation-lock.js +51 -35
- package/src/checks/automatic/definition-list-children-valid.js +46 -25
- package/src/checks/automatic/deprecated-elements-not-used.js +25 -9
- package/src/checks/automatic/dialog-name-present.js +47 -85
- package/src/checks/automatic/dlitem-parent-valid.js +25 -8
- package/src/checks/automatic/duplicate-id-aria.js +28 -9
- package/src/checks/automatic/embed-text-alternative-present.js +88 -35
- package/src/checks/automatic/form-control-programmatic-label-present.js +81 -196
- package/src/checks/automatic/form-control-single-label.js +50 -14
- package/src/checks/automatic/html-xml-lang-mismatch.js +36 -18
- package/src/checks/automatic/iframe-focusable-content.js +265 -22
- package/src/checks/automatic/iframe-name-present.js +33 -9
- package/src/checks/automatic/iframe-title-unique.js +32 -9
- package/src/checks/automatic/img-alt-present.js +54 -52
- package/src/checks/automatic/input-image-alt-present.js +141 -112
- package/src/checks/automatic/label-in-name.js +65 -41
- package/src/checks/automatic/language-page-present.js +111 -109
- package/src/checks/automatic/link-in-text-block.js +61 -19
- package/src/checks/automatic/link-name-present.js +47 -14
- package/src/checks/automatic/list-children-valid.js +40 -33
- package/src/checks/automatic/listbox-name-present.js +41 -19
- package/src/checks/automatic/listitem-parent-valid.js +48 -13
- package/src/checks/automatic/menuitem-name-present.js +41 -61
- package/src/checks/automatic/meta-refresh-no-exceptions.js +32 -11
- package/src/checks/automatic/meta-refresh-timing-absent.js +22 -6
- package/src/checks/automatic/meta-viewport-zoom-enabled.js +26 -7
- package/src/checks/automatic/meter-name-present.js +40 -36
- package/src/checks/automatic/nested-interactive-controls-absent.js +58 -15
- package/src/checks/automatic/object-text-alternative-present.js +93 -39
- package/src/checks/automatic/option-name-present.js +40 -21
- package/src/checks/automatic/page-title-present.js +19 -6
- package/src/checks/automatic/progressbar-name-present.js +49 -44
- package/src/checks/automatic/role-img-alt-present.js +211 -159
- package/src/checks/automatic/searchbox-name-present.js +41 -19
- package/src/checks/automatic/server-side-image-map-absent.js +27 -11
- package/src/checks/automatic/slider-name-present.js +42 -47
- package/src/checks/automatic/spinbutton-name-present.js +41 -19
- package/src/checks/automatic/summary-name-present.js +39 -17
- package/src/checks/automatic/svg-image-text-alternative-present.js +116 -47
- package/src/checks/automatic/svg-text-alternative-present.js +262 -230
- package/src/checks/automatic/tab-name-present.js +39 -60
- package/src/checks/automatic/table-headers-attr-valid.js +27 -10
- package/src/checks/automatic/table-th-has-data-cells.js +24 -8
- package/src/checks/automatic/target-size-minimum.js +123 -48
- package/src/checks/automatic/td-has-header.js +53 -12
- package/src/checks/automatic/textbox-name-present.js +41 -19
- package/src/checks/automatic/tooltip-name-present.js +39 -18
- package/src/checks/automatic/treeitem-name-present.js +40 -21
- package/src/checks/automatic/valid-lang.js +22 -6
- package/src/checks/automatic/video-poster-text-alternative-present.js +81 -36
- package/src/checks/manual/accesskeys-manual.js +17 -6
- package/src/checks/manual/area-alt-decorative-manual.js +194 -193
- package/src/checks/manual/area-alt-quality-manual.js +184 -141
- package/src/checks/manual/aria-checked-state-mismatch-manual.js +48 -34
- package/src/checks/manual/aria-text-manual.js +20 -11
- package/src/checks/manual/canvas-text-alternative-quality-manual.js +151 -114
- package/src/checks/manual/css-hidden-focus.js +375 -169
- package/src/checks/manual/embed-text-alternative-quality-manual.js +178 -162
- package/src/checks/manual/empty-heading-manual.js +41 -24
- package/src/checks/manual/empty-table-header-manual.js +69 -31
- package/src/checks/manual/focus-order-semantics-manual.js +60 -13
- package/src/checks/manual/form-control-programmatic-label-quality-manual.js +209 -246
- package/src/checks/manual/heading-order-manual.js +50 -8
- package/src/checks/manual/identical-links-same-purpose-manual.js +36 -12
- package/src/checks/manual/image-redundant-alt-manual.js +38 -8
- package/src/checks/manual/img-alt-decorative-manual.js +133 -96
- package/src/checks/manual/img-alt-quality-manual.js +178 -127
- package/src/checks/manual/input-image-alt-decorative-manual.js +127 -92
- package/src/checks/manual/input-image-alt-quality-manual.js +127 -92
- package/src/checks/manual/label-title-only-manual.js +44 -28
- package/src/checks/manual/landmark-banner-is-top-level-manual.js +95 -38
- package/src/checks/manual/landmark-contentinfo-is-top-level-manual.js +85 -32
- package/src/checks/manual/landmark-main-is-top-level-manual.js +69 -27
- package/src/checks/manual/landmark-no-duplicate-banner-manual.js +45 -33
- package/src/checks/manual/landmark-no-duplicate-contentinfo-manual.js +43 -31
- package/src/checks/manual/landmark-no-duplicate-main-manual.js +27 -21
- package/src/checks/manual/landmark-one-main-manual.js +38 -43
- package/src/checks/manual/landmark-unique-manual.js +78 -67
- package/src/checks/manual/link-name-quality-manual.js +45 -12
- package/src/checks/manual/media-transcript-present-manual.js +37 -22
- package/src/checks/manual/meta-viewport-large-manual.js +19 -6
- package/src/checks/manual/mouse-only-event-handlers-manual.js +40 -11
- package/src/checks/manual/no-autoplay-audio-manual.js +22 -6
- package/src/checks/manual/object-text-alternative-quality-manual.js +177 -154
- package/src/checks/manual/p-as-heading-manual.js +24 -7
- package/src/checks/manual/page-has-heading-one-manual.js +42 -32
- package/src/checks/manual/page-title-patterns-manual.js +80 -50
- package/src/checks/manual/presentation-role-conflict-manual.js +101 -47
- package/src/checks/manual/region-manual.js +244 -60
- package/src/checks/manual/scope-attr-valid-manual.js +13 -4
- package/src/checks/manual/scrollable-region-focusable-manual.js +39 -11
- package/src/checks/manual/skip-link-manual.js +42 -18
- package/src/checks/manual/svg-text-alternative-quality-manual.js +208 -165
- package/src/checks/manual/tabindex-manual.js +13 -4
- package/src/checks/manual/table-duplicate-name-manual.js +22 -11
- package/src/checks/manual/table-fake-caption-manual.js +48 -10
- package/src/checks/manual/video-caption-manual.js +17 -4
- package/src/checks/manual-review.js +58 -12
- package/src/core.js +41705 -29650
- package/src/index.js +2 -0
- package/src/report.js +109 -47
- package/src/sarif.js +190 -0
- package/surea11y.browser.js +37774 -0
- package/bin/core.js +0 -348
- package/docs/CLI.md +0 -75
- package/src/catalogs/composites.wcag.js +0 -490
- package/src/checks/rules-and-tags.full.csv +0 -19
- package/src/checks/rules-and-tags.full.json +0 -259
- package/src/core/aria-helpers.js +0 -970
- package/src/core/contrast-helpers.js +0 -1147
- package/src/core/dom-helpers.js +0 -4235
- package/src/core/dom-runner.js +0 -671
- package/src/core/frame-messaging.js +0 -210
- package/src/core/frame-scan.js +0 -178
- package/src/core/rollup-composites.js +0 -135
- package/src/core/rule-meta.js +0 -159
- package/src/coverage/wcag-facets.js +0 -1079
- package/src/coverage/wcag-version-map.js +0 -84
- package/src/i18n/en.js +0 -923
- package/src/i18n/fr.js +0 -844
- package/src/policy/contracts.js +0 -18
- package/src/policy/resolvePolicy.js +0 -55
- package/src/policy/schemas/engine-options.schema.json +0 -103
- package/src/policy/schemas/policy-contract.schema.json +0 -40
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* SPDX-License-Identifier: MPL-2.0 */
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -12,9 +14,8 @@
|
|
|
12
14
|
* declare — either because WAI-ARIA has deprecated it (e.g. "directory",
|
|
13
15
|
* superseded by role="list") or because it's reserved for user-agent-
|
|
14
16
|
* internal use only, not a spec deprecation but the same "valid token,
|
|
15
|
-
* prohibited for authors" shape (role="generic" —
|
|
16
|
-
*
|
|
17
|
-
* not be used by web authors" guidance).
|
|
17
|
+
* prohibited for authors" shape (role="generic" — per WAI-ARIA 1.2 and
|
|
18
|
+
* MDN's "It should not be used by web authors" guidance).
|
|
18
19
|
* @expectation
|
|
19
20
|
* The role in use is neither deprecated nor author-prohibited. This is a
|
|
20
21
|
* distinct, atomic decision from aria-roles-valid (existence/
|
|
@@ -26,7 +27,8 @@ const id = 'aria-deprecated-role';
|
|
|
26
27
|
|
|
27
28
|
const meta = {
|
|
28
29
|
title: 'role attribute must not use a deprecated or author-prohibited ARIA role',
|
|
29
|
-
description:
|
|
30
|
+
description:
|
|
31
|
+
'Checks that an explicit role="" attribute does not use a role deprecated by the WAI-ARIA specification, or one reserved for user-agent-internal use only (e.g. role="generic").',
|
|
30
32
|
i18n: {
|
|
31
33
|
titleKey: 'ariaDeprecatedRole_title',
|
|
32
34
|
descriptionKey: 'ariaDeprecatedRole_description'
|
|
@@ -35,7 +37,13 @@ const meta = {
|
|
|
35
37
|
tags: ['wcag2a', 'wcag412', 'aria', 'structure', 'atomic', 'automatic'],
|
|
36
38
|
wcagSc: ['4.1.2'],
|
|
37
39
|
normativeMappings: [
|
|
38
|
-
{
|
|
40
|
+
{
|
|
41
|
+
standard: 'WCAG',
|
|
42
|
+
version: '2.2',
|
|
43
|
+
requirement: '4.1.2',
|
|
44
|
+
title: 'Name, Role, Value',
|
|
45
|
+
conformanceLevel: 'A'
|
|
46
|
+
}
|
|
39
47
|
],
|
|
40
48
|
defaultSeverity: 'moderate',
|
|
41
49
|
category: 'robust',
|
|
@@ -45,14 +53,16 @@ const meta = {
|
|
|
45
53
|
};
|
|
46
54
|
|
|
47
55
|
function runInPage(ctx) {
|
|
48
|
-
const {
|
|
56
|
+
const { helpers, rule } = ctx;
|
|
49
57
|
|
|
50
58
|
const ariaHelpers = helpers && helpers.aria ? helpers.aria : null;
|
|
51
59
|
if (!ariaHelpers) {
|
|
52
60
|
return { ruleId: rule.ruleId, outcome: 'notApplicable', severity: 'minor', occurrences: [] };
|
|
53
61
|
}
|
|
54
62
|
|
|
55
|
-
const nodes = helpers.queryAllSmart
|
|
63
|
+
const nodes = helpers.queryAllSmart
|
|
64
|
+
? helpers.queryAllSmart('[role]')
|
|
65
|
+
: helpers.queryAll('[role]');
|
|
56
66
|
|
|
57
67
|
const occurrences = [];
|
|
58
68
|
let applicableCount = 0;
|
|
@@ -72,10 +82,10 @@ function runInPage(ctx) {
|
|
|
72
82
|
if (!ariaHelpers.isDeprecatedRole(role)) continue;
|
|
73
83
|
|
|
74
84
|
const stableSelector = helpers.buildSelector ? helpers.buildSelector(el) : 'html';
|
|
75
|
-
const html = helpers.getOuterHtmlSnippet ? helpers.getOuterHtmlSnippet(el) :
|
|
85
|
+
const html = helpers.getOuterHtmlSnippet ? helpers.getOuterHtmlSnippet(el) : el.outerHTML || '';
|
|
76
86
|
const guidance = ariaHelpers.getDeprecatedRoleGuidance
|
|
77
|
-
|
|
78
|
-
|
|
87
|
+
? ariaHelpers.getDeprecatedRoleGuidance(role)
|
|
88
|
+
: 'Replace the deprecated role with its recommended replacement.';
|
|
79
89
|
|
|
80
90
|
occurrences.push({
|
|
81
91
|
selector: stableSelector,
|
|
@@ -97,7 +107,12 @@ function runInPage(ctx) {
|
|
|
97
107
|
return { ruleId: rule.ruleId, outcome: 'notApplicable', severity: 'minor', occurrences: [] };
|
|
98
108
|
}
|
|
99
109
|
if (occurrences.length) {
|
|
100
|
-
return {
|
|
110
|
+
return {
|
|
111
|
+
ruleId: rule.ruleId,
|
|
112
|
+
outcome: 'fail',
|
|
113
|
+
severity: rule.defaultSeverity || 'moderate',
|
|
114
|
+
occurrences
|
|
115
|
+
};
|
|
101
116
|
}
|
|
102
117
|
return { ruleId: rule.ruleId, outcome: 'pass', severity: 'minor', occurrences: [] };
|
|
103
118
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* SPDX-License-Identifier: MPL-2.0 */
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -14,17 +16,18 @@
|
|
|
14
16
|
* @expectation
|
|
15
17
|
* <body> does not have aria-hidden="true". Hiding the document body
|
|
16
18
|
* removes the entire page's content and structure from the
|
|
17
|
-
* accessibility tree at once —
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* accessibility tree at once — both 1.3.1 (Info and Relationships: the
|
|
20
|
+
* page's structure becomes entirely non-determinable) and 4.1.2 (Name,
|
|
21
|
+
* Role, Value: nothing in the document exposes a role/name/value any
|
|
22
|
+
* longer) apply.
|
|
21
23
|
*/
|
|
22
24
|
|
|
23
25
|
const id = 'aria-hidden-body';
|
|
24
26
|
|
|
25
27
|
const meta = {
|
|
26
28
|
title: 'The document <body> must not be aria-hidden',
|
|
27
|
-
description:
|
|
29
|
+
description:
|
|
30
|
+
'Checks that <body> does not have aria-hidden="true", which would remove the entire page from the accessibility tree.',
|
|
28
31
|
i18n: {
|
|
29
32
|
titleKey: 'ariaHiddenBody_title',
|
|
30
33
|
descriptionKey: 'ariaHiddenBody_description'
|
|
@@ -33,8 +36,20 @@ const meta = {
|
|
|
33
36
|
tags: ['wcag2a', 'wcag131', 'wcag412', 'structure', 'atomic', 'automatic'],
|
|
34
37
|
wcagSc: ['1.3.1', '4.1.2'],
|
|
35
38
|
normativeMappings: [
|
|
36
|
-
{
|
|
37
|
-
|
|
39
|
+
{
|
|
40
|
+
standard: 'WCAG',
|
|
41
|
+
version: '2.2',
|
|
42
|
+
requirement: '1.3.1',
|
|
43
|
+
title: 'Info and Relationships',
|
|
44
|
+
conformanceLevel: 'A'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
standard: 'WCAG',
|
|
48
|
+
version: '2.2',
|
|
49
|
+
requirement: '4.1.2',
|
|
50
|
+
title: 'Name, Role, Value',
|
|
51
|
+
conformanceLevel: 'A'
|
|
52
|
+
}
|
|
38
53
|
],
|
|
39
54
|
defaultSeverity: 'critical',
|
|
40
55
|
category: 'perceivable',
|
|
@@ -72,24 +87,34 @@ function runInPage(ctx) {
|
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
const stableSelector = helpers.buildSelector ? helpers.buildSelector(body) : 'body';
|
|
75
|
-
const html = helpers.getOuterHtmlSnippet
|
|
90
|
+
const html = helpers.getOuterHtmlSnippet
|
|
91
|
+
? helpers.getOuterHtmlSnippet(body)
|
|
92
|
+
: (body.outerHTML || '').slice(0, 200);
|
|
76
93
|
|
|
77
|
-
const occurrences = [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
94
|
+
const occurrences = [
|
|
95
|
+
{
|
|
96
|
+
selector: stableSelector,
|
|
97
|
+
html,
|
|
98
|
+
summary:
|
|
99
|
+
'The document body has aria-hidden="true", which hides the entire page from assistive technologies.',
|
|
100
|
+
hint: 'Remove aria-hidden from <body>. Hide specific elements instead, if that was the intent.',
|
|
101
|
+
i18n: {
|
|
102
|
+
summaryKey: 'ariaHiddenBody_summary_fail',
|
|
103
|
+
hintKey: 'ariaHiddenBody_hint_fail',
|
|
104
|
+
params: {}
|
|
105
|
+
},
|
|
106
|
+
data: {
|
|
107
|
+
details: { reasonCode: 'ARIA_HIDDEN_BODY' }
|
|
108
|
+
}
|
|
89
109
|
}
|
|
90
|
-
|
|
110
|
+
];
|
|
91
111
|
|
|
92
|
-
return {
|
|
112
|
+
return {
|
|
113
|
+
ruleId: rule.ruleId,
|
|
114
|
+
outcome: 'fail',
|
|
115
|
+
severity: rule.defaultSeverity || 'critical',
|
|
116
|
+
occurrences
|
|
117
|
+
};
|
|
93
118
|
}
|
|
94
119
|
|
|
95
|
-
module.exports = { id, meta, runInPage, applicability };
|
|
120
|
+
module.exports = { id, meta, runInPage, applicability };
|