Packs

Ein Pack bringt Regeln, Varianten der Regeln von core, eine Norm oder eine Checkliste sowie deren Profile und Meldungen aus einem eigenen Paket zu @surea11y/core, ohne einen Fork oder einen Build von core. Eine nationale Norm wie RGAA kann ein Pack sein, ebenso die Barrierefreiheitsrichtlinie Ihrer Organisation. Ein Scan nimmt Packs in engineOptions.packs entgegen und führt sie so aus wie die eigenen Regeln und Normen von core: in Node und im Browser, aus der CLI, den Bindings und den Test-Matchern, mit Ergebnissen, Zusammenfassungen und Berichtseinträgen im selben Format wie die von core. Packs erfordern @surea11y/core 1.11.1 oder neuer.

Welche Art von Pack

Sie habenArtWas es enthält
Die Barrierefreiheitsrichtlinie einer Organisation: „WCAG 2.2 AA, dazu diese Regeln, ohne jene, mit diesen Punkten in unserem Bericht“ChecklisteProfile, die Regeln von core und eigene auswählen, und Zusammenfassungen als Punkte der Checkliste.
Eine Norm mit eigenen Anforderungen (eine nationale Norm wie RGAA, die einer Branche): nummerierte Anforderungen, die jeweils von einigen Regeln geprüft werdenNormEine Anforderungstabelle, die Regeln, die jede Anforderung prüfen, ein Ergebnis pro Anforderung und Profile.
Ein paar Regeln, die jedem Scan hinzugefügt werden sollen, ohne Profilnur RegelnRegeln sowie Varianten oder Überschreibungen der Regeln von core. Beginnen Sie mit einer Checkliste und löschen Sie deren Profile und Zusammenfassungen.

Die Regeln und Profile eines Packs können jede Regel von core verwenden: Eine Checkliste oder eine Norm besteht größtenteils aus Regeln von core, ausgewählt und gruppiert, plus den wenigen Regeln, die core nicht hat. Die Beispiele auf dieser Seite verwenden acme-policy-pack.js, das kleine Pack, das jedes Binding in seinem Ordner examples/ mitliefert: eine hauseigene Regel, ein Checklistenprofil (WCAG 2.2 A und AA, region und die hauseigene Regel) und zwei Checklistenpunkte. Sein Quelltext steht weiter unten.

Das EN-301-549-Pack

@surea11y/pack-en301549 ist ein Normen-Pack der SureA11y-Familie, fertig zur Installation: Kapitel 9 (Web) der EN 301 549, in V3.2.1 und V4.1.1. Es hat ein Profil pro Version, en301549-v4.1.1 und en301549-v3.2.1, das ein Ergebnis pro Klausel meldet, und mappings: ['en301549'], um die Klauseln in den Ergebnissen jedes Scans zu nennen, auch eines WCAG-Scans. Es braucht @surea11y/core 1.13.0 oder neuer.

Seine Version 1.1.0, gebaut auf core 1.14.0, beurteilt jede Klausel so, wie core das WCAG-Kriterium beurteilt, das sie wiedergibt. Daher besteht noch keine Klausel: Wo alle ihre Regeln bestehen, ist eine Klausel cantTell, damit eine Person den Rest prüft, wie ihr Kriterium (siehe WCAG-Konformitätszuordnung). Das Profil en301549-v3.2.1 behält 4.1.1 „Syntaxanalyse“ bei, sodass eine doppelte id dort 9.4.1.1 weiterhin fehlschlagen lässt, und 9.1.4.5, 9.3.3.1 und 9.4.1.3 haben ihre ersten Regeln (image-of-text, invalid-field-error-message, live-region-announcements). Mit core 1.13 verhält es sich wie seine Versionen 1.0.

// npm install @surea11y/core @surea11y/pack-en301549
const en301549 = require('@surea11y/pack-en301549');
 
runDomRulesInPage(url, null, { packs: [en301549], profile: 'en301549-v4.1.1' });
runDomRulesInPage(url, null, { packs: [en301549], profile: 'wcag22-aa', mappings: ['en301549:V4.1.1'] });

Es ist auch ein vollständiges Beispiel für eine eigene Norm. Es hat keine Regeln: Kapitel 9 gibt die WCAG wieder, also prüfen die Regeln von core für das jeweilige Kriterium jede Klausel. Seine Profile wählen diese Regeln (tags, mappedRules: true), nennen die WCAG-Version, nach der jede Version der Norm beurteilt wird (wcagVersion), und behalten für V3.2.1 4.1.1 „Syntaxanalyse“ bei (keepsParsing). Seine Klauseln geben WCAG-Kriterien eins zu eins wieder (applicability: 'wcag'), und seine Regelzuordnung wird aus dem Katalog des installierten core abgeleitet: Eine Regel, die core hinzufügt, ist ohne Änderung am Pack abgedeckt. Eine Norm mit Anforderungen, die die WCAG nicht hat, folgt derselben Form und bringt eigene Regeln mit. Der Quelltext ist kurz und lohnt sich neben Ein Pack schreiben weiter unten.

