ultra11y 5.24.0 → 5.26.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.
Files changed (42) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.opencode/plugins/ultra11y.js +1 -1
  5. package/dist/playwright.mjs +1 -1
  6. package/package.json +1 -1
  7. package/scripts/build-pack-rgaa.mjs +41 -1
  8. package/scripts/ultra11y.mjs +704 -48
  9. package/scripts/vendor/rgaa/SOURCE.json +4 -3
  10. package/scripts/vendor/rgaa/methodologies.json +260 -0
  11. package/scripts/verify-rgaa-source.mjs +23 -6
  12. package/skills/review-a11y/SKILL.md +1 -1
  13. package/skills/review-a11y/scripts/ultra11y.mjs +704 -48
  14. package/skills/ultra11y/SKILL.md +10 -1
  15. package/skills/ultra11y/references/judgment.md +27 -1
  16. package/skills/ultra11y/references/orchestration.md +5 -0
  17. package/skills/ultra11y/scripts/ultra11y.mjs +704 -48
  18. package/src/adjudicate-subjects.ts +73 -1
  19. package/src/adjudicate.ts +206 -23
  20. package/src/adjudication-data.ts +31 -0
  21. package/src/audit.ts +1 -1
  22. package/src/cli.ts +51 -2
  23. package/src/criteria-view.ts +18 -8
  24. package/src/criteria.ts +17 -1
  25. package/src/data/standards/rgaa.json +471 -0
  26. package/src/dev.ts +1 -1
  27. package/src/glob.ts +2 -2
  28. package/src/graph/imports.ts +1 -1
  29. package/src/integrations/cypress-plugin.ts +1 -1
  30. package/src/integrations/cypress.ts +2 -2
  31. package/src/integrations/playwright.ts +5 -5
  32. package/src/mcp/handlers.ts +1 -1
  33. package/src/orchestrate-templates.ts +9 -5
  34. package/src/orchestrate.ts +1 -1
  35. package/src/rules/images.ts +1 -1
  36. package/src/rules/tables.ts +2 -2
  37. package/src/scan.ts +1 -1
  38. package/src/standards/pack-rules.ts +1 -1
  39. package/src/standards/pack.ts +6 -0
  40. package/src/standards/types.ts +17 -0
  41. package/src/standards/validate.ts +30 -0
  42. 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.24.0",
13
+ "version": "5.26.0",
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.24.0",
4
+ "version": "5.26.0",
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.24.0",
4
+ "version": "5.26.0",
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.24.0";
30
+ const ULTRA11Y_PLUGIN_VERSION = "5.26.0";
31
31
 
32
32
  const here = dirname(fileURLToPath(import.meta.url));
33
33
 
