pour-engine 1.13.0 → 1.14.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/config/project.config.js
CHANGED
package/engine/rules/index.js
CHANGED
|
@@ -50,9 +50,12 @@ import ariaAttrValid from './wcag/4.1.2-aria-attr-valid.js';
|
|
|
50
50
|
// instead of claiming a failure (see the note in the rule file).
|
|
51
51
|
import ariaAllowedAttr from './wcag/4.1.2-aria-allowed-attr.js';
|
|
52
52
|
import ariaFieldName from './wcag/4.1.2-aria-field-name.js';
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
53
|
+
// Asks instead of asserting: a prohibited name on a generic element is a
|
|
54
|
+
// real ARIA MUST violation the browser silently drops, so it runs in the
|
|
55
|
+
// default scope as a review question (see the note in the rule file —
|
|
56
|
+
// it has been asserted, demoted, and now asks; same route as
|
|
57
|
+
// aria-allowed-attr).
|
|
58
|
+
import ariaLabelMisuse from './wcag/4.1.2-aria-label-misuse.js';
|
|
56
59
|
import roleRequiredAria from './wcag/4.1.2-role-required-aria.js';
|
|
57
60
|
import labelForValid from './wcag/4.1.2-label-for-valid.js';
|
|
58
61
|
import listitemParent from './wcag/1.3.1-listitem-parent.js';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// ARIA 1.2 §5.2.8.6 ("Roles which cannot be named"): for generic, "the
|
|
2
|
+
// element does not support name from author. Authors MUST NOT use the
|
|
3
|
+
// aria-label or aria-labelledby attributes to name the element." A label on
|
|
4
|
+
// a plain div/span/p breaks that MUST, so it is a real, provable authoring
|
|
5
|
+
// error — and browsers respond by dropping the prohibited name, which is
|
|
6
|
+
// exactly what makes the WCAG verdict undecidable from the DOM.
|
|
7
|
+
//
|
|
8
|
+
// It is not, on its own, a 4.1.2 failure. A static text container is not a
|
|
9
|
+
// "user interface component", and the dropped name leaves whatever name,
|
|
10
|
+
// role and value the element legitimately has untouched. Nothing is
|
|
11
|
+
// announced wrongly; nothing the criterion requires is provably absent.
|
|
12
|
+
//
|
|
13
|
+
// What CAN fail is the thing underneath: if the author reached for a label
|
|
14
|
+
// because assistive technology genuinely should announce this element — a
|
|
15
|
+
// hand-rolled widget missing its role, a region missing its landmark — then
|
|
16
|
+
// the name they wrote is invisible and the missing role is the defect.
|
|
17
|
+
// Whether that is so is exactly what the DOM cannot establish.
|
|
18
|
+
//
|
|
19
|
+
// This rule has lived on both sides of the line. It asserted under WCAG
|
|
20
|
+
// scope originally, was demoted to best-practice when an independent audit
|
|
21
|
+
// found its volume dominating WCAG results on news/commerce pages, and the
|
|
22
|
+
// demotion buried it: teams act on what a default audit shows, so a real
|
|
23
|
+
// ARIA MUST violation went unseen. Asking is the third option (the same
|
|
24
|
+
// route aria-allowed-attr took): it runs in the default scope, lands in
|
|
25
|
+
// needs-review rather than violations, and hands the human the one question
|
|
26
|
+
// that decides it.
|
|
27
|
+
/** Roles whose accessible name is built from their contents, so a label on
|
|
28
|
+
* anything inside them contributes to that name rather than being dropped. */
|
|
29
|
+
const NAME_FROM_CONTENT = 'a[href], button, summary, h1, h2, h3, h4, h5, h6, th, td,'
|
|
30
|
+
+ ' [role="button"], [role="link"], [role="menuitem"], [role="menuitemcheckbox"],'
|
|
31
|
+
+ ' [role="menuitemradio"], [role="option"], [role="tab"], [role="treeitem"],'
|
|
32
|
+
+ ' [role="checkbox"], [role="radio"], [role="switch"], [role="heading"],'
|
|
33
|
+
+ ' [role="cell"], [role="gridcell"], [role="columnheader"], [role="rowheader"], [role="tooltip"]';
|
|
34
|
+
|
|
35
|
+
export default {
|
|
36
|
+
id: 'aria-label-misuse',
|
|
37
|
+
impact: 'moderate',
|
|
38
|
+
tags: ['wcag2a', 'wcag412'],
|
|
39
|
+
help: 'aria-label on a generic element is dropped by the browser',
|
|
40
|
+
helpUrl: 'https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html',
|
|
41
|
+
selector: 'div[aria-label]:not([role]):not([tabindex]), span[aria-label]:not([role]):not([tabindex]), p[aria-label]:not([role]):not([tabindex])',
|
|
42
|
+
evaluate(element) {
|
|
43
|
+
// Inside a name-from-content ancestor the label is NOT ignored: accname
|
|
44
|
+
// applies the whole algorithm to each descendant while building the
|
|
45
|
+
// ancestor's name, so this label becomes the button's or link's name.
|
|
46
|
+
// Chromium reports exactly that. Claiming it does nothing is false, and
|
|
47
|
+
// the advised fix would delete the control's only name.
|
|
48
|
+
if (element.closest(NAME_FROM_CONTENT)) return { status: 'pass' };
|
|
49
|
+
return {
|
|
50
|
+
status: 'incomplete',
|
|
51
|
+
message: `aria-label="${element.getAttribute('aria-label')}" on a plain <${element.tagName.toLowerCase()}> is prohibited by ARIA and dropped by the browser, so assistive technology never sees it. Nothing is announced wrongly, but nothing is announced at all. Should this element be announced? If it plays a role worth naming — a widget, a region, a group — the missing role is the defect and this is a 4.1.2 failure. If it is just a styled container, the attribute is stray and no one is affected.`,
|
|
52
|
+
fix: 'If the element should be announced, give it the role it is playing (a landmark, group, or widget role) so the name is legal and exposed. If it should not, remove the aria-label. Do not add a role solely to legalise the label.',
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
package/package.json
CHANGED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
// aria-label on a generic element (plain div/span/p) is PROHIBITED by ARIA
|
|
2
|
-
// 1.2 — the role doesn't support naming, so conforming assistive technology
|
|
3
|
-
// ignores the label. That makes it an authoring defect worth surfacing, but
|
|
4
|
-
// NOT a WCAG failure: a static text container is not a "user interface
|
|
5
|
-
// component", so no success criterion (4.1.2 included) actually fails.
|
|
6
|
-
// Best-practice scope is the honest home; demoted from WCAG scope after an
|
|
7
|
-
// independent audit found it dominating WCAG results on news/commerce pages.
|
|
8
|
-
/** Roles whose accessible name is built from their contents, so a label on
|
|
9
|
-
* anything inside them contributes to that name rather than being dropped. */
|
|
10
|
-
const NAME_FROM_CONTENT = 'a[href], button, summary, h1, h2, h3, h4, h5, h6, th, td,'
|
|
11
|
-
+ ' [role="button"], [role="link"], [role="menuitem"], [role="menuitemcheckbox"],'
|
|
12
|
-
+ ' [role="menuitemradio"], [role="option"], [role="tab"], [role="treeitem"],'
|
|
13
|
-
+ ' [role="checkbox"], [role="radio"], [role="switch"], [role="heading"],'
|
|
14
|
-
+ ' [role="cell"], [role="gridcell"], [role="columnheader"], [role="rowheader"], [role="tooltip"]';
|
|
15
|
-
|
|
16
|
-
export default {
|
|
17
|
-
id: 'aria-label-misuse',
|
|
18
|
-
impact: 'moderate',
|
|
19
|
-
tags: ['best-practice'],
|
|
20
|
-
help: 'aria-label on generic elements is ignored by assistive technology',
|
|
21
|
-
helpUrl: 'https://www.w3.org/TR/using-aria/#practical-support-aria-label-aria-labelledby-and-aria-describedby',
|
|
22
|
-
selector: 'div[aria-label]:not([role]):not([tabindex]), span[aria-label]:not([role]):not([tabindex]), p[aria-label]:not([role]):not([tabindex])',
|
|
23
|
-
evaluate(element) {
|
|
24
|
-
// Inside a name-from-content ancestor the label is NOT ignored: accname
|
|
25
|
-
// applies the whole algorithm to each descendant while building the
|
|
26
|
-
// ancestor's name, so this label becomes the button's or link's name.
|
|
27
|
-
// Chromium reports exactly that. Claiming it does nothing is false, and
|
|
28
|
-
// the advised fix would delete the control's only name.
|
|
29
|
-
if (element.closest(NAME_FROM_CONTENT)) return { status: 'pass' };
|
|
30
|
-
return {
|
|
31
|
-
status: 'fail',
|
|
32
|
-
message: `aria-label="${element.getAttribute('aria-label')}" on a plain <${element.tagName.toLowerCase()}> does nothing — screen readers only announce labels on interactive elements or landmarks.`,
|
|
33
|
-
fix: 'Give the element a suitable role (or use a landmark/heading), or remove the aria-label.',
|
|
34
|
-
};
|
|
35
|
-
},
|
|
36
|
-
};
|