Core hatte EN 301 549 bis 1.13.0 eingebaut; diese Version kündigt das zugunsten dieses Packs ab (siehe WCAG-Konformitätszuordnung). Wie jedes Profil wählen die des Packs, was läuft: Eine Konformitätserklärung braucht weiterhin eine Person, die jede Klausel prüft.

Ein Pack verwenden

Aus Node

const { runDomRulesInPage, getChecksCatalog } = require('@surea11y/core');
const acmePolicy = require('./acme-policy-pack');
 
const result = runDomRulesInPage(url, null, { packs: [acmePolicy], profile: 'acme-web-2026' }, null);
result.engine.packs; // ['@acme/a11y-policy@1.0.0']
getChecksCatalog({ packs: [acmePolicy] }); // core's rules and the pack's

Das Pack wird einmal vorbereitet und für den nächsten Scan mit demselben Pack-Objekt behalten, sodass ein Crawl, der jeder Seite dieselben Packs übergibt, sie nur einmal vorbereitet. definePack friert das Pack-Objekt ein: Behandeln Sie es als unveränderlich, und verwenden Sie zwischen Scans dasselbe Objekt wieder. Ein übergebenes Pack wird für den Scan registriert; seine Regeln wählt das nicht aus. Eine Regel des Packs, die das Namensraum-Tag des Packs trägt, ist eine Opt-in-Regel: Ohne eines der Profile des Packs läuft sie nur, wenn sie über ihre ID oder über dieses Tag ausgewählt wird (siehe Namen). Eine Regel des Packs ohne das Tag wird ausgewählt wie die Regeln von core, sodass ein Standard-Scan mit dem Pack sie ausführt. Ergänzen Sie runOnly: { bestPractices: true } neben dem Profil, um auch die Best Practices auszuführen.

Mit einem Browser-Binding

Playwright, Puppeteer, Selenium und WebdriverIO nehmen das Pack-Objekt in .withPacks() entgegen und registrieren es vor dem Scan in der Seite, mit .frames(true) auch in jedem Frame:

const { A11yCoreBuilder, getScanGaps } = require('@surea11y/playwright');
const acmePolicy = require('./acme-policy-pack');
 
const results = await new A11yCoreBuilder({ page })
.withPacks(acmePolicy)
.options({ profile: 'acme-web-2026' })
.analyze();
 
results.engine.packs; // ['@acme/a11y-policy@1.0.0']
 
// A checklist's items, each one result, beside core's WCAG rollups:
results.rulesResults.filter((r) => r.meta && r.meta.standard === 'Acme web policy');

Übergeben Sie ein Array oder rufen Sie .withPacks() erneut auf, um mit mehreren Packs zu scannen. Die Bindings teilen sich .withPacks(), aber jeder Builder nimmt sein eigenes Treiberobjekt ({ page }, { driver } oder { browser }) und braucht seine eigene Einrichtung. Siehe Playwright, Puppeteer, Selenium und WebdriverIO.

Mit Cypress

Ein Pack wird in Node vorbereitet, und eine Cypress-Spec läuft im Browser. Daher nimmt .withPacks() in Cypress den Modulnamen jedes Packs entgegen (einen Paketnamen oder einen Pfad ab dem Projektverzeichnis), und das Plugin des Bindings bereitet das Pack in Node vor. Registrieren Sie das Plugin einmal:

// cypress.config.js
const { defineConfig } = require('cypress');
const surea11y = require('@surea11y/cypress/plugin');
 
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
surea11y(on, config);
}
}
});
new A11yCoreBuilder()
.withPacks('./examples/acme-policy-pack.js') // or a package name, '@acme/a11y-policy'
.options({ profile: 'acme-web-2026' })
.analyze()
.then((results) => {
expect(results.engine.packs).to.deep.equal(['@acme/a11y-policy@1.0.0']);
});

.analyze() fragt das Plugin über cy.task nach dem Script, das die Packs registriert, und führt es in der Seite aus, mit .frames(true) auch in jedem Frame desselben Ursprungs. Das Plugin behält ein Pack für den Rest des Laufs, daher zeigt sich eine Änderung an der Datei eines Packs beim nächsten cypress run oder nach einem Neustart von cypress open. Ein Pack-Objekt, wie es die anderen Bindings annehmen, wirft bei .withPacks() einen Fehler: Es lässt sich nicht im Browser vorbereiten.

Mit den Test-Matchern

@surea11y/test-matchers scannt in Node, daher wird ein Pack als das Objekt selbst übergeben:

const acmePolicy = require('./acme-policy-pack');
const policy = { packs: [acmePolicy], profile: 'acme-web-2026' };
 
test("a page that breaks the pack's house rule fails the assertion", () => {
document.body.innerHTML = '<main><h1>Welcome</h1><video autoplay src="intro.mp4"></video></main>';
expect(document).not.toHaveNoA11yViolations(policy);
});