@@ -720,7 +720,7 @@ var test = (() => {
720
720
  const base = load(from).test;
721
721
  if (!base?.extend) continue;
722
722
  return base.extend({
723
- // biome-ignore lint/suspicious/noExplicitAny: same
723
+ // `any` for the same reason.
724
724
  ultra11y: async ({ page }, use) => {
725
725
  await use((opts) => checkA11y(page, opts));
726
726
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultra11y",
3
- "version": "5.24.0",
3
+ "version": "5.26.0",
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",
@@ -6,7 +6,8 @@
6
6
  // of its criteria onto WCAG success criteria (bare SC ids). The WCAG↔rule coverage
7
7
  // lives in the core (scripts/build-standards.mjs). The RGAA content is Licence
8
8
  // Ouverte / Etalab 2.0 — see NOTICE. The official source is vendored under
9
- // scripts/vendor/rgaa/ so the build is reproducible offline.
9
+ // scripts/vendor/rgaa/ (criteres.json, glossaire.json, methodologies.json) so the
10
+ // build is reproducible offline.
10
11
  // node scripts/build-pack-rgaa.mjs # build from the vendored source
11
12
  // node scripts/build-pack-rgaa.mjs --offline # alias (the source is always local)
12
13
  // node scripts/build-pack-rgaa.mjs --fetch # refresh the vendored source from DINUM, then build
@@ -76,6 +77,22 @@ const flattenNode = (v) => {
76
77
  };
77
78
  const toArr = (v) => flattenNode(v);
78
79
 
80
+ // The official méthodologie de test for one criterion, keyed by the criterion's OWN test
81
+ // numbers so it renders directly under the test it explains: `{ "1": "1. Retrouver…", … }`.
82
+ // DINUM's file is flat and keyed by full test id ("11.2.1"), so this is the re-key.
83
+ //
84
+ // Returns undefined when the criterion has none, and the field is then absent from the pack
85
+ // rather than present-and-empty: `methodology` is optional on PackCriterion, and an empty
86
+ // object would make every consumer test for two shapes instead of one.
87
+ function methodologyOf(methodologies, id, tests) {
88
+ const out = {};
89
+ for (const k of Object.keys(tests || {})) {
90
+ const text = methodologies[`${id}.${k}`];
91
+ if (typeof text === "string" && text.trim()) out[k] = text.trim();
92
+ }
93
+ return Object.keys(out).length ? { methodology: out } : undefined;
94
+ }
95
+
79
96
  // crude HTML -> plaintext for glossary bodies
80
97
  const deHtml = (s) =>
81
98
  s
@@ -245,6 +262,12 @@ const RULE_TO_CRITERIA = {
245
262
  async function main() {
246
263
  const criteres = await source("criteres.json");
247
264
  const glossaire = await source("glossaire.json");
265
+ // THE OFFICIAL TEST METHODOLOGY — the third file DINUM publishes beside the other two,
266
+ // keyed by TEST id ("11.2.1"), and the one thing an adjudicator was never given. The
267
+ // criterion's wording says WHAT is required; this says HOW it is tested, step by step, in
268
+ // the referential's own words. Vendored like the rest so it reaches CI, an offline run and
269
+ // a model prompt without a network call — see `methodology` in src/standards/types.ts.
270
+ const methodologies = await source("methodologies.json");
248
271
 
249
272
  const glossary = {};
250
273
  for (const e of glossaire.glossary) glossary[slug(e.title)] = { title: e.title, body: deHtml(e.body) };
@@ -267,6 +290,7 @@ async function main() {
267
290
  title: { fr: criterium.title },
268
291
  titlePlain: { fr: plain(criterium.title) },
269
292
  tests: criterium.tests || {},
293
+ ...(methodologyOf(methodologies, id, criterium.tests) ?? {}),
270
294
  techniques: [...techniques],
271
295
  ...(criterium.technicalNote ? { technicalNote: toArr(criterium.technicalNote) } : {}),
272
296
  ...(criterium.particularCases ? { particularCases: toArr(criterium.particularCases) } : {}),
@@ -462,6 +486,9 @@ const DOWNLOAD_EXT = "pdf|docx?|pptx?|xlsx?|odt|ods|odp|rtf|csv|zip|rar|7z|gz|ep
462
486
  source: "https://github.com/DISIC/accessibilite.numerique.gouv.fr",
463
487
  attribution: "RGAA 4.1.2 © DINUM (Direction interministérielle du numérique) — Licence Ouverte / Etalab 2.0",
464
488
  idPattern: "^\\d+\\.\\d+$",
489
+ // Where DINUM publishes each criterion. Cited by the adjudication brief so a reader can
490
+ // reach the normative page — the vendored text above stays the authority either way.
491
+ criterionUrl: "https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/#{id}",
465
492
  // Auditor-display vocabulary (FR): the nouns an RGAA auditor reads. Rendered by the
466
493
  // `prd` auditor block + GitHub issues; see src/standards/vocabulary.ts.
467
494
  vocabulary: {
@@ -572,9 +599,22 @@ const DOWNLOAD_EXT = "pdf|docx?|pptx?|xlsx?|odt|ods|odp|rtf|csv|zip|rar|7z|gz|ep
572
599
  throw new Error(`build-pack-rgaa: ${stringified.length} normative text(s) stringified to "[object Object]" — extend flattenNode: ${stringified.join(", ")}`);
573
600
  }
574
601
 
602
+ // THE METHODOLOGY TABLE MUST NOT GO STALE EITHER. A methodology whose test id does not
603
+ // exist in the referential is a curation mistake upstream OR a re-key bug here, and it
604
+ // would ship as dead weight in every bundle. A test with no methodology is legitimate
605
+ // (DINUM does not document every one), so that is counted, not refused.
606
+ const testIds = new Set();
607
+ for (const c of criteria) for (const k of Object.keys(c.tests ?? {})) testIds.add(`${c.id}.${k}`);
608
+ const orphans = Object.keys(methodologies).filter((k) => !testIds.has(k));
609
+ if (orphans.length) {
610
+ throw new Error(`build-pack-rgaa: ${orphans.length} methodology(ies) name a test the referential does not have: ${orphans.join(", ")}`);
611
+ }
612
+ const documented = criteria.reduce((n, c) => n + Object.keys(c.methodology ?? {}).length, 0);
613
+
575
614
  const noWcag = criteria.filter((c) => c.wcag.length === 0).map((c) => c.id);
576
615
  console.log(`build-pack-rgaa: ${themes.length} themes, ${criteria.length} criteria → src/data/standards/rgaa.json`);
577
616
  console.log(`build-pack-rgaa: glossary ${Object.keys(glossary).length} entries → src/data/standards/rgaa.glossary.json`);
617
+ console.log(`build-pack-rgaa: official test methodology on ${documented}/${testIds.size} tests`);
578
618
  console.log(`build-pack-rgaa: criteria with no WCAG mapping (pack-local): ${noWcag.length ? noWcag.join(", ") : "none"} (${noWcag.length})`);
579
619
  }
580
620