ultra11y 5.5.1 → 5.5.2
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/package.json +1 -1
- package/scripts/ultra11y.mjs +11 -4
- package/skills/review-a11y/SKILL.md +1 -1
- package/skills/review-a11y/scripts/ultra11y.mjs +11 -4
- package/skills/ultra11y/SKILL.md +1 -1
- package/skills/ultra11y/scripts/ultra11y.mjs +11 -4
- package/src/adjudicate-subjects.ts +25 -2
- package/src/adjudicate.ts +11 -8
- 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.5.
|
|
13
|
+
"version": "5.5.2",
|
|
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.5.
|
|
4
|
+
"version": "5.5.2",
|
|
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.5.
|
|
4
|
+
"version": "5.5.2",
|
|
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.5.
|
|
30
|
+
const ULTRA11Y_PLUGIN_VERSION = "5.5.2";
|
|
31
31
|
|
|
32
32
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
33
33
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultra11y",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.2",
|
|
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",
|
package/scripts/ultra11y.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
|
|
|
6
6
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
|
|
7
7
|
|
|
8
8
|
// src/types.ts
|
|
9
|
-
var VERSION = "5.5.
|
|
9
|
+
var VERSION = "5.5.2";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
|
|
12
12
|
// src/audit.ts
|
|
@@ -55758,6 +55758,13 @@ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
|
55758
55758
|
import { join as join35, resolve as resolve10 } from "path";
|
|
55759
55759
|
|
|
55760
55760
|
// src/adjudicate-subjects.ts
|
|
55761
|
+
var VOLATILE = [
|
|
55762
|
+
[/\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b/g, "<date>"],
|
|
55763
|
+
[/\b\d{4}-\d{2}-\d{2}\b/g, "<date>"],
|
|
55764
|
+
[/\b\d{1,2}:\d{2}(?::\d{2})?\b/g, "<time>"],
|
|
55765
|
+
[/\b\d{6,}\b/g, "<num>"]
|
|
55766
|
+
];
|
|
55767
|
+
var stable = (s) => VOLATILE.reduce((acc, [re, to]) => acc.replace(re, to), s);
|
|
55761
55768
|
var selectorFor = (el) => {
|
|
55762
55769
|
const id = el.attribs.id ? `#${el.attribs.id}` : "";
|
|
55763
55770
|
const cls = el.attribs.class ? `.${el.attribs.class.trim().split(/\s+/)[0]}` : "";
|
|
@@ -55766,14 +55773,14 @@ var selectorFor = (el) => {
|
|
|
55766
55773
|
function h(doc, el, note, cls) {
|
|
55767
55774
|
return {
|
|
55768
55775
|
ev: { file: doc.file, line: el.line, selector: selectorFor(el), snippet: snippet(doc, el, 160), note },
|
|
55769
|
-
cls: cls ?? `${el.tag}|${note}
|
|
55776
|
+
cls: stable(cls ?? `${el.tag}|${note}`),
|
|
55770
55777
|
at: el.start
|
|
55771
55778
|
};
|
|
55772
55779
|
}
|
|
55773
55780
|
function hAt(doc, line, selector, note, cls) {
|
|
55774
55781
|
return {
|
|
55775
55782
|
ev: { file: doc.file, line, selector, snippet: (doc.source.split("\n")[line - 1] ?? "").trim().slice(0, 160), note },
|
|
55776
|
-
cls,
|
|
55783
|
+
cls: stable(cls),
|
|
55777
55784
|
at: line
|
|
55778
55785
|
};
|
|
55779
55786
|
}
|
|
@@ -57174,7 +57181,7 @@ function adjudicationText(sc, lang) {
|
|
|
57174
57181
|
}
|
|
57175
57182
|
|
|
57176
57183
|
// src/adjudicate.ts
|
|
57177
|
-
var ADJUDICATE_MAX_EVIDENCE_CLASSES =
|
|
57184
|
+
var ADJUDICATE_MAX_EVIDENCE_CLASSES = 1200;
|
|
57178
57185
|
var ALSO_AT_MAX = 8;
|
|
57179
57186
|
function adjudicationContract() {
|
|
57180
57187
|
return {
|
|
@@ -5,7 +5,7 @@ when_to_use: "Invoke WITHOUT being asked whenever changed front-end code should
|
|
|
5
5
|
allowed-tools: Bash(node ${CLAUDE_SKILL_DIR}/scripts/ultra11y.mjs *), Read, Grep, Glob
|
|
6
6
|
license: MIT
|
|
7
7
|
metadata:
|
|
8
|
-
version: 5.5.
|
|
8
|
+
version: 5.5.2
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# review-a11y — accessibility review of changed code
|
|
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
|
|
|
6
6
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
|
|
7
7
|
|
|
8
8
|
// src/types.ts
|
|
9
|
-
var VERSION = "5.5.
|
|
9
|
+
var VERSION = "5.5.2";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
|
|
12
12
|
// src/audit.ts
|
|
@@ -55758,6 +55758,13 @@ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
|
55758
55758
|
import { join as join35, resolve as resolve10 } from "path";
|
|
55759
55759
|
|
|
55760
55760
|
// src/adjudicate-subjects.ts
|
|
55761
|
+
var VOLATILE = [
|
|
55762
|
+
[/\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b/g, "<date>"],
|
|
55763
|
+
[/\b\d{4}-\d{2}-\d{2}\b/g, "<date>"],
|
|
55764
|
+
[/\b\d{1,2}:\d{2}(?::\d{2})?\b/g, "<time>"],
|
|
55765
|
+
[/\b\d{6,}\b/g, "<num>"]
|
|
55766
|
+
];
|
|
55767
|
+
var stable = (s) => VOLATILE.reduce((acc, [re, to]) => acc.replace(re, to), s);
|
|
55761
55768
|
var selectorFor = (el) => {
|
|
55762
55769
|
const id = el.attribs.id ? `#${el.attribs.id}` : "";
|
|
55763
55770
|
const cls = el.attribs.class ? `.${el.attribs.class.trim().split(/\s+/)[0]}` : "";
|
|
@@ -55766,14 +55773,14 @@ var selectorFor = (el) => {
|
|
|
55766
55773
|
function h(doc, el, note, cls) {
|
|
55767
55774
|
return {
|
|
55768
55775
|
ev: { file: doc.file, line: el.line, selector: selectorFor(el), snippet: snippet(doc, el, 160), note },
|
|
55769
|
-
cls: cls ?? `${el.tag}|${note}
|
|
55776
|
+
cls: stable(cls ?? `${el.tag}|${note}`),
|
|
55770
55777
|
at: el.start
|
|
55771
55778
|
};
|
|
55772
55779
|
}
|
|
55773
55780
|
function hAt(doc, line, selector, note, cls) {
|
|
55774
55781
|
return {
|
|
55775
55782
|
ev: { file: doc.file, line, selector, snippet: (doc.source.split("\n")[line - 1] ?? "").trim().slice(0, 160), note },
|
|
55776
|
-
cls,
|
|
55783
|
+
cls: stable(cls),
|
|
55777
55784
|
at: line
|
|
55778
55785
|
};
|
|
55779
55786
|
}
|
|
@@ -57174,7 +57181,7 @@ function adjudicationText(sc, lang) {
|
|
|
57174
57181
|
}
|
|
57175
57182
|
|
|
57176
57183
|
// src/adjudicate.ts
|
|
57177
|
-
var ADJUDICATE_MAX_EVIDENCE_CLASSES =
|
|
57184
|
+
var ADJUDICATE_MAX_EVIDENCE_CLASSES = 1200;
|
|
57178
57185
|
var ALSO_AT_MAX = 8;
|
|
57179
57186
|
function adjudicationContract() {
|
|
57180
57187
|
return {
|
package/skills/ultra11y/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: "Use to AUDIT existing HTML/CSS/JSX against WCAG 2.2 AA accessibili
|
|
|
4
4
|
when_to_use: "Invoke when the user asks for an accessibility AUDIT or a formal deliverable: audit a repo, site or page against WCAG 2.2 AA or a country standard (RGAA, Section 508, EN 301 549); produce a dated conformance report, a criterion grid, a PRD backlog, or tickets (GitHub/GitLab/Jira); author accessible markup from scratch; wire the repo gate (init --hook/--ci) or a rendered-DOM capture pipeline. For a review of the code UNDER CHANGE (diff, branch, PR), use the `review-a11y` skill instead."
|
|
5
5
|
license: MIT
|
|
6
6
|
metadata:
|
|
7
|
-
version: 5.5.
|
|
7
|
+
version: 5.5.2
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# ultra11y — audit WCAG 2.2 AA and write accessible markup
|
|
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
|
|
|
6
6
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
|
|
7
7
|
|
|
8
8
|
// src/types.ts
|
|
9
|
-
var VERSION = "5.5.
|
|
9
|
+
var VERSION = "5.5.2";
|
|
10
10
|
var SCHEMA_VERSION = 2;
|
|
11
11
|
|
|
12
12
|
// src/audit.ts
|
|
@@ -55758,6 +55758,13 @@ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
|
55758
55758
|
import { join as join35, resolve as resolve10 } from "path";
|
|
55759
55759
|
|
|
55760
55760
|
// src/adjudicate-subjects.ts
|
|
55761
|
+
var VOLATILE = [
|
|
55762
|
+
[/\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b/g, "<date>"],
|
|
55763
|
+
[/\b\d{4}-\d{2}-\d{2}\b/g, "<date>"],
|
|
55764
|
+
[/\b\d{1,2}:\d{2}(?::\d{2})?\b/g, "<time>"],
|
|
55765
|
+
[/\b\d{6,}\b/g, "<num>"]
|
|
55766
|
+
];
|
|
55767
|
+
var stable = (s) => VOLATILE.reduce((acc, [re, to]) => acc.replace(re, to), s);
|
|
55761
55768
|
var selectorFor = (el) => {
|
|
55762
55769
|
const id = el.attribs.id ? `#${el.attribs.id}` : "";
|
|
55763
55770
|
const cls = el.attribs.class ? `.${el.attribs.class.trim().split(/\s+/)[0]}` : "";
|
|
@@ -55766,14 +55773,14 @@ var selectorFor = (el) => {
|
|
|
55766
55773
|
function h(doc, el, note, cls) {
|
|
55767
55774
|
return {
|
|
55768
55775
|
ev: { file: doc.file, line: el.line, selector: selectorFor(el), snippet: snippet(doc, el, 160), note },
|
|
55769
|
-
cls: cls ?? `${el.tag}|${note}
|
|
55776
|
+
cls: stable(cls ?? `${el.tag}|${note}`),
|
|
55770
55777
|
at: el.start
|
|
55771
55778
|
};
|
|
55772
55779
|
}
|
|
55773
55780
|
function hAt(doc, line, selector, note, cls) {
|
|
55774
55781
|
return {
|
|
55775
55782
|
ev: { file: doc.file, line, selector, snippet: (doc.source.split("\n")[line - 1] ?? "").trim().slice(0, 160), note },
|
|
55776
|
-
cls,
|
|
55783
|
+
cls: stable(cls),
|
|
55777
55784
|
at: line
|
|
55778
55785
|
};
|
|
55779
55786
|
}
|
|
@@ -57174,7 +57181,7 @@ function adjudicationText(sc, lang) {
|
|
|
57174
57181
|
}
|
|
57175
57182
|
|
|
57176
57183
|
// src/adjudicate.ts
|
|
57177
|
-
var ADJUDICATE_MAX_EVIDENCE_CLASSES =
|
|
57184
|
+
var ADJUDICATE_MAX_EVIDENCE_CLASSES = 1200;
|
|
57178
57185
|
var ALSO_AT_MAX = 8;
|
|
57179
57186
|
function adjudicationContract() {
|
|
57180
57187
|
return {
|
|
@@ -27,6 +27,29 @@ import { type Doc, type El, ancestors, attr, elementsByTag, snippet as elSnippet
|
|
|
27
27
|
import { parseInlineStyle } from "./color.js";
|
|
28
28
|
import type { Evidence } from "./adjudicate.js";
|
|
29
29
|
|
|
30
|
+
/** Mask the parts of a text that change between runs without the code changing.
|
|
31
|
+
*
|
|
32
|
+
* Only the class IDENTITY is masked — the note and the snippet keep the real text, so the
|
|
33
|
+
* adjudicator still reads what the page says. What this decides is whether two anchors are
|
|
34
|
+
* "the same thing": a row rendered at 13:04 and the same row rendered at 14:12 are one
|
|
35
|
+
* decision about accessibility, not two.
|
|
36
|
+
*
|
|
37
|
+
* It matters beyond tidiness. The verdict ledger fingerprints the evidence a criterion was
|
|
38
|
+
* ruled against, and a fingerprint that moves every run makes a stored verdict stale on
|
|
39
|
+
* arrival — the criterion returns to « to assess » and the ledger stops paying for itself.
|
|
40
|
+
* Measured on a real capture set: four criteria carried a run timestamp in their evidence.
|
|
41
|
+
*
|
|
42
|
+
* Deliberately narrow. Generated ids that are stable for a given tree (React `useId`) and
|
|
43
|
+
* content hashes that are stable for given source are NOT masked: when those move, the code
|
|
44
|
+
* moved, and a verdict about it SHOULD be re-examined. */
|
|
45
|
+
const VOLATILE: [RegExp, string][] = [
|
|
46
|
+
[/\b\d{1,2}[/-]\d{1,2}[/-]\d{2,4}\b/g, "<date>"],
|
|
47
|
+
[/\b\d{4}-\d{2}-\d{2}\b/g, "<date>"],
|
|
48
|
+
[/\b\d{1,2}:\d{2}(?::\d{2})?\b/g, "<time>"],
|
|
49
|
+
[/\b\d{6,}\b/g, "<num>"],
|
|
50
|
+
];
|
|
51
|
+
const stable = (s: string): string => VOLATILE.reduce((acc, [re, to]) => acc.replace(re, to), s);
|
|
52
|
+
|
|
30
53
|
/** One harvested anchor, plus the content class it belongs to. Two anchors sharing a class
|
|
31
54
|
* are the same thing rendered twice — a header link on 38 pages, not 38 link problems. */
|
|
32
55
|
export interface Harvested {
|
|
@@ -52,7 +75,7 @@ const selectorFor = (el: El): string => {
|
|
|
52
75
|
function h(doc: Doc, el: El, note: string, cls?: string): Harvested {
|
|
53
76
|
return {
|
|
54
77
|
ev: { file: doc.file, line: el.line, selector: selectorFor(el), snippet: elSnippet(doc, el, 160), note },
|
|
55
|
-
cls: cls ?? `${el.tag}|${note}
|
|
78
|
+
cls: stable(cls ?? `${el.tag}|${note}`),
|
|
56
79
|
at: el.start,
|
|
57
80
|
};
|
|
58
81
|
}
|
|
@@ -62,7 +85,7 @@ function h(doc: Doc, el: El, note: string, cls?: string): Harvested {
|
|
|
62
85
|
function hAt(doc: Doc, line: number, selector: string, note: string, cls: string): Harvested {
|
|
63
86
|
return {
|
|
64
87
|
ev: { file: doc.file, line, selector, snippet: (doc.source.split("\n")[line - 1] ?? "").trim().slice(0, 160), note },
|
|
65
|
-
cls,
|
|
88
|
+
cls: stable(cls),
|
|
66
89
|
at: line,
|
|
67
90
|
};
|
|
68
91
|
}
|
package/src/adjudicate.ts
CHANGED
|
@@ -47,15 +47,18 @@ import { guidanceExampleBlock } from "./prd.js";
|
|
|
47
47
|
* 887 links over 38 captured pages are 97 distinct (text, href) pairs. When even the class
|
|
48
48
|
* count exceeds this, `evidenceComplete` goes false and the fold refuses a `C` outright —
|
|
49
49
|
* an incomplete reading may still find a real failure, it may never clear one. */
|
|
50
|
-
export const ADJUDICATE_MAX_EVIDENCE_CLASSES =
|
|
50
|
+
export const ADJUDICATE_MAX_EVIDENCE_CLASSES = 1200;
|
|
51
51
|
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
52
|
+
// The number is set by what a real application actually contains, measured, and then given
|
|
53
|
+
// room to grow. On a 338-file product with 38 captured pages the largest per-criterion
|
|
54
|
+
// populations run to 592 classes (what survives when CSS is off), 531 (reading order) and 487
|
|
55
|
+
// (structure) — and those ARE the populations, not samples of them.
|
|
56
|
+
//
|
|
57
|
+
// The headroom is the point. A cap sitting just above today's largest criterion is a gate
|
|
58
|
+
// that flips the day someone adds a heading: the criterion becomes unclearable for reasons of
|
|
59
|
+
// VOLUME rather than of uncertainty, which is the wrong reason to refuse a verdict and an
|
|
60
|
+
// especially confusing one, since nothing about the code got worse. Refusing to conclude is
|
|
61
|
+
// honest only when something really was not looked at.
|
|
59
62
|
|
|
60
63
|
/** Sibling anchors listed per class. Bounded for readability; `occurrences` carries the true
|
|
61
64
|
* count, and the citation gate accepts any anchor of the class, listed or not. */
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Single source of truth for shared types + the embedded version. sync-version.mjs
|
|
2
2
|
// rewrites VERSION at release time (kept in lockstep with package.json + SKILL.md).
|
|
3
|
-
export const VERSION = "5.5.
|
|
3
|
+
export const VERSION = "5.5.2";
|
|
4
4
|
export const SCHEMA_VERSION = 2;
|
|
5
5
|
|
|
6
6
|
// Lang = the UI FRAME's language — the `L` localization tables each module (report,
|