Halten Sie die Pack-Objekte an einer Stelle (einer Setup-Datei oder einem Modul), sodass jeder Test dieselben übergibt. Ein Pack, das nicht gelaufen ist, lässt die Assertion scheitern. Siehe test-matchers.

Aus der CLI

$ surea11y scan ./dist/index.html --pack ./acme-policy-pack.js --profile acme-web-2026
$ surea11y scan ./dist/index.html --pack @acme/a11y-policy --profile acme-web-2026

--pack nimmt einen Paketnamen, aufgelöst aus dem Projekt des Arbeitsverzeichnisses, oder einen Pfad entgegen und lässt sich für mehrere Packs wiederholen. Das Pack lädt @surea11y/core/pack, das neben der CLI installiert wird, wenn Sie @surea11y/cli im Projekt installieren. Siehe CLI.

In einer eigenen Seite

Für eine Browser-Erweiterung oder ein eigenes page.evaluate fügen Sie packScript([acmePolicy]) aus @surea11y/core/pack nach dem Browser-Bundle von core ein oder liefern eine einzige Datei aus, die mit buildBrowserBundle({ packs: [acmePolicy] }) gebaut wurde, und nennen das Pack als name@version. Siehe Standalone. Für eine Seite, die ihre Scripts als Dateien lädt, eignet sich die eine Datei aus buildBrowserBundle am besten: Das Script eines Packs läuft nur mit dem core, der es geschrieben hat.

Eine Seite mit dem Bundle eines anderen core überspringt das Pack, und skippedPacks nennt die beiden Versionen. Erzeugen Sie diese Datei daher für jede Version von core oder des Packs neu.

Was ein Scan meldet

  • engine.packs nennt jedes Pack, das gelaufen ist, als name@version, und engine.profile das Profil, das angewendet wurde.
  • Die Regeln eines Packs erscheinen in checksResults wie die von core, mit IDs, die mit seinem Namensraum beginnen (acme-no-autoplay). Eine Regel eines Packs, die einem WCAG-Kriterium zugeordnet ist, zählt für die Zusammenfassung dieses Kriteriums, es sei denn, sie trägt das Opt-in-Namensraum-Tag des Packs: Solche Regeln prüfen, was die WCAG nicht verlangen, und zählen daher nur in den eigenen Zusammenfassungen des Packs. Ihr wcagSc nennt trotzdem die WCAG-Kriterien, die sie prüfen, für die Berichte, und keine andere Norm (EN 301 549, die jede Regel über ihre WCAG-Kriterien zuordnet) beansprucht sie. Eine Überschreibung zählt anstelle der Regel von core, die sie ersetzt, dort, wohin ihre eigene Zuordnung sie stellt.
  • Die Punkte einer Checkliste oder die Anforderungen einer Norm sind Zusammenfassungen in rulesResults, mit dem Namen der Checkliste oder Norm als meta.standard. Der HTML-Bericht zeigt sie in einem eigenen Abschnitt, SARIF taggt jede Regel mit den Punkten, zu denen sie gehört (acme-images), und JUnit führt sie als Eigenschaften auf. standards des Ergebnisses nennt die Checkliste, sodass ein gespeichertes Ergebnis überall gleich dargestellt wird.
  • Ändert ein Profil über sein Feld severity den Schweregrad einer Regel, zeigen die betroffenen Ergebnisse den neuen Schweregrad, und der ursprüngliche Schweregrad der Regel bleibt als ruleSeverity erhalten.

Wenn ein Pack nicht läuft

Ein Pack, dessen core-Bereich das installierte core ausschließt, das nicht gültig ist oder das nicht zu core passt (eine Regel-ID außerhalb seines Namensraums, ein Wörterbuchschlüssel, den core hat, eine Variante einer Regel, die es nicht gibt), wird übersprungen: Der Scan läuft ohne es, warnt und listet es in skippedPacks als { name, reason }. Unter strictOptions wirft er einen Fehler mit code: 'INVALID_ENGINE_OPTIONS', wie jeder Fehler in engineOptions.packs. Zwei Packs, die miteinander kollidieren (ein Wörterbuchschlüssel, den beide definieren, zwei Normen mit einem Schlüssel), werfen einen Fehler, da jede Art, zwischen ihnen zu wählen, von der Reihenfolge abhinge, in der sie übergeben wurden. In einer Seite wird ein in engineOptions.packs genanntes Pack, das kein Aufruf von packScript registriert hat oder das mit einer anderen core-Version registriert wurde, genauso aufgeführt. Ein Scan kann also ohne die Prüfungen enden, für die Sie das Pack hinzugefügt haben: Ein Tool, das von einem Pack abhängt, sollte skippedPacks prüfen, bevor es den Scan als vollständig behandelt.

