ultra11y 5.37.1 → 5.38.1
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.opencode/plugins/ultra11y.js +1 -1
- package/README.md +43 -7
- package/dist/playwright.mjs +24 -4
- package/package.json +1 -1
- package/scripts/build-pack-rgaa.mjs +39 -6
- package/scripts/build-standards.mjs +9 -7
- package/scripts/ultra11y.mjs +715 -123
- package/skills/review-a11y/SKILL.md +1 -1
- package/skills/review-a11y/scripts/ultra11y.mjs +715 -123
- package/skills/ultra11y/SKILL.md +4 -4
- package/skills/ultra11y/references/act.md +17 -14
- package/skills/ultra11y/references/ci.md +1 -1
- package/skills/ultra11y/references/criteria.md +6 -6
- package/skills/ultra11y/references/judgment.md +3 -3
- package/skills/ultra11y/references/mcp.md +1 -1
- package/skills/ultra11y/references/pages.md +6 -6
- package/skills/ultra11y/references/rgaa-automation.md +37 -37
- package/skills/ultra11y/scripts/ultra11y.mjs +715 -123
- package/src/act.ts +20 -8
- package/src/audit.ts +22 -1
- package/src/check.ts +50 -8
- package/src/cli.ts +17 -8
- package/src/data/standards/rgaa.json +139 -36
- package/src/data/wcag.json +11 -4
- package/src/llm.ts +18 -1
- package/src/messages.ts +80 -0
- package/src/name.ts +68 -8
- package/src/parse/html.ts +16 -0
- package/src/parse/jsx-bridge.ts +11 -2
- package/src/prd.ts +2 -1
- package/src/probes.ts +24 -4
- package/src/rules/forms.ts +24 -5
- package/src/rules/links.ts +108 -52
- package/src/rules/mandatory.ts +103 -3
- package/src/rules/presentation.ts +63 -1
- package/src/rules/scripts-aria.ts +74 -1
- package/src/rules/tables.ts +19 -0
- package/src/scan.ts +5 -1
- package/src/standards/derive.ts +14 -3
- package/src/standards/document.ts +12 -5
- package/src/types.ts +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "ultra11y",
|
|
11
11
|
"source": "./",
|
|
12
12
|
"description": "Automatic accessibility review of the code under change before every commit, push and pull request, plus full WCAG 2.2 AA / RGAA audits and conformance deliverables on demand.",
|
|
13
|
-
"version": "5.
|
|
13
|
+
"version": "5.38.1",
|
|
14
14
|
"author": { "name": "maxgfr" },
|
|
15
15
|
"homepage": "https://github.com/maxgfr/ultra11y",
|
|
16
16
|
"repository": "https://github.com/maxgfr/ultra11y",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
3
|
"description": "Accessibility for WCAG 2.2 AA and country standards (RGAA…): an automatic review of the code under change before every commit, push and pull request, plus full audits and conformance deliverables on demand.",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.38.1",
|
|
5
5
|
"author": { "name": "maxgfr" },
|
|
6
6
|
"homepage": "https://github.com/maxgfr/ultra11y",
|
|
7
7
|
"repository": "https://github.com/maxgfr/ultra11y",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
3
|
"description": "Accessibility for WCAG 2.2 AA and country standards (RGAA…): an automatic review of the code under change before every commit, push and pull request, plus full audits and conformance deliverables on demand.",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.38.1",
|
|
5
5
|
"author": { "name": "maxgfr", "url": "https://github.com/maxgfr" },
|
|
6
6
|
"homepage": "https://github.com/maxgfr/ultra11y",
|
|
7
7
|
"repository": "https://github.com/maxgfr/ultra11y",
|
|
@@ -27,7 +27,7 @@ import { fileURLToPath } from "node:url";
|
|
|
27
27
|
// Ownership marker: `ultra11y install --opencode` refuses to overwrite a plugin file that
|
|
28
28
|
// does not carry it, so a user's own ultra11y.js is never clobbered.
|
|
29
29
|
const ULTRA11Y_OPENCODE_PLUGIN = "ULTRA11Y_OPENCODE_PLUGIN";
|
|
30
|
-
const ULTRA11Y_PLUGIN_VERSION = "5.
|
|
30
|
+
const ULTRA11Y_PLUGIN_VERSION = "5.38.1";
|
|
31
31
|
|
|
32
32
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
33
33
|
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Full details, thresholds and off-switches under [Install](#install).</sub>
|
|
|
25
25
|
|
|
26
26
|
> Audit HTML/CSS/JSX against **WCAG 2.2 AA** accessibility and produce a dated compliance report — or author/review accessible markup without regressions. A [skills.sh](https://skills.sh) agent skill: a deterministic, zero-dependency static engine **plus** the agent's judgment, with `check`/`verify` gates against hallucinated non-conformities. **The central deliverable is the auditor conformance block** — theme, criterion + official wording, test(s), WCAG mapping + level, finding, expected state, verification, `file:line` occurrences — rendered identically by the `report` (compliance doc), the `prd` backlog and the GitHub issues, in the active standard's vocabulary and **in your language** (`--lang auto` follows the conversation/repo). **WCAG is the worldwide core; country standards (RGAA, …) are pluggable in-repo packs.**
|
|
27
27
|
|
|
28
|
-
ultra11y is built around an honest **division of labour**. Automated tools only catch a fraction of accessibility problems, so the engine does the *mechanical* work —
|
|
28
|
+
ultra11y is built around an honest **division of labour**. Automated tools only catch a fraction of accessibility problems, so the engine does the *mechanical* work — 93 machine-detectable static checks tied to the WCAG 2.2 success criteria — and is explicit about everything it can't decide statically. What it can't, the **AI agent adjudicates** (statically, from the evidence, gated by `verify`/`check`) — not a deferral to a human:
|
|
29
29
|
|
|
30
30
|
- **Automatable (engine):** missing `alt`/`lang`/`title`, unlabeled fields, empty links/buttons, icon-only controls, iframes without title, tables without headers, heading-level skips, empty/dangling headings & labels, duplicate ids, invalid/broken ARIA, positive `tabindex`, autoplay/timed-refresh/`blink`/`marquee` media…
|
|
31
31
|
- **Agent judgment (gated):** alt-text relevance, link purpose in context, reading/tab order, caption accuracy — the agent rules on these via `verify --manual` → `--apply`, each verdict carrying a justification (or a groundable NC), never a silent "conforming".
|
|
@@ -41,11 +41,11 @@ A self-authored fixture can only prove that a rule fires on the defect written f
|
|
|
41
41
|
|
|
42
42
|
| | |
|
|
43
43
|
|---|---|
|
|
44
|
-
| Rules scored | **
|
|
45
|
-
| `failed` examples caught | **
|
|
46
|
-
| `passed` / `inapplicable` examples left alone | **
|
|
44
|
+
| Rules scored | **40** (the ACT rules an equivalent engine check exists for) |
|
|
45
|
+
| `failed` examples caught | **125 / 176** |
|
|
46
|
+
| `passed` / `inapplicable` examples left alone | **364 / 364** — no unexplained false positive |
|
|
47
47
|
| Deliberate divergences | 9, each argued on the record |
|
|
48
|
-
| Declared gaps (statically decidable, not implemented) |
|
|
48
|
+
| Declared gaps (statically decidable, not implemented) | 5 |
|
|
49
49
|
|
|
50
50
|
Rules needing a rendered page (computed contrast, keyboard traps) or a human call (is this heading descriptive?) are **declared and routed**, not silently scored zero. The full per-rule matrix — including every gap and every divergence — is generated into [`skills/ultra11y/references/act.md`](skills/ultra11y/references/act.md) and re-checked on every build; the corpus itself is refreshed daily by a workflow, so the numbers cannot quietly go stale.
|
|
51
51
|
|
|
@@ -314,6 +314,42 @@ where a reader goes looking for it.
|
|
|
314
314
|
others are welcome — adding a country is a single PR (pack JSON + one registration line +
|
|
315
315
|
a test). See [`CONTRIBUTING.md`](CONTRIBUTING.md) and `skills/ultra11y/references/standards.md`.
|
|
316
316
|
|
|
317
|
+
### What RGAA automation actually covers
|
|
318
|
+
|
|
319
|
+
The engine's 93 rules are not 93 RGAA criteria: several rules can evidence the same official
|
|
320
|
+
test, and a rule can detect a useful symptom without exhausting the criterion's alternatives,
|
|
321
|
+
exceptions or relevance checks. The generated contract classifies all **258 official RGAA
|
|
322
|
+
tests**:
|
|
323
|
+
|
|
324
|
+
- **27 `static` tests across 19 criteria:** `1.1`, `2.1`, `5.7`, `5.8`, `6.2`, `7.1`,
|
|
325
|
+
`8.2`, `8.3`, `8.4`, `8.5`, `8.10`, `9.3`, `10.1`, `10.12`, `11.1`, `11.5`,
|
|
326
|
+
`11.6`, `11.8`, `11.9`.
|
|
327
|
+
- **3 `rendered` tests across 3 criteria:** `1.1`, `8.1`, `10.7`.
|
|
328
|
+
- Those two tiers cover **21 distinct criteria that can produce a deterministic `NC`**;
|
|
329
|
+
`1.1` belongs to both.
|
|
330
|
+
- **49 criteria receive a normative engine signal:** 21 have at least one decisive rule and
|
|
331
|
+
41 receive candidate evidence, with overlap. One additional criterion receives only an
|
|
332
|
+
advisory signal. A candidate is forwarded to adjudication and never changes a verdict by
|
|
333
|
+
itself.
|
|
334
|
+
- Only **8.3, 8.5 and 10.1** may earn `C` from a complete silent measurement. For the other
|
|
335
|
+
mechanically detectable tests, silence can mean “no subject found” or “an alternative or
|
|
336
|
+
exception still needs judging”, so it cannot prove conformity.
|
|
337
|
+
- The remaining **228 `judgment` tests across 92 criteria** all enter the AI worklist,
|
|
338
|
+
including an apparently absent subject whose `NA` still needs confirmation. Overall,
|
|
339
|
+
**103 of 106 criteria require adjudication to earn `C`**.
|
|
340
|
+
|
|
341
|
+
The number can grow, but the useful target is **more observed, exact failures**, not a larger
|
|
342
|
+
marketing count. The best next candidates are complete rendered probes for zoom/reflow and
|
|
343
|
+
hover content (10.4, 10.11, 10.13), and contrast,
|
|
344
|
+
link distinction or orientation checks (3.2, 3.3, 10.6, 13.9) that first rule out every
|
|
345
|
+
official alternative and particular case. The 5 declared ACT gaps are another implementation
|
|
346
|
+
queue, although adding one does not necessarily cover a new RGAA criterion. A candidate is
|
|
347
|
+
promoted only when a narrower rule demonstrably exhausts its cited official test; the two
|
|
348
|
+
`C`-by-silence criteria stay unchanged until an equally complete proof exists.
|
|
349
|
+
|
|
350
|
+
The generated [106-criterion / 258-test matrix](skills/ultra11y/references/rgaa-automation.md)
|
|
351
|
+
is the source of truth; CI rebuilds it from the vendored DINUM data and rejects drift.
|
|
352
|
+
|
|
317
353
|
### Scale, fixes, and repo automation
|
|
318
354
|
|
|
319
355
|
- **Scale** — the engine streams file-by-file (bounded memory), audits **only markup**,
|
|
@@ -372,8 +408,8 @@ a test). See [`CONTRIBUTING.md`](CONTRIBUTING.md) and `skills/ultra11y/reference
|
|
|
372
408
|
Each can say *"I don't know"*: an unresolvable backdrop, a varied region, a cross-origin
|
|
373
409
|
stylesheet, a `box-shadow` that might be the boundary — all leave the criterion undecided
|
|
374
410
|
rather than guessed, and without signals the rules do not fire, so no pre-existing verdict
|
|
375
|
-
changes. `tests/rgaa-coverage.test.ts`
|
|
376
|
-
|
|
411
|
+
changes. `tests/rgaa-coverage.test.ts` pins a floor of **50 of 106** RGAA criteria mapped
|
|
412
|
+
onto an engine rule, up from 43 before this tier; silently losing one fails CI.
|
|
377
413
|
- **Every scanned page is a snapshot** — `scan` no longer keeps only findings: each page it
|
|
378
414
|
visits is persisted to `.ultra11y/pages/<id>/` (`--no-snapshot` opts out). That is what turns
|
|
379
415
|
a URL into a real per-page verdict — a page known only by its URL can never be conforming by
|
package/dist/playwright.mjs
CHANGED
|
@@ -136,10 +136,30 @@ var COLLECT_SNAPSHOT = `(() => {
|
|
|
136
136
|
var PRELUDE = `
|
|
137
137
|
const __sel = (e) => {
|
|
138
138
|
if (!e || !e.tagName) return '\u2014';
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
139
|
+
const esc = (v) => (typeof CSS !== 'undefined' && CSS.escape) ? CSS.escape(v) : String(v).replace(/[^a-zA-Z0-9_-]/g, '\\\\$&');
|
|
140
|
+
const unique = (s) => { try { return document.querySelectorAll(s).length === 1; } catch { return false; } };
|
|
141
|
+
const short = (n) => {
|
|
142
|
+
const t = n.tagName.toLowerCase();
|
|
143
|
+
if (n.id) return t + '#' + esc(n.id);
|
|
144
|
+
const c = typeof n.className === 'string' ? n.className.trim().split(/\\s+/)[0] : '';
|
|
145
|
+
return c ? t + '.' + esc(c) : t;
|
|
146
|
+
};
|
|
147
|
+
const first = short(e);
|
|
148
|
+
if (unique(first)) return first;
|
|
149
|
+
const parts = [];
|
|
150
|
+
for (let n = e; n && n.tagName; n = n.parentElement) {
|
|
151
|
+
let part = short(n);
|
|
152
|
+
if (n.id && unique(part)) { parts.unshift(part); return parts.join(' > '); }
|
|
153
|
+
const parent = n.parentElement;
|
|
154
|
+
if (parent) {
|
|
155
|
+
const same = Array.from(parent.children).filter((x) => x.tagName === n.tagName);
|
|
156
|
+
if (same.length > 1) part += ':nth-of-type(' + (same.indexOf(n) + 1) + ')';
|
|
157
|
+
}
|
|
158
|
+
parts.unshift(part);
|
|
159
|
+
const path = parts.join(' > ');
|
|
160
|
+
if (unique(path)) return path;
|
|
161
|
+
}
|
|
162
|
+
return parts.join(' > ') || first;
|
|
143
163
|
};
|
|
144
164
|
const __vis = (e) => {
|
|
145
165
|
const r = e.getBoundingClientRect();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.38.1",
|
|
4
4
|
"description": "Audit HTML/CSS/JSX against WCAG 2.2 AA and produce a dated compliance report, or author/review accessible markup (native-HTML-first). A skills.sh agent skill: an install-free static engine (bundled, no npm install) plus the agent's judgment, with check/verify gates against hallucinated non-conformities, and pluggable in-repo standards packs (RGAA France first; Section 508 & EN 301 549 next).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.33.0",
|
|
@@ -130,6 +130,10 @@ const RULE_SC = {
|
|
|
130
130
|
"clickable-noninteractive": ["4.1.2", "2.1.1"], "contrast-literal": ["1.4.3"], "control-label-missing": ["4.1.2"],
|
|
131
131
|
"rendered-contrast": ["1.4.3"], "rendered-contrast-pixel": ["1.4.3"], "rendered-link-colour-only": ["1.4.1"],
|
|
132
132
|
"rendered-nontext-contrast": ["1.4.11"], "rendered-focus-not-visible": ["2.4.7"], "rendered-orientation-lock": ["1.3.4"],
|
|
133
|
+
"document-language-missing": ["3.1.1"], "html-lang-xml-lang-mismatch": ["3.1.1"], "duplicate-attribute": ["4.1.2"],
|
|
134
|
+
"presentational-children-focusable": ["4.1.2"], "decorative-marked-exposed": ["1.1.1", "4.1.2"], "menuitem-empty-name": ["4.1.2"],
|
|
135
|
+
"letter-spacing-important": ["1.4.12"], "word-spacing-important": ["1.4.12"], "line-height-important": ["1.4.12"],
|
|
136
|
+
"table-scope-invalid": ["1.3.1"],
|
|
133
137
|
"css-generated-content-informative": ["1.3.1"], "date-fields-ungrouped": ["3.3.2"], "disabled-context-content": ["4.1.2"],
|
|
134
138
|
"control-name-title-only": ["4.1.2"], "cross-icon-only-unnamed": ["4.1.2"],
|
|
135
139
|
"cross-prop-drilled-name-lost": ["4.1.2"], "data-table-no-headers": ["1.3.1"],
|
|
@@ -180,6 +184,7 @@ const RULE_TO_CRITERIA = {
|
|
|
180
184
|
"chart-no-accessible-name": ["1.1"], "canvas-fallback-missing": ["1.1"], "axe:image-alt": ["1.1"],
|
|
181
185
|
"axe:input-image-alt": ["1.1"], "axe:area-alt": ["1.1"], "axe:role-img-alt": ["1.1"], "axe:svg-img-alt": ["1.1"],
|
|
182
186
|
"axe:object-alt": ["1.1"], "decorative-alt-misuse": ["1.2"], "axe:image-redundant-alt": ["1.2"],
|
|
187
|
+
"decorative-marked-exposed": ["1.2"],
|
|
183
188
|
// Theme 2 — frames (2.1 frame title)
|
|
184
189
|
"iframe-title-missing": ["2.1"], "axe:frame-title": ["2.1"], "axe:frame-title-unique": ["2.1"],
|
|
185
190
|
// Theme 3 — colour contrast. RGAA 10.5 asks about paired CSS declarations, not the
|
|
@@ -206,6 +211,7 @@ const RULE_TO_CRITERIA = {
|
|
|
206
211
|
// Theme 5 — tables (5.4 title, 5.6/5.7 headers, 5.8 layout-table markup)
|
|
207
212
|
"table-caption-missing": ["5.4"], "data-table-no-headers": ["5.6", "5.7"],
|
|
208
213
|
"layout-table-data-markup": ["5.8"], "axe:td-headers-attr": ["5.7"], "axe:th-has-data-cells": ["5.6"],
|
|
214
|
+
"headers-attr-dangling": ["5.7"], "table-scope-invalid": ["5.7"], "th-no-data-cells": ["5.6"],
|
|
209
215
|
"axe:scope-attr-valid": ["5.7"], "axe:td-has-header": ["5.6"], "axe:table-fake-caption": ["5.8"],
|
|
210
216
|
// Theme 6 — links (6.2 link label)
|
|
211
217
|
"link-empty-name": ["6.2"], "icon-only-control-unnamed": ["6.2", "11.9"], "cross-icon-only-unnamed": ["11.9"],
|
|
@@ -214,6 +220,8 @@ const RULE_TO_CRITERIA = {
|
|
|
214
220
|
"invalid-aria-role": ["7.1"], "aria-ref-missing-id": ["7.1"], "aria-required-children": ["7.1"],
|
|
215
221
|
"aria-hidden-focusable": ["7.1"], "redundant-aria": ["7.1"], "nested-interactive": ["7.1"],
|
|
216
222
|
"cross-prop-drilled-name-lost": ["7.1"],
|
|
223
|
+
"presentational-children-focusable": ["7.1"], "menuitem-empty-name": ["7.1"],
|
|
224
|
+
"button-empty-name": ["7.1"], "label-in-name-mismatch": ["7.1"],
|
|
217
225
|
"clickable-noninteractive": ["7.3"], "live-region-conflict": ["7.5"], "status-message-not-assertive": ["7.5"],
|
|
218
226
|
// Dynamic tier (scan --local): the live-region probe projects onto WCAG 4.1.3 → RGAA 7.5
|
|
219
227
|
// (status messages) — the WCAG-faithful home. Ara ALSO classifies the source finding under
|
|
@@ -226,10 +234,13 @@ const RULE_TO_CRITERIA = {
|
|
|
226
234
|
"axe:aria-required-attr": ["7.1"], "axe:aria-required-children": ["7.1"], "axe:aria-required-parent": ["7.1"],
|
|
227
235
|
"axe:aria-valid-attr": ["7.1"], "axe:aria-valid-attr-value": ["7.1"], "axe:nested-interactive": ["7.1"],
|
|
228
236
|
"axe:aria-hidden-focus": ["7.1"], "axe:presentation-role-conflict": ["7.1"],
|
|
237
|
+
"axe:button-name": ["7.1"], "axe:input-button-name": ["7.1"],
|
|
229
238
|
// Theme 8 — document (8.2 valid code, 8.3 default lang, 8.4 lang relevant, 8.5 title, 8.7/8.8 lang changes)
|
|
230
239
|
"duplicate-id": ["8.2"], "axe:duplicate-id": ["8.2"], "axe:duplicate-id-aria": ["8.2"], "axe:duplicate-id-active": ["8.2"],
|
|
231
240
|
"html-lang-missing": ["8.3"], "axe:html-has-lang": ["8.3"],
|
|
241
|
+
"document-language-missing": ["8.3"],
|
|
232
242
|
"lang-invalid": ["8.4", "8.8"], "axe:html-lang-valid": ["8.4"], "axe:html-xml-lang-mismatch": ["8.4"], "axe:valid-lang": ["8.8"],
|
|
243
|
+
"html-lang-xml-lang-mismatch": ["8.4"], "duplicate-attribute": ["8.2"],
|
|
233
244
|
"title-missing-empty": ["8.5"], "axe:document-title": ["8.5"], "inline-lang-change-missing": ["8.7"],
|
|
234
245
|
// Theme 9 — structure (9.1 headings, 9.2 doc structure, 9.3 lists)
|
|
235
246
|
"h1-missing": ["9.1"], "h1-multiple": ["9.1"], "heading-order-skip": ["9.1"], "empty-heading": ["9.1"],
|
|
@@ -241,6 +252,7 @@ const RULE_TO_CRITERIA = {
|
|
|
241
252
|
"css-generated-content-informative": ["10.2"],
|
|
242
253
|
"meta-viewport-zoom-block": ["10.4"], "axe:meta-viewport": ["10.4"], "axe:meta-viewport-large": ["10.4"],
|
|
243
254
|
"dyn-reflow": ["10.11"], "dyn-reflow-zoom": ["10.4"], "dyn-focus-visible": ["10.7"], "dyn-text-spacing": ["10.12"], "dyn-hover": ["10.13"],
|
|
255
|
+
"letter-spacing-important": ["10.12"], "word-spacing-important": ["10.12"], "line-height-important": ["10.12"],
|
|
244
256
|
// Stateful input-overflow probes — a filled input clipped under each stress, same RGAA
|
|
245
257
|
// theme as the corresponding reflow/zoom/text-spacing residual probe above.
|
|
246
258
|
"dyn-input-overflow-reflow": ["10.11"], "dyn-input-overflow-zoom": ["10.4"], "dyn-input-overflow-spacing": ["10.12"],
|
|
@@ -248,10 +260,11 @@ const RULE_TO_CRITERIA = {
|
|
|
248
260
|
"control-label-missing": ["11.1"], "label-for-dangling": ["11.1"], "placeholder-as-label": ["11.1"],
|
|
249
261
|
"form-field-multiple-labels": ["11.1"], "select-has-option": ["11.1"], "control-name-title-only": ["11.1"],
|
|
250
262
|
"radio-checkbox-group-ungrouped": ["11.5"], "date-fields-ungrouped": ["11.5"],
|
|
251
|
-
"field-purpose-incomplete": ["11.1", "11.13"], "fieldset-legend-missing": ["11.6"], "button-empty-name": ["11.9"],
|
|
263
|
+
"field-purpose-incomplete": ["11.1", "11.13"], "fieldset-legend-missing": ["11.6"], "form-button-empty-name": ["11.9"],
|
|
264
|
+
"autocomplete-token-invalid": ["11.13"], "form-label-in-name-mismatch": ["11.9"],
|
|
252
265
|
"error-not-associated": ["11.10"], "aria-invalid-no-description": ["11.10"],
|
|
253
266
|
"axe:label": ["11.1"], "axe:form-field-multiple-labels": ["11.1"], "axe:select-name": ["11.1"], "axe:label-title-only": ["11.1"],
|
|
254
|
-
"axe:autocomplete-valid": ["11.13"], "axe:fieldset": ["11.6"],
|
|
267
|
+
"axe:autocomplete-valid": ["11.13"], "axe:fieldset": ["11.6"],
|
|
255
268
|
// Theme 12 — navigation (12.7 skip link, 12.8 tab order, 12.9 keyboard trap)
|
|
256
269
|
"skip-link-target-missing": ["12.7"], "axe:skip-link": ["12.7"], "axe:bypass": ["12.7"],
|
|
257
270
|
"positive-tabindex": ["12.8"], "axe:tabindex": ["12.8"],
|
|
@@ -284,8 +297,11 @@ const DECISIVE_RULE_TESTS = {
|
|
|
284
297
|
"8.2|axe:duplicate-id": ["1"],
|
|
285
298
|
"8.2|axe:duplicate-id-aria": ["1"],
|
|
286
299
|
"8.2|axe:duplicate-id-active": ["1"],
|
|
300
|
+
"8.2|duplicate-attribute": ["1"],
|
|
301
|
+
"8.3|document-language-missing": ["1"],
|
|
287
302
|
"8.4|axe:html-lang-valid": ["1"],
|
|
288
303
|
"8.4|lang-invalid": ["1"],
|
|
304
|
+
"8.4|html-lang-xml-lang-mismatch": ["1"],
|
|
289
305
|
"8.5|title-missing-empty": ["1"],
|
|
290
306
|
"8.5|axe:document-title": ["1"],
|
|
291
307
|
"9.3|list-structure": ["1", "2", "3"],
|
|
@@ -294,14 +310,28 @@ const DECISIVE_RULE_TESTS = {
|
|
|
294
310
|
"9.3|axe:definition-list": ["3"],
|
|
295
311
|
"9.3|axe:dlitem": ["3"],
|
|
296
312
|
"10.7|dyn-focus-visible": ["1"],
|
|
313
|
+
"10.12|letter-spacing-important": ["1"],
|
|
314
|
+
"10.12|word-spacing-important": ["1"],
|
|
315
|
+
"10.12|line-height-important": ["1"],
|
|
297
316
|
"11.1|axe:label": ["1"],
|
|
298
317
|
"11.1|axe:select-name": ["1"],
|
|
299
318
|
"11.1|control-label-missing": ["1"],
|
|
300
319
|
"11.6|axe:fieldset": ["1"],
|
|
301
320
|
"11.6|fieldset-legend-missing": ["1"],
|
|
302
|
-
"11.9|
|
|
303
|
-
"11.9|
|
|
304
|
-
"11.
|
|
321
|
+
"11.9|form-button-empty-name": ["1"],
|
|
322
|
+
"11.9|form-label-in-name-mismatch": ["2"],
|
|
323
|
+
"11.5|radio-checkbox-group-ungrouped": ["1"],
|
|
324
|
+
"5.7|headers-attr-dangling": ["4"],
|
|
325
|
+
"5.7|table-scope-invalid": ["2", "3"],
|
|
326
|
+
"5.8|layout-table-data-markup": ["1"],
|
|
327
|
+
// An absent accessible name fails the prerequisite name/role/value test (7.1.1).
|
|
328
|
+
// Test 7.1.3 asks whether an already-accessible name/role is pertinent; it cannot be the
|
|
329
|
+
// attachment for a component that has no name at all.
|
|
330
|
+
"7.1|menuitem-empty-name": ["1"],
|
|
331
|
+
"7.1|button-empty-name": ["1"],
|
|
332
|
+
"7.1|axe:button-name": ["1"],
|
|
333
|
+
"7.1|axe:input-button-name": ["1"],
|
|
334
|
+
"7.1|label-in-name-mismatch": ["3"],
|
|
305
335
|
};
|
|
306
336
|
|
|
307
337
|
// Candidate evidence is test-scoped too. The fallback remains all tests only when one rule id
|
|
@@ -316,6 +346,7 @@ const CANDIDATE_RULE_TESTS = {
|
|
|
316
346
|
"1.1|object-embed-no-name": ["6", "7"],
|
|
317
347
|
"1.1|canvas-fallback-missing": ["8"],
|
|
318
348
|
"1.1|chart-no-accessible-name": ["1", "5", "8"],
|
|
349
|
+
"1.2|decorative-marked-exposed": ["1", "2", "3", "4", "5", "6"],
|
|
319
350
|
"4.3|axe:audio-caption": ["1"],
|
|
320
351
|
"4.3|axe:video-caption": ["1"],
|
|
321
352
|
"4.3|media-no-track": ["1"],
|
|
@@ -325,6 +356,7 @@ const CANDIDATE_RULE_TESTS = {
|
|
|
325
356
|
"5.7|axe:scope-attr-valid": ["2", "3"],
|
|
326
357
|
"5.7|axe:td-headers-attr": ["4"],
|
|
327
358
|
"7.3|clickable-noninteractive": ["1"],
|
|
359
|
+
"7.1|presentational-children-focusable": ["1", "2"],
|
|
328
360
|
"8.4|axe:html-xml-lang-mismatch": ["1"],
|
|
329
361
|
"9.1|axe:empty-heading": ["2"],
|
|
330
362
|
"9.1|empty-heading": ["2"],
|
|
@@ -348,6 +380,7 @@ const CANDIDATE_RULE_TESTS = {
|
|
|
348
380
|
"11.1|placeholder-as-label": ["1", "3"],
|
|
349
381
|
"11.1|field-purpose-incomplete": ["1", "3"],
|
|
350
382
|
"11.1|select-has-option": ["1"],
|
|
383
|
+
"11.13|autocomplete-token-invalid": ["1"],
|
|
351
384
|
"11.9|cross-icon-only-unnamed": ["1"],
|
|
352
385
|
"11.9|icon-only-control-unnamed": ["1"],
|
|
353
386
|
"11.10|aria-invalid-no-description": ["3", "4", "6", "7"],
|
|
@@ -362,7 +395,7 @@ const CANDIDATE_RULE_TESTS = {
|
|
|
362
395
|
"13.8|axe:marquee": ["1"],
|
|
363
396
|
};
|
|
364
397
|
|
|
365
|
-
const COMPLETE_BY_SILENCE = new Set(["8.5", "10.1"]);
|
|
398
|
+
const COMPLETE_BY_SILENCE = new Set(["8.3", "8.5", "10.1"]);
|
|
366
399
|
const renderedTier = (ruleId) =>
|
|
367
400
|
ruleId.startsWith("rendered-") || ruleId.startsWith("dyn-") || ruleId.startsWith("axe:") ? "rendered" : "static";
|
|
368
401
|
const mergeTestTier = (current, next) => (current === "static" || next === "static" ? "static" : next);
|
|
@@ -637,14 +637,14 @@ const NEEDS_RENDERING = new Set([
|
|
|
637
637
|
// icon-only-control-unnamed) appear under BOTH their SCs so registry's bidirectional
|
|
638
638
|
// rule↔dataset cross-check holds.
|
|
639
639
|
const RULE_SC_COVERAGE = {
|
|
640
|
-
"1.1.1": ["img-alt-missing", "canvas-fallback-missing", "decorative-alt-misuse", "input-image-alt-missing", "object-embed-no-name", "chart-no-accessible-name"],
|
|
640
|
+
"1.1.1": ["img-alt-missing", "canvas-fallback-missing", "decorative-alt-misuse", "decorative-marked-exposed", "input-image-alt-missing", "object-embed-no-name", "chart-no-accessible-name"],
|
|
641
641
|
"1.2.2": ["media-no-track"],
|
|
642
642
|
"1.3.1": [
|
|
643
643
|
"fieldset-legend-missing", "data-table-no-headers", "table-caption-missing",
|
|
644
644
|
"layout-table-data-markup", "heading-order-skip", "h1-missing", "h1-multiple", "list-structure", "dl-structure",
|
|
645
645
|
"empty-heading", "label-for-dangling", "missing-main-landmark", "multiple-main-landmark",
|
|
646
646
|
"sortable-header-no-aria-sort", "nav-landmark-missing", "nav-landmark-unnamed", "aria-required-parent",
|
|
647
|
-
"headers-attr-dangling", "th-no-data-cells",
|
|
647
|
+
"headers-attr-dangling", "th-no-data-cells", "table-scope-invalid",
|
|
648
648
|
"radio-checkbox-group-ungrouped", "table-empty-data-cell", "css-generated-content-informative",
|
|
649
649
|
"presentational-element", "presentational-attribute", "presentational-spacing",
|
|
650
650
|
],
|
|
@@ -654,6 +654,7 @@ const RULE_SC_COVERAGE = {
|
|
|
654
654
|
"1.4.1": ["rendered-link-colour-only"],
|
|
655
655
|
"1.4.3": ["contrast-literal", "rendered-contrast", "rendered-contrast-pixel"],
|
|
656
656
|
"1.4.11": ["rendered-nontext-contrast"],
|
|
657
|
+
"1.4.12": ["letter-spacing-important", "word-spacing-important", "line-height-important"],
|
|
657
658
|
"1.4.4": ["meta-viewport-zoom-block"],
|
|
658
659
|
"2.1.1": ["clickable-noninteractive"],
|
|
659
660
|
"2.2.1": ["meta-refresh-redirect"],
|
|
@@ -663,19 +664,20 @@ const RULE_SC_COVERAGE = {
|
|
|
663
664
|
"2.4.3": ["positive-tabindex"],
|
|
664
665
|
"2.4.7": ["rendered-focus-not-visible"],
|
|
665
666
|
"2.4.4": ["link-empty-name", "icon-only-control-unnamed"],
|
|
666
|
-
"2.5.3": ["label-in-name-mismatch"],
|
|
667
|
+
"2.5.3": ["label-in-name-mismatch", "form-label-in-name-mismatch"],
|
|
667
668
|
"3.2.2": ["on-input-context-change"],
|
|
668
669
|
"3.3.8": ["credential-entry-blocked"],
|
|
669
|
-
"3.1.1": ["html-lang-missing", "lang-invalid"],
|
|
670
|
+
"3.1.1": ["html-lang-missing", "document-language-missing", "html-lang-xml-lang-mismatch", "lang-invalid"],
|
|
670
671
|
"3.1.2": ["inline-lang-change-missing", "lang-invalid"],
|
|
671
672
|
"3.3.1": ["aria-invalid-no-description", "error-not-associated"],
|
|
672
673
|
"3.3.2": ["radio-checkbox-group-ungrouped", "date-fields-ungrouped"],
|
|
673
674
|
"4.1.2": [
|
|
674
675
|
"iframe-title-missing", "invalid-aria-role", "aria-ref-missing-id", "redundant-aria",
|
|
675
676
|
"clickable-noninteractive", "aria-required-children", "aria-hidden-focusable", "nested-interactive", "invalid-aria-attr", "invalid-aria-value", "aria-required-attr", "aria-prohibited-attr",
|
|
676
|
-
"duplicate-id", "control-label-missing", "placeholder-as-label", "form-field-multiple-labels",
|
|
677
|
-
"select-has-option", "button-empty-name", "icon-only-control-unnamed", "control-name-title-only",
|
|
678
|
-
"field-purpose-incomplete", "disabled-context-content",
|
|
677
|
+
"duplicate-id", "duplicate-attribute", "control-label-missing", "placeholder-as-label", "form-field-multiple-labels",
|
|
678
|
+
"select-has-option", "button-empty-name", "form-button-empty-name", "icon-only-control-unnamed", "control-name-title-only",
|
|
679
|
+
"field-purpose-incomplete", "disabled-context-content", "presentational-children-focusable",
|
|
680
|
+
"decorative-marked-exposed", "menuitem-empty-name",
|
|
679
681
|
],
|
|
680
682
|
"4.1.3": ["live-region-conflict", "status-message-not-assertive"],
|
|
681
683
|
};
|