Jedes Tool macht aus einem übersprungenen Pack einen sichtbaren Fehlschlag:

  • Die Browser-Bindings prüfen jedes Pack beim Aufruf von .withPacks() und werfen vor dem Scan einen Fehler bei einem Pack, das core nicht ausführen kann. Ein Pack, das die Seite dann nicht ausführt, ist eine Lücke 'pack-skipped' in getScanGaps(results), und .analyze() warnt davor, sodass ein Test, der die Lücken prüft, fehlschlägt.
  • Die Test-Matcher lassen die Assertion scheitern und nennen das Pack und den Grund.
  • Die CLI endet mit Exit-Code 2, ohne einen Bericht oder eine Baseline zu schreiben, bei einem Pack, das sie nicht finden oder laden kann, oder einem, das die Engine überspringt.

Installieren Sie das Pack neben @surea11y/core und dem Paket, das es ausführt, damit alle drei dieselbe Kopie von core nutzen.

Ein Pack schreiben

Vom Beispiel ausgehen

Ein Pack ist ein Objekt, das mit definePack aus @surea11y/core/pack erstellt wird. Das ist acme-policy-pack.js, das Beispiel, das die Bindings mitliefern:

'use strict';
 
// A small pack: one house rule, a checklist profile and two checklist items.
// A real pack is a package of its own; `npx surea11y-pack new <folder>` writes one.
 
const { definePack, wcagTags } = require('@surea11y/core/pack');
 
module.exports = definePack({
name: '@acme/a11y-policy',
title: 'Acme web policy',
version: '1.0.0',
namespace: 'acme',
core: '^1.11.1',
rules: [
{
id: 'acme-no-autoplay',
meta: {
title: 'Videos do not play sound on their own',
description: 'A video that starts with sound talks over a screen reader.',
tags: ['acme'],
defaultSeverity: 'serious'
},
runInPage(ctx) {
// defaultMuted reflects the muted attribute where muted isn't set from it yet (jsdom).
const loud = [...ctx.document.querySelectorAll('video[autoplay]')].filter((v) => !(v.muted || v.defaultMuted));
return loud.length
? {
outcome: 'fail',
occurrences: loud.map((v) =>
ctx.helpers.reportOccurrence(v, { summary: 'This video plays with sound as the page opens.', hint: 'Remove autoplay, or add muted.' })
)
}
: { outcome: 'pass', occurrences: [] };
}
}
],
profiles: {
'acme-web-2026': { tags: wcagTags('2.2', ['A', 'AA']), rules: ['region', 'acme-no-autoplay'] }
},
rollups: [
{ id: 'acme-images', title: 'Images have a text alternative', checksIds: ['img-alt-present'] },
{ id: 'acme-media', title: 'Media stays quiet until asked', checksIds: ['acme-no-autoplay'] }
]
});

Sein Profil, acme-web-2026, führt die Regeln für WCAG 2.2 A und AA aus core aus, die Best-Practice-Regel region, die kein WCAG-Tag auswählt, und die hauseigene Regel. Seine zwei Zusammenfassungen sind die Punkte der Checkliste: Jede gruppiert Regeln, aus core oder dem Pack, zu einem Ergebnis.

Für eine Norm ist das EN-301-549-Pack ein vollständiges, veröffentlichtes Beispiel.

Eines mit surea11y-pack new erstellen

Für ein eigenes Pack gehen Sie von einem erzeugten Paket aus:

$ npx -p @surea11y/core surea11y-pack new acme-a11y --name @acme/a11y-pack
# or, for a standard:
$ npx -p @surea11y/core surea11y-pack new city-standard --name @city/a11y-standard --kind standard --title "City Standard"
$ cd acme-a11y
$ npm install
$ npx playwright install chromium # once, for npm run docs
$ npm test && npm run lint && npm run docs

Das Pack funktioniert direkt nach dem Erzeugen: Seine Tests bestehen, seine Regeln bestehen den Lint ohne Befunde, seine Beispiele stimmen mit seinen Regeln überein. surea11y-pack new prüft das Pack vor dem Schreiben so, wie ein Scan es täte, und lehnt einen Namen, Namensraum oder Titel ab, der es ungültig machen würde (ein Titel WCAG gibt seine Norm als eine von core aus), mit Begründung. Ändern Sie es von dort aus Schritt für Schritt und führen Sie dabei npm test aus. Seine README geht jede Datei durch:

DateiWas sie enthält
index.jsDas Pack, geschrieben mit definePack() aus @surea11y/core/pack.
rules/automatic/<ns>-link-text-specific.jsEine Regel, die entscheidet, mit den Helfern von core.
rules/automatic/<ns>-contrast-enhanced.jsEine Variante von contrast-minimum aus core bei 7:1.
rules/manual/<ns>-new-window-review.jsEine manuelle Regel, die eine manuelle Prüfung verlangt, mit ihren Reason-Codes und den Schritten, mit denen eine Person sie beantwortet (meta.reasonCodes, meta.review).
i18n/en.jsonDie Meldungen.
tests/rules/*.test.js, tests/profiles.test.jsEin Test pro Regel und dafür, was jedes Profil ausführt.
docs/RULE_EXAMPLES.mdBeispiele für die Ergebnisse jeder Regel.
eslint.config.jsDie Lint-Regeln von core für Regeln.
requirements.js, rule-map.jsNur bei einer Norm: die Anforderungen und die Regeln, die jede prüfen.
package.jsonprivate, mit @surea11y/core als Peer-Dependency in der Version, die es geschrieben hat (^1.14.1), und eslint, jsdom und Playwright als Entwicklungsabhängigkeiten.
README.md, .gitignoreDie eigene Anleitung des Packs zu diesen Dateien, und was git auslässt.

Namen

  • Paketname und Version sind ein npm-Paketname und eine vollständige Version (1.0.0). Ein Scan meldet sie in engine.packs.
  • Der Namensraum (namespace: 'acme') hält die IDs des Packs von denen von core und anderer Packs getrennt: Jede Regel-, Zusammenfassungs- und Profil-ID beginnt mit ihm und -. Er darf kein Präfix von Regel-IDs aus core sein (img, aria oder link wären es, wie in img-alt-present) und nicht mit wcag beginnen, und zwei Packs in einem Scan können ihn nicht teilen. Er ist außerdem das Tag, das die eigenen Regeln des Packs zu Opt-in-Regeln macht: Eine Regel mit diesem Tag läuft nur unter einem der Profile des Packs, über ihre ID oder über das Tag (optInRules: ['acme']). Standardmäßig führt ein Scan, der auf WCAG zielt, sie also nicht aus. Das Freischalten des Tags mit optInRules entfernt weder das Profil noch die Filter des Scans: Unter einem WCAG-Profil läuft eine freigeschaltete Regel nur, wenn ihre Tags auch zu diesem Profil passen. Lassen Sie das Tag bei einer Regel weg, die in jedem Scan mit dem Pack laufen soll: Sie wird dann ausgewählt wie die Regeln von core, und ein Scan, der auf WCAG zielt, kann sie ausführen und ihre Fehlschläge melden, wenn ihre Tags passen.
  • core ist der Bereich der core-Versionen, mit denen das Pack funktioniert ('^1.11.1'), gelesen so, wie npm Bereiche liest. Beginnen Sie neue Packs mit 1.11.1: Dem Paket 1.11.0 fehlte eine Datei, die Packs in Node brauchen. Ein Scan mit einem core außerhalb davon überspringt das Pack, mit dem Grund in skippedPacks. surea11y-pack new schreibt die Version, die das Pack erzeugt hat (^1.14.1); behalten Sie einen Bereich, der bei 1.14 beginnt, wenn das Pack nutzt, was 1.14 hinzugefügt hat: meta.review, Zeilen mit reasonCodes und findings, meta.contributions, applicability, partial oder keepsParsing.
  • title ist der Name, unter dem Ergebnisse und Berichte eine Checkliste führen, und description ein Satz dazu, was das Pack prüft, für Tools, in denen Nutzende Packs auswählen können (describePacks gibt ihn zurück).

Profile

Ein Profil ist eine benannte Auswahl, ausgeführt mit engineOptions.profile. Eine Regel läuft darunter, wenn sie eines seiner tags trägt oder ihre ID in rules steht und sie nicht in exclude steht; die Regeln des Packs, die das Tag seines Namensraums tragen, laufen unter jedem Profil des Packs.

profiles: {
'acme-policy': {
tags: wcagTags('2.2', ['A', 'AA']), // core's WCAG 2.2 A and AA rules
rules: ['region', 'heading-order'], // and these, by id
exclude: { rules: ['contrast-minimum'] }, // but not this one
severity: { 'img-alt-present': 'critical' } // and this one is critical here
},
'acme-quick': {
tags: [],
rules: ['img-alt-present', 'link-name-present', 'page-title-present']
}
}
FeldWas es bewirkt
tagsRegeln, die eines dieser Tags tragen. wcagTags(version, levels) aus @surea11y/core/pack liefert die WCAG-Tags von core (wcagTags('2.1') sind 2.0 und 2.1, A und AA).
rulesRegeln nach ID, aus core oder dem Pack: eine Best-Practice-Regel, die kein WCAG-Tag auswählt, oder, mit tags: [], die Regeln von core, die das Profil neben den eigenen des Packs ausführt.
exclude{ rules: [...] } lässt Regeln aus dem Scan weg; { criteria: ['2.5.8'] } erlässt diese Kriterien: Ihre Zusammenfassungen entfallen, ebenso jede Regel, deren Kriterien alle erlassen sind; eine Regel, die auch ein Kriterium prüft, das das Profil behält, läuft weiter. Das schränkt ein, was der Scan prüft: Die Anforderungen der WCAG bleiben, wie sie sind.
severity{ ruleId: level }: ein anderer Schweregrad unter dem Profil. Ergebnisse zeigen ihn und behalten den ursprünglichen Schweregrad der Regel als ruleSeverity; Baselines und Befund-IDs ändern sich nicht.
wcagVersion'2.0', '2.1' oder '2.2': die WCAG-Version, nach der die Scans des Profils beurteilt werden (engine.wcagVersion). Ohne das Feld ergibt sich die Version aus den WCAG-Tags in tags, und ein Profil ohne solche Tags wird nach 2.2 beurteilt. Eine eigene engineOptions.wcagVersion des Scans hat weiterhin Vorrang. Ab core 1.12.0.
keepsParsingtrue, wenn die Norm 4.1.1 „Syntaxanalyse“ im Wortlaut verlangt, wie EN 301 549 V3.2.1: Ein Fehlschlag dort bleibt dann bei einem 2.0- oder 2.1-Ziel ein Fehlschlag. Unter einem Profil ohne dieses Feld werten die Errata von 2023 zu WCAG 2.0 und 2.1 das Kriterium 4.1.1 für HTML und XML als erfüllt, und duplicate-id fragt stattdessen nach (unter 2.2, das 4.1.1 entfernt hat, fragt es nach, gleich was das Profil sagt). Nur das eigene Feld des Profils zählt: Das Profil eines Packs, das an die Stelle eines Profils von core tritt, erbt es nicht. engineOptions.mappings ändert nie ein Ergebnis; ein Scan, der nach einer Norm beurteilt wird, die 4.1.1 beibehält, führt daher deren Profil aus. Ab core 1.14.0.
version, mappedRulesNur beim Profil einer Norm: die Version der Norm, auf die es zielt, und mappedRules: true, um jede Regel auszuführen, die die Norm für diese Version zuordnet.

Ein Profil, das nur ausführt, was seine Norm verlangt. Das Profil einer Norm mit tags: [<ns>] und mappedRules: true führt die eigenen Regeln des Packs und die Regeln von core aus, die seine Zuordnung mit einer Anforderung verknüpft, und sonst nichts: Keine Regel prüft, was die Norm nicht verlangt, und die Ergebnisse enthalten keine WCAG-Kriterien. Ohne WCAG-Tag sagt allerdings nichts, auf welcher WCAG-Version die Norm aufbaut, und der Lauf wird nach 2.2 beurteilt. Für eine Norm, die auf 2.1 aufbaut, ist das falsch: Der Lauf meldet Kriterien von 2.2, etwa 2.5.8, die die Norm nicht hat. Geben Sie die Version an, und keepsParsing: true, wenn die Norm 4.1.1 „Syntaxanalyse“ weiterhin verlangt. Die erzeugte index.js liest sie aus requirements.js, wo jede Version der Norm die WCAG-Version nennt, auf der sie aufbaut ({ version: '1.0', wcagVersion: '2.2' }):

'city-1.0': {
version: '1.0',
tags: ['city'], // the pack's own rules
mappedRules: true, // and the core rules its map links to a requirement
wcagVersion: wcagVersionOf('1.0') // judged by the WCAG version requirements.js gives for 1.0
}

Die Regeln von core mit ihren IDs und Tags stehen unter Regeln.

Checklistenpunkte und Anforderungen

Die Punkte einer Checkliste sind ihre rollups: { id, title, checksIds }, die jeweils Regeln zu einem Ergebnis gruppieren. Ein Punkt ergibt fail, wenn eine seiner Regeln fail ergibt, und pass, wenn alle bestehen. Ergibt keine Regel fail, aber eine cantTell, ist auch der Punkt cantTell: Er erfordert eine manuelle Prüfung. Ein Pack gibt entweder profiles und rollups an, eine Checkliste, oder einen standard, nicht beides.

Die Anforderungen einer Norm stammen aus zwei Tabellen, die der Generator schreibt: requirements.js (pro Version Nummer, Wortlaut und WCAG-Kriterien jeder Anforderung) und rule-map.js (welche Anforderungen jede Regel prüft und warum). ruleMappedStandard() aus @surea11y/core/pack macht daraus die Norm: eine Zusammenfassung pro Anforderung, die Anforderungen, die das Ergebnis jeder Regel nennt, und Prüfungen beider Tabellen beim Vorbereiten des Packs.

Befunde Anforderungen zuweisen

Die Zeile einer Regel in rule-map.js kann ihre Befunde eines Reason-Codes anderswohin schicken, mit reasonCodes: { [code]: { requirements, outcome } }: requirements (standardmäßig die der Zeile) sind die Anforderungen, für die diese Befunde zählen, [] für keine, und outcome: 'cantTell' macht einen fehlschlagenden dort zu einer Frage. Die Zusammenfassung einer Anforderung beurteilt die Regel dann nach den Befunden, die für sie zählen; so kann eine Norm zu einer Ursache nachfragen, wo WCAG sie fehlschlagen lässt, oder zwei Ursachen zwei Tests zuordnen:

'list-children-valid': {
requirements: ['9.3.1'],
reasonCodes: { LIST_ITEM_ROLE_OVERRIDDEN: { requirements: ['9.3.1', '9.3.2'], outcome: 'cantTell' } }
}

Eine Zeile kann Befunde auch danach zuweisen, was sie festhalten, mit findings: [{ when, requirements, outcome }]: when gibt Werte an, die Felder im data.details eines Befunds haben müssen, benannt über ihren Pfad mit Punkten. Ein Befund richtet sich nach dem ersten Eintrag, auf den er passt, sonst nach seinem Reason-Code, sonst nach der Zeile. So kann eine Norm die Fehlschläge einer Regel dem Test für ihre Textgröße zuordnen, obwohl sie einen Reason-Code teilen:

'contrast-minimum': {
requirements: ['3.1', '3.2'],
findings: [
{ when: { 'typography.isLargeText': false }, requirements: ['3.1'] },
{ when: { 'typography.isLargeText': true }, requirements: ['3.2'] }
]
}

Vergleichen Sie nur Felder, die eine Regel stabil hält: reasonCode bei jeder Regel und die wenigen weiteren, die die API-Stabilitätsrichtlinie von core auf GitHub nennt (darunter Kontrastverhältnis, Schwelle und Typografie von contrast-minimum). Ein Feld, das sich ändert oder wegfällt, passt auf nichts, und der Befund richtet sich nach seinem Code oder der Zeile. Die Reason-Codes jeder Regel stehen unter „What a finding reports“ im Regelkatalog von core auf GitHub.

Zwei weitere Felder ändern, wie eine Anforderung beurteilt wird. Eine Norm, deren Anforderungen WCAG-Kriterien eins zu eins wiedergeben, wie Kapitel 9 der EN 301 549, übergibt applicability: 'wcag' an ruleMappedStandard: Die Zusammenfassung einer Anforderung ist dann nur dort notApplicable oder pass, wo es die WCAG-Zusammenfassung ihrer Kriterien wäre, sodass beide in einem Bericht übereinstimmen. Eine Anforderung, die die Regeln von core nicht vollständig prüfen, ohne ein Kriterium wiederzugeben, trägt partial: true in der Anforderungstabelle: Ihre Zusammenfassung ist dann cantTell, wo alle ihre Regeln bestehen oder nichts finden, da sie nur einen Teil geprüft haben. Eine Norm, die ihre eigenen Zusammenfassungen schreibt, gibt beides im meta jeder Zusammenfassung an und weist Befunde in meta.contributions zu; StandardRollup in pack.d.ts gibt die Form vor, und die Pack-Anleitung von core auf GitHub führt Schritt für Schritt durch. All das braucht core 1.14.0.

Regeln

Eine Regel hat die Form der Regelmodule von core: { id, meta, runInPage }, und applicability, wenn sie nur manchmal anwendbar ist, mit demselben ctx. runInPage(ctx) läuft in der Seite, verwendet also nur ctx, nie eine Variable oder ein Modul von außerhalb, und liest nur: Die Regeln eines Packs laufen nach denen von core, und die Helfer und Optionen, die sie erhalten, sind schreibgeschützt. Schreibschutz ist eine Regel, keine Sandbox: Nichts hindert den Code einer Regel daran, mehr zu tun, laden Sie also nur Packs, denen Sie vertrauen (siehe die Sicherheitsrichtlinie von core auf GitHub). Drei Abkürzungen brauchen wenig oder keinen Code: eine Variante führt eine Regel von core mit anderen Einstellungen aus ({ id, from: 'contrast-minimum', config: { normalTextRatio: 7 }, meta }; ein Schwellenwert nimmt eine endliche Zahl über 0, eine Auswahl einen ihrer aufgeführten Werte, und definePack lehnt alles andere ab), eine Überschreibung ersetzt eine Regel von core (aufgeführt in overrides und in overriddenBuiltinIds der Ergebnisse), und eine Regel von core, wie sie ist, braucht nur ihre ID in einem Profil oder einer Zusammenfassung. Wie man eine Regel schreibt, steht in der Anleitung zum Schreiben von Regeln von core auf GitHub.

Die Liste der Regeleinstellungen von core auf GitHub nennt jede Einstellung, die die Regeln von core einer Variante bieten, mit ihrem Standardwert, den Werten, die sie annimmt, und dem, was sie ändert; getChecksCatalog() gibt dasselbe als variantSettings jeder Regel aus. So läuft die Fassung einer Anforderung aus einer anderen Norm, oder eine Wahl, die WCAG der prüfenden Person überlässt, auf dem Code von core. Seit core 1.14 bietet contrast-minimum Auswahlmöglichkeiten für Text, der wie ein Logo aussieht (logoText), für eine Seite mit einem Schalter zu höherem Kontrast (contrastSwitch) und für halbfetten Text (semiBold), und valid-lang bietet codes: 'iso639' für eine Norm wie RGAA, die jeden Sprachcode nach ISO 639 akzeptiert.

Wie eine Person ein cantTell prüft

Eine Regel, die einen Befund offen lassen kann, kann pro Reason-Code angeben, wie eine Person ihn beantwortet, wie es die Regeln von core tun (siehe „So prüfen Sie es“ im Ausgabeschema): einige Schritte, ausgehend von dem Element, das der Befund nennt, und dann, was sie sieht, wenn er besteht und wenn er fehlschlägt.

meta.review = {
GENERIC_LINK_NAME: {
steps: ['Find the link the report names.', 'Read the text around it.'],
passWhen: 'The text around the link says where it goes.',
failWhen: 'Nothing near the link says where it goes, which fails WCAG 2.4.4.'
}
};

definePack prüft die Form: 1 bis 6 Schritte und ein nicht leeres passWhen und failWhen pro Reason-Code. Eine Regel, die ihre Reason-Codes in meta.reasonCodes angibt (['GENERIC_LINK_NAME']), gibt nur für einen Code Schritte an, den sie dort angibt oder in ihrem runInPage nennt, sodass ein vertippter Code abgelehnt wird: Sie anzugeben lohnt sich für diese Prüfung. Die Schritte sind englisch, gleich in welcher Locale der Scan läuft, und bleiben außerhalb der Seite: runDomRulesInPage mit engineOptions.packs fügt sie dem Ergebnis hinzu, und bei einem Ergebnis aus einer Seite tut es addHowToCheck(result, { packs }). Eine Variante hat die Schritte ihrer Regel von core, übersetzt, und braucht daher keine; eine Überschreibung hat, wie eine eigene Regel, keine. Ab core 1.14.0.

Meldungen und Sprachen

Jeder Text, den eine Regel zeigt, hat einen Schlüssel, pro Locale in i18n/<locale>.json abgelegt und in den dictionaries des Packs aufgeführt. Ein Scan mit engineOptions.locale: 'fr' zeigt die französischen; eine Locale, für die das Pack kein Wörterbuch hat, zeigt Englisch. Die Schlüssel eines Packs sind seine eigenen und beginnen mit seinem Namensraum: Ein Pack kann keine Meldung von core in einer Locale ändern, die core mitliefert.

Testen, linten und dokumentieren

  • Tests verwenden @surea11y/core/testing, das, was die eigenen Regeltests von core verwenden: runa11yCoreOnHtml(html, { engineOptions }) scannt HTML in jsdom, und assertRule(result, ruleId, outcome) prüft eine Regel. Mit Packs führt der Scan sie sowohl aus den Pack-Objekten aus als auch so, wie eine Seite sie hat, sodass eine Regel, die eine Variable von außerhalb ihrer Funktion liest, an ihrem Test scheitert. Dafür ist jsdom als Dev-Dependency nötig.
  • Prüfungen: definePack wirft einen Fehler, der jedes Problem nennt, sodass die eigenen Tests des Packs fehlschlagen; checkPack(pack) gibt dieselbe Liste zurück, ohne zu werfen, und prüft dabei auch die installierte Version von core. Beide führen die eigenen Prüfungen einer Norm für ihre Tabellen (validate) gegen die Regeln von core und des Packs aus, wie es ein Scan tut, sodass eine Version ohne ihr wcagVersion oder ein Befund, der einer in der Tabelle fehlenden Anforderung zugewiesen ist, schon dort abgelehnt wird, statt dass jeder Scan das Pack überspringt. Ab core 1.14.0.
  • Lint (npm run lint, @surea11y/core/eslint-plugin) misst die Regeln des Packs an denselben Lint-Regeln wie die von core.
  • Docs (npm run docs, surea11y-pack docs) schreiben docs/RULE_CATALOG.md des Packs und führen jedes Beispiel aus seinem docs/RULE_EXAMPLES.md in Chromium aus (CHROMIUM_EXECUTABLE_PATH nennt einen anderen Chromium-Build); --check schlägt fehl, wenn eines davon veraltet ist, für die CI des Packs.

Veröffentlichen

Das erzeugte Paket ist private. Wählen Sie seine Lizenz, setzen Sie license und entfernen Sie private in package.json, und führen Sie npm publish aus. Behalten Sie @surea11y/core als Peer Dependency, mit dem Bereich aus core. Semver deckt ab, worauf ein Pack aufbaut: Ein für core 1.11 geschriebenes Pack funktioniert mit späteren 1.x-Versionen weiter. Für Ihre eigenen Nutzenden sind die ID einer Regel und ihre Reason-Codes das, was deren Baselines enthalten: Benennen Sie eine davon nur in einer Major-Version des Packs um oder entfernen Sie sie nur dann.

Die vollständige Anleitung, von einem leeren Ordner bis zu einem veröffentlichten Pack, ist PACKS.md von core auf GitHub, und jedes Feld steht in der Pack-Referenz von ENGINE_OPTIONS.md.