eaa-kit 0.5.0 → 0.7.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 (69) hide show
  1. package/README.md +53 -5
  2. package/dist/astro/index.d.ts +1 -1
  3. package/dist/astro/index.js +1 -1
  4. package/dist/audit/runners/worker.js +1 -1
  5. package/dist/audit-Bwm1xBdJ.js +2 -0
  6. package/dist/{audit-B282A3EA.js → audit-DRjAY2iY.js} +243 -107
  7. package/dist/{baseline-CuAS2lMk.js → baseline-BpE7DbDq.js} +36 -9
  8. package/dist/baseline-rtnj3RHB.js +2 -0
  9. package/dist/cache-D4dOIuOi.js +219 -0
  10. package/dist/checklist-DDd9jewi.js +44 -0
  11. package/dist/cli/index.js +130 -17
  12. package/dist/{command-C3D7JWn6.js → command-3r4fht5f.js} +102 -10
  13. package/dist/{component-C3GL1Mnu.js → component-ChisoFyY.js} +1 -1
  14. package/dist/{component-DKd3EHOg.js → component-DcCn3BJS.js} +1 -1
  15. package/dist/{coverage-B_Y6l-Ra.js → coverage-cb5kPp48.js} +45 -290
  16. package/dist/coverage-n1X9CkiG.js +3 -0
  17. package/dist/{crawl-BUWPgaGW.js → crawl-BHkJmUkA.js} +42 -8
  18. package/dist/criteria-CnPJKGeb.js +286 -0
  19. package/dist/eleventy/index.d.ts +1 -1
  20. package/dist/eleventy/index.js +1 -1
  21. package/dist/{html-C4vktg0A.js → html-BIxxF3FC.js} +54 -30
  22. package/dist/{impact-DZt2oBCP.js → impact-luGCnN8F.js} +11 -1
  23. package/dist/index.d.ts +87 -1
  24. package/dist/index.js +3 -3
  25. package/dist/{init-CW7LfGT5.js → init-DrFfzjvm.js} +3 -3
  26. package/dist/jsdom-BUYuVJJm.js +3 -0
  27. package/dist/{jsdom-B--cEH-G.js → jsdom-CsW_xVcA.js} +11 -12
  28. package/dist/{json-DROX33kh.js → json-Bus6YhxB.js} +13 -17
  29. package/dist/{json-D_Mnnft5.js → json-CrQmoTj6.js} +1 -1
  30. package/dist/{load-yAR4wzez.js → load-BaWMa-G_.js} +11 -2
  31. package/dist/load-n62iXDq_.js +2 -0
  32. package/dist/nuxt/index.d.ts +1 -1
  33. package/dist/nuxt/index.js +1 -1
  34. package/dist/{playwright-BojtYVUa.js → playwright-ukCr_5o3.js} +3 -2
  35. package/dist/{pool-BO25OIez.js → pool-B4tEUa2S.js} +6 -2
  36. package/dist/{remediation-CMBIrnpN.js → remediation-C0klJblu.js} +35 -4
  37. package/dist/{render-DbGOVmhx.js → render-C1sUZZI_.js} +145 -6
  38. package/dist/{result-BWcYXeRs.js → result-B7_zVxAX.js} +24 -1
  39. package/dist/result-CRmjjoAA.js +2 -0
  40. package/dist/review-CdMK2GpQ.js +161 -0
  41. package/dist/review-DIbOTmOM.js +2 -0
  42. package/dist/{run-CtcEUhbe.d.ts → run-BK2blxMI.d.ts} +18 -0
  43. package/dist/{run-C2nKFcb-.js → run-DrS0Komf.js} +6 -2
  44. package/dist/{sarif-B-UBcVu8.js → sarif-BNCE0PNT.js} +24 -12
  45. package/dist/statement/templates/at.de.md +14 -0
  46. package/dist/statement/templates/at.en.md +14 -0
  47. package/dist/statement/templates/ch.de.md +14 -0
  48. package/dist/statement/templates/ch.en.md +14 -0
  49. package/dist/statement/templates/de.de.md +14 -0
  50. package/dist/statement/templates/de.en.md +14 -0
  51. package/dist/statement/templates/es.en.md +14 -0
  52. package/dist/statement/templates/es.es.md +15 -0
  53. package/dist/statement/templates/fr.en.md +14 -0
  54. package/dist/statement/templates/fr.fr.md +15 -0
  55. package/dist/statement/templates/it.en.md +14 -0
  56. package/dist/statement/templates/it.it.md +15 -0
  57. package/dist/statement/templates/nl.en.md +14 -0
  58. package/dist/statement/templates/nl.nl.md +15 -0
  59. package/dist/{text-CKKpzkYM.js → text-BF1LHMiV.js} +22 -2
  60. package/dist/vite/index.d.ts +1 -1
  61. package/dist/vite/index.js +1 -1
  62. package/dist/webpack/index.d.ts +1 -1
  63. package/dist/webpack/index.js +1 -1
  64. package/dist/worksheet-BIxMtbUd.js +64 -0
  65. package/package.json +3 -2
  66. package/dist/audit-DyHPmGeD.js +0 -2
  67. package/dist/baseline-0u4df12v.js +0 -2
  68. package/dist/jsdom-22Bkt65v.js +0 -3
  69. package/dist/load-CFq2VQtT.js +0 -2
@@ -0,0 +1,161 @@
1
+ import { d as optional, h as string, i as enumeration, l as number, m as safeParse, o as isoDate, p as record, u as object, y as withDefault } from "./schema-DJSF4K05.js";
2
+ import { a as isoDate$1 } from "./text-BF1LHMiV.js";
3
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ /** Default filename, used by the CLI when no path is given. */
6
+ const DEFAULT_REVIEW_FILE = "eaa-review.json";
7
+ /**
8
+ * What a person concluded about one criterion.
9
+ *
10
+ * `not-applicable` is kept apart from `met` for the reason `inapplicable` is
11
+ * kept apart from `passes` everywhere else in this tool: a criterion with
12
+ * nothing on the site to which it applies has not been met, it has been ruled
13
+ * out, and folding the two together would let an empty site look conformant.
14
+ */
15
+ const REVIEW_RESULTS = [
16
+ "met",
17
+ "not-met",
18
+ "not-applicable",
19
+ "unreviewed"
20
+ ];
21
+ const entrySchema = object({
22
+ result: withDefault(enumeration(REVIEW_RESULTS), () => "unreviewed"),
23
+ /** ISO date the check was done. Without it the entry cannot be aged. */
24
+ reviewedOn: optional(isoDate()),
25
+ /** Who did it, when that is not the person named on the record. */
26
+ reviewedBy: optional(string()),
27
+ /** What was checked and what was found. Free text, for whoever reads it. */
28
+ note: optional(string())
29
+ });
30
+ const reviewSchema = object({
31
+ schemaVersion: number(),
32
+ /** Who carried out the review, for the record as a whole. */
33
+ reviewedBy: optional(string()),
34
+ /** Keyed by success criterion number, e.g. '1.2.1'. */
35
+ criteria: withDefault(record(entrySchema), () => ({}))
36
+ });
37
+ var ReviewError = class extends Error {
38
+ name = "ReviewError";
39
+ };
40
+ /**
41
+ * What the record says about one criterion, and whether it counts.
42
+ *
43
+ * Returns undefined when there is nothing recorded, which is the ordinary case
44
+ * for most criteria of most sites: a missing entry and an `unreviewed` one mean
45
+ * the same thing and are reported the same way.
46
+ */
47
+ function criterionReview(criterionNumber, options, engineReachedVerdict) {
48
+ const entry = options.record.criteria[criterionNumber];
49
+ if (entry === void 0 || entry.result === "unreviewed") return void 0;
50
+ const attributed = {
51
+ ...entry,
52
+ ...entry.reviewedBy === void 0 && options.record.reviewedBy !== void 0 ? { reviewedBy: options.record.reviewedBy } : {}
53
+ };
54
+ const ignored = ignoredReason(entry, options, engineReachedVerdict);
55
+ return ignored === void 0 ? {
56
+ ...attributed,
57
+ counts: true
58
+ } : {
59
+ ...attributed,
60
+ counts: false,
61
+ ignored
62
+ };
63
+ }
64
+ function ignoredReason(entry, options, engineReachedVerdict) {
65
+ if (engineReachedVerdict) return "engine-reached-a-verdict";
66
+ if (options.maxAgeDays === void 0) return void 0;
67
+ if (entry.reviewedOn === void 0) return "undated";
68
+ return olderThan(entry.reviewedOn, options.maxAgeDays, options.today ?? /* @__PURE__ */ new Date()) ? "stale" : void 0;
69
+ }
70
+ /** Whole days between an ISO date and today, without pulling in a date library. */
71
+ function olderThan(reviewedOn, maxAgeDays, today) {
72
+ const then = Date.parse(`${reviewedOn}T00:00:00Z`);
73
+ if (Number.isNaN(then)) return true;
74
+ return (Date.parse(`${isoDate$1(today)}T00:00:00Z`) - then) / 864e5 > maxAgeDays;
75
+ }
76
+ /**
77
+ * What a person recorded, as the sentence both reports print under the criterion.
78
+ *
79
+ * One sentence rather than one per format: the console report and the HTML one
80
+ * were composing the same four parts in the same order, with two tables of
81
+ * reasons that had already drifted apart in wording. A reader comparing the two
82
+ * documents of one run should not have to work out whether they mean the same
83
+ * thing.
84
+ *
85
+ * An entry that was not counted still gets a sentence, with the reason. Dropping
86
+ * it would hide the one thing a reader has to act on: a review that has aged
87
+ * out, or one recorded against a criterion the run decided for itself.
88
+ */
89
+ function reviewSentence(review) {
90
+ const by = review.reviewedBy === void 0 ? "" : ` by ${review.reviewedBy}`;
91
+ const on = review.reviewedOn ?? "no date recorded";
92
+ const because = review.counts ? "" : `, not counted: ${IGNORED_REASONS[review.ignored ?? "stale"]}`;
93
+ return `checked by hand${by} (${on}): ${review.result}${because}`;
94
+ }
95
+ /** Why an entry was read and not counted, in words rather than a code. */
96
+ const IGNORED_REASONS = {
97
+ "engine-reached-a-verdict": "this run reached its own verdict here",
98
+ stale: "older than the maximum age this run was given",
99
+ undated: "no date recorded, and a maximum age was set"
100
+ };
101
+ /** A record with an entry for every criterion, keeping any answers already given. */
102
+ function blankReview(criteria, existing) {
103
+ const entries = {};
104
+ for (const criterion of criteria) entries[criterion.number] = existing?.criteria[criterion.number] ?? { result: "unreviewed" };
105
+ for (const [number, entry] of Object.entries(existing?.criteria ?? {})) entries[number] ??= entry;
106
+ return {
107
+ schemaVersion: 1,
108
+ ...existing?.reviewedBy ? { reviewedBy: existing.reviewedBy } : {},
109
+ criteria: sortByCriterion(entries)
110
+ };
111
+ }
112
+ /** How many criteria the record has a usable answer for, before any run is considered. */
113
+ function answeredCount(record) {
114
+ return Object.values(record.criteria).filter((entry) => entry.result !== "unreviewed").length;
115
+ }
116
+ /** Numerically by section, so 1.4.10 sorts after 1.4.5 rather than before it. */
117
+ function sortByCriterion(entries) {
118
+ return Object.fromEntries(Object.entries(entries).sort(([a], [b]) => compareCriteria(a, b)));
119
+ }
120
+ function compareCriteria(a, b) {
121
+ const left = a.split(".").map(Number);
122
+ const right = b.split(".").map(Number);
123
+ for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
124
+ const difference = (left[index] ?? 0) - (right[index] ?? 0);
125
+ if (difference !== 0) return difference;
126
+ }
127
+ return 0;
128
+ }
129
+ function serialiseReview(record) {
130
+ return `${JSON.stringify(record, null, 2)}\n`;
131
+ }
132
+ async function readReview(file, cwd = process.cwd()) {
133
+ const target = path.resolve(cwd, file);
134
+ let raw;
135
+ try {
136
+ raw = await readFile(target, "utf8");
137
+ } catch {
138
+ throw new ReviewError(`Could not read the review record at ${file}. Create one with: eaa-kit checklist`);
139
+ }
140
+ let value;
141
+ try {
142
+ value = JSON.parse(raw);
143
+ } catch (cause) {
144
+ throw new ReviewError(`${path.basename(target)} is not valid JSON: ${cause instanceof Error ? cause.message : String(cause)}`);
145
+ }
146
+ const result = safeParse(reviewSchema, value);
147
+ if (!result.success) {
148
+ const issues = result.error.issues.map((issue) => `${issue.path.join(".") || "document"}: ${issue.message}`).slice(0, 5);
149
+ throw new ReviewError(`${path.basename(target)} is not an eaa-kit review record (${issues.join("; ")})`);
150
+ }
151
+ if (result.data.schemaVersion !== 1) throw new ReviewError(`${path.basename(target)} has schemaVersion ${result.data.schemaVersion}; this version of eaa-kit reads 1.`);
152
+ return result.data;
153
+ }
154
+ async function writeReview(file, record, cwd = process.cwd()) {
155
+ const target = path.resolve(cwd, file);
156
+ await mkdir(path.dirname(target), { recursive: true });
157
+ await writeFile(target, serialiseReview(record), "utf8");
158
+ return target;
159
+ }
160
+ //#endregion
161
+ export { blankReview as a, readReview as c, writeReview as d, answeredCount as i, reviewSentence as l, REVIEW_RESULTS as n, compareCriteria as o, ReviewError as r, criterionReview as s, DEFAULT_REVIEW_FILE as t, serialiseReview as u };
@@ -0,0 +1,2 @@
1
+ import { a as blankReview, c as readReview, d as writeReview, i as answeredCount, r as ReviewError } from "./review-CdMK2GpQ.js";
2
+ export { ReviewError, answeredCount, blankReview, readReview, writeReview };
@@ -29,9 +29,27 @@ interface IntegrationOptions {
29
29
  fast?: boolean;
30
30
  concurrency?: number;
31
31
  baseline?: string;
32
+ /**
33
+ * Path to a review record: what a person checked, for the criteria no engine
34
+ * can reach. It changes nothing about whether the build fails — a review is a
35
+ * claim beside the run's own findings, never a verdict on them — but it is
36
+ * what makes the coverage in a build log describe the whole standard rather
37
+ * than only the automatable fraction of it.
38
+ */
39
+ review?: string;
40
+ /** Days after which a recorded review stops counting. */
41
+ reviewMaxAge?: number;
32
42
  format?: OutputFormat;
33
43
  /** Write the report here instead of the build log. */
34
44
  output?: string;
45
+ /**
46
+ * False audits every page, reusing nothing an earlier build measured.
47
+ *
48
+ * The cache is on by default here as everywhere, and a build is where it pays
49
+ * best: most builds change a handful of pages. Turn it off for a release
50
+ * build that should answer from nothing but the files in front of it.
51
+ */
52
+ cache?: boolean;
35
53
  /**
36
54
  * Report without failing the build. For the week it takes to adopt this on a
37
55
  * site that already exists — a baseline is the honest way to go green after
@@ -30,12 +30,16 @@ var BuildAuditError = class extends Error {
30
30
  * when it should not.
31
31
  */
32
32
  async function auditBuild(directory, options, logger) {
33
- const { enabled, failBuild, ...auditOptions } = options;
33
+ const { enabled, failBuild, cache, ...rest } = options;
34
+ const auditOptions = {
35
+ ...rest,
36
+ ...cache === false ? { noCache: true } : {}
37
+ };
34
38
  if (enabled === false) {
35
39
  logger.info("skipped (enabled: false)");
36
40
  return;
37
41
  }
38
- const { runAuditCommand } = await import("./audit-DyHPmGeD.js");
42
+ const { runAuditCommand } = await import("./audit-Bwm1xBdJ.js");
39
43
  const { exitCode } = await runAuditCommand(directory, auditOptions);
40
44
  if (exitCode === 0) {
41
45
  logger.info("no violations at or above the threshold");
@@ -1,8 +1,9 @@
1
- import { o as isImpactLevel } from "./impact-DZt2oBCP.js";
2
- import { o as standardsReference } from "./text-CKKpzkYM.js";
1
+ import { s as isImpactLevel } from "./impact-luGCnN8F.js";
2
+ import { s as standardsReference } from "./text-BF1LHMiV.js";
3
3
  import { t as TOOL_VERSION } from "./version-B3v4rNoG.js";
4
4
  import { t as elementFingerprint } from "./fingerprint-BjYV_0F7.js";
5
- import { c as ruleOutcomes, o as findingElements } from "./result-BWcYXeRs.js";
5
+ import { m as uniqueRuleOutcomes, s as findingElements, u as runEngine } from "./result-B7_zVxAX.js";
6
+ import { t as buildCoverage } from "./coverage-cb5kPp48.js";
6
7
  import path from "node:path";
7
8
  //#region src/audit/report/sarif.ts
8
9
  const SARIF_VERSION = "2.1.0";
@@ -75,7 +76,7 @@ function buildSarifReport(audits, options) {
75
76
  toolExecutionNotifications: notifications
76
77
  }],
77
78
  results,
78
- properties: summaryProperties(audits, options.completeness)
79
+ properties: summaryProperties(audits, options.completeness, options.review)
79
80
  }]
80
81
  };
81
82
  }
@@ -115,12 +116,7 @@ function fingerprint(ruleId, selector, html) {
115
116
  }
116
117
  /** Every rule the run knows about, so the catalogue is complete in GitHub. */
117
118
  function buildRules(audits) {
118
- const rules = /* @__PURE__ */ new Map();
119
- for (const audit of audits) for (const outcome of ruleOutcomes(audit)) {
120
- if (rules.has(outcome.ruleId)) continue;
121
- rules.set(outcome.ruleId, toSarifRule(outcome));
122
- }
123
- return [...rules.values()].sort((a, b) => a.id.localeCompare(b.id));
119
+ return uniqueRuleOutcomes(audits).map(toSarifRule);
124
120
  }
125
121
  function toSarifRule(outcome) {
126
122
  const references = standardsReference(outcome.successCriteria, outcome.enClauses);
@@ -140,7 +136,7 @@ function toSarifRule(outcome) {
140
136
  * Coverage that has no place in `results` but should not vanish: a SARIF log
141
137
  * with no results must not be mistaken for "everything was checked".
142
138
  */
143
- function summaryProperties(audits, completeness) {
139
+ function summaryProperties(audits, completeness, review) {
144
140
  let needsReview = 0;
145
141
  let notEvaluated = 0;
146
142
  const notEvaluatedRules = /* @__PURE__ */ new Set();
@@ -149,15 +145,17 @@ function summaryProperties(audits, completeness) {
149
145
  notEvaluatedRules.add(finding.ruleId);
150
146
  } else needsReview += 1;
151
147
  return {
152
- engine: audits[0]?.engine ?? "jsdom",
148
+ engine: runEngine(audits),
153
149
  pages: audits.length,
154
150
  needsReview,
155
151
  notEvaluated,
156
152
  notEvaluatedRules: [...notEvaluatedRules].sort(),
153
+ ...review ? reviewProperties(audits, review) : {},
157
154
  ...completeness ? {
158
155
  complete: completeness.complete,
159
156
  discovery: completeness.discovery,
160
157
  pagesAudited: completeness.audited,
158
+ pagesReused: completeness.reused,
161
159
  pagesErrored: completeness.errored,
162
160
  pagesUnreachable: completeness.unreachable.length,
163
161
  truncated: completeness.truncated
@@ -165,6 +163,20 @@ function summaryProperties(audits, completeness) {
165
163
  };
166
164
  }
167
165
  /**
166
+ * The review as three counts, in the same shape the JSON report carries them.
167
+ *
168
+ * Counts only: this log's job is alerts, and the criterion-by-criterion detail
169
+ * belongs in the JSON report, which carries it in full.
170
+ */
171
+ function reviewProperties(audits, review) {
172
+ const coverage = buildCoverage(audits, void 0, review);
173
+ return {
174
+ reviewedCriteria: coverage.reviewed,
175
+ reviewedNotMet: coverage.reviewedNotMet,
176
+ reviewNotCounted: coverage.reviewNotCounted
177
+ };
178
+ }
179
+ /**
168
180
  * Artifact URIs are relative to the working directory and POSIX-separated, so
169
181
  * GitHub can line them up with files in the repository.
170
182
  */
@@ -64,6 +64,20 @@ Grundlage ist eine Selbstbewertung durch {{ provider.legalName }}.
64
64
  Grundlage ist eine Prüfung durch Dritte.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ Eines der {{ review.total }} Erfolgskriterien der WCAG 2.2 (Stufen A und AA) wurde manuell
69
+ geprüft.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} der {{ review.total }} Erfolgskriterien der WCAG 2.2 (Stufen A und AA)
73
+ wurden manuell geprüft.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ Die jüngste dieser manuellen Prüfungen erfolgte am {{ review.checkedOnFormatted }}.
77
+ {{/if}}
78
+ {{#if hasReview}}
79
+
80
+ {{/if}}
67
81
  {{#if audit.isSinglePage}}
68
82
  Die automatisierte Prüfung vom {{ audit.checkedOnFormatted }} umfasste eine Seite dieser
69
83
  Website.
@@ -63,6 +63,20 @@ It is based on a self-assessment carried out by {{ provider.legalName }}.
63
63
  It is based on an assessment carried out by a third party.
64
64
  {{/if}}
65
65
 
66
+ {{#if review.isSingle}}
67
+ One of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and AA was checked
68
+ manually.
69
+ {{/if}}
70
+ {{#if review.isPlural}}
71
+ {{ review.answered }} of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and
72
+ AA were checked manually.
73
+ {{/if}}
74
+ {{#if review.hasDate}}
75
+ The most recent of those manual checks was recorded on {{ review.checkedOnFormatted }}.
76
+ {{/if}}
77
+ {{#if hasReview}}
78
+
79
+ {{/if}}
66
80
  {{#if audit.isSinglePage}}
67
81
  The automated test run of {{ audit.checkedOnFormatted }} covered one page of this website.
68
82
  {{/if}}
@@ -68,6 +68,20 @@ Grundlage ist eine Selbstbewertung durch {{ provider.legalName }}.
68
68
  Grundlage ist eine Prüfung durch Dritte.
69
69
  {{/if}}
70
70
 
71
+ {{#if review.isSingle}}
72
+ Eines der {{ review.total }} Erfolgskriterien der WCAG 2.2 (Stufen A und AA) wurde manuell
73
+ geprüft.
74
+ {{/if}}
75
+ {{#if review.isPlural}}
76
+ {{ review.answered }} der {{ review.total }} Erfolgskriterien der WCAG 2.2 (Stufen A und AA)
77
+ wurden manuell geprüft.
78
+ {{/if}}
79
+ {{#if review.hasDate}}
80
+ Die jüngste dieser manuellen Prüfungen erfolgte am {{ review.checkedOnFormatted }}.
81
+ {{/if}}
82
+ {{#if hasReview}}
83
+
84
+ {{/if}}
71
85
  {{#if audit.isSinglePage}}
72
86
  Die automatisierte Prüfung vom {{ audit.checkedOnFormatted }} umfasste eine Seite dieser
73
87
  Website.
@@ -69,6 +69,20 @@ It is based on a self-assessment carried out by {{ provider.legalName }}.
69
69
  It is based on an assessment carried out by a third party.
70
70
  {{/if}}
71
71
 
72
+ {{#if review.isSingle}}
73
+ One of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and AA was checked
74
+ manually.
75
+ {{/if}}
76
+ {{#if review.isPlural}}
77
+ {{ review.answered }} of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and
78
+ AA were checked manually.
79
+ {{/if}}
80
+ {{#if review.hasDate}}
81
+ The most recent of those manual checks was recorded on {{ review.checkedOnFormatted }}.
82
+ {{/if}}
83
+ {{#if hasReview}}
84
+
85
+ {{/if}}
72
86
  {{#if audit.isSinglePage}}
73
87
  The automated test run of {{ audit.checkedOnFormatted }} covered one page of this website.
74
88
  {{/if}}
@@ -64,6 +64,20 @@ Grundlage ist eine Selbstbewertung durch {{ provider.legalName }}.
64
64
  Grundlage ist eine Prüfung durch Dritte.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ Eines der {{ review.total }} Erfolgskriterien der WCAG 2.2 (Stufen A und AA) wurde manuell
69
+ geprüft.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} der {{ review.total }} Erfolgskriterien der WCAG 2.2 (Stufen A und AA)
73
+ wurden manuell geprüft.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ Die jüngste dieser manuellen Prüfungen erfolgte am {{ review.checkedOnFormatted }}.
77
+ {{/if}}
78
+ {{#if hasReview}}
79
+
80
+ {{/if}}
67
81
  {{#if audit.isSinglePage}}
68
82
  Die automatisierte Prüfung vom {{ audit.checkedOnFormatted }} umfasste eine Seite dieser
69
83
  Website.
@@ -64,6 +64,20 @@ It is based on a self-assessment carried out by {{ provider.legalName }}.
64
64
  It is based on an assessment carried out by a third party.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ One of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and AA was checked
69
+ manually.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and
73
+ AA were checked manually.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ The most recent of those manual checks was recorded on {{ review.checkedOnFormatted }}.
77
+ {{/if}}
78
+ {{#if hasReview}}
79
+
80
+ {{/if}}
67
81
  {{#if audit.isSinglePage}}
68
82
  The automated test run of {{ audit.checkedOnFormatted }} covered one page of this website.
69
83
  {{/if}}
@@ -64,6 +64,20 @@ It is based on a self-assessment carried out by {{ provider.legalName }}.
64
64
  It is based on an assessment carried out by a third party.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ One of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and AA was checked
69
+ manually.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and
73
+ AA were checked manually.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ The most recent of those manual checks was recorded on {{ review.checkedOnFormatted }}.
77
+ {{/if}}
78
+ {{#if hasReview}}
79
+
80
+ {{/if}}
67
81
  {{#if audit.isSinglePage}}
68
82
  The automated test run of {{ audit.checkedOnFormatted }} covered one page of this website.
69
83
  {{/if}}
@@ -64,6 +64,21 @@ Se basa en una autoevaluación realizada por {{ provider.legalName }}.
64
64
  Se basa en una evaluación realizada por un tercero.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ Uno de los {{ review.total }} criterios de conformidad de las WCAG 2.2 (niveles A y AA) se
69
+ comprobó manualmente.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} de los {{ review.total }} criterios de conformidad de las WCAG 2.2
73
+ (niveles A y AA) se comprobaron manualmente.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ La más reciente de esas comprobaciones manuales se registró el
77
+ {{ review.checkedOnFormatted }}.
78
+ {{/if}}
79
+ {{#if hasReview}}
80
+
81
+ {{/if}}
67
82
  {{#if audit.isSinglePage}}
68
83
  El análisis automático del {{ audit.checkedOnFormatted }} abarcó una página de este sitio
69
84
  web.
@@ -64,6 +64,20 @@ It is based on a self-assessment carried out by {{ provider.legalName }}.
64
64
  It is based on an assessment carried out by a third party.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ One of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and AA was checked
69
+ manually.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and
73
+ AA were checked manually.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ The most recent of those manual checks was recorded on {{ review.checkedOnFormatted }}.
77
+ {{/if}}
78
+ {{#if hasReview}}
79
+
80
+ {{/if}}
67
81
  {{#if audit.isSinglePage}}
68
82
  The automated test run of {{ audit.checkedOnFormatted }} covered one page of this website.
69
83
  {{/if}}
@@ -64,6 +64,21 @@ Elle repose sur une auto-évaluation réalisée par {{ provider.legalName }}.
64
64
  Elle repose sur une évaluation réalisée par un tiers.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ Un des {{ review.total }} critères de succès des WCAG 2.2 (niveaux A et AA) a été vérifié
69
+ manuellement.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} des {{ review.total }} critères de succès des WCAG 2.2 (niveaux A et
73
+ AA) ont été vérifiés manuellement.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ La plus récente de ces vérifications manuelles a été effectuée le
77
+ {{ review.checkedOnFormatted }}.
78
+ {{/if}}
79
+ {{#if hasReview}}
80
+
81
+ {{/if}}
67
82
  {{#if audit.isSinglePage}}
68
83
  Le test automatisé du {{ audit.checkedOnFormatted }} a porté sur une page de ce site.
69
84
  {{/if}}
@@ -64,6 +64,20 @@ It is based on a self-assessment carried out by {{ provider.legalName }}.
64
64
  It is based on an assessment carried out by a third party.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ One of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and AA was checked
69
+ manually.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and
73
+ AA were checked manually.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ The most recent of those manual checks was recorded on {{ review.checkedOnFormatted }}.
77
+ {{/if}}
78
+ {{#if hasReview}}
79
+
80
+ {{/if}}
67
81
  {{#if audit.isSinglePage}}
68
82
  The automated test run of {{ audit.checkedOnFormatted }} covered one page of this website.
69
83
  {{/if}}
@@ -64,6 +64,21 @@ Si basa su un'autovalutazione svolta da {{ provider.legalName }}.
64
64
  Si basa su una valutazione svolta da terzi.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ Uno dei {{ review.total }} criteri di successo delle WCAG 2.2 (livelli A e AA) è stato
69
+ verificato manualmente.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} dei {{ review.total }} criteri di successo delle WCAG 2.2 (livelli A e
73
+ AA) sono stati verificati manualmente.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ La più recente di queste verifiche manuali è stata effettuata il
77
+ {{ review.checkedOnFormatted }}.
78
+ {{/if}}
79
+ {{#if hasReview}}
80
+
81
+ {{/if}}
67
82
  {{#if audit.isSinglePage}}
68
83
  Il test automatico del {{ audit.checkedOnFormatted }} ha riguardato una pagina di questo
69
84
  sito.
@@ -64,6 +64,20 @@ It is based on a self-assessment carried out by {{ provider.legalName }}.
64
64
  It is based on an assessment carried out by a third party.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ One of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and AA was checked
69
+ manually.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} of the {{ review.total }} success criteria in WCAG 2.2 at Levels A and
73
+ AA were checked manually.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ The most recent of those manual checks was recorded on {{ review.checkedOnFormatted }}.
77
+ {{/if}}
78
+ {{#if hasReview}}
79
+
80
+ {{/if}}
67
81
  {{#if audit.isSinglePage}}
68
82
  The automated test run of {{ audit.checkedOnFormatted }} covered one page of this website.
69
83
  {{/if}}
@@ -64,6 +64,21 @@ Zij berust op een zelfbeoordeling door {{ provider.legalName }}.
64
64
  Zij berust op een beoordeling door een derde partij.
65
65
  {{/if}}
66
66
 
67
+ {{#if review.isSingle}}
68
+ Eén van de {{ review.total }} succescriteria van WCAG 2.2 (niveaus A en AA) is handmatig
69
+ gecontroleerd.
70
+ {{/if}}
71
+ {{#if review.isPlural}}
72
+ {{ review.answered }} van de {{ review.total }} succescriteria van WCAG 2.2 (niveaus A en
73
+ AA) zijn handmatig gecontroleerd.
74
+ {{/if}}
75
+ {{#if review.hasDate}}
76
+ De meest recente van deze handmatige controles is uitgevoerd op
77
+ {{ review.checkedOnFormatted }}.
78
+ {{/if}}
79
+ {{#if hasReview}}
80
+
81
+ {{/if}}
67
82
  {{#if audit.isSinglePage}}
68
83
  De geautomatiseerde test van {{ audit.checkedOnFormatted }} betrof één pagina van deze
69
84
  website.
@@ -18,9 +18,21 @@ function escapeText(value) {
18
18
  function escapeAttribute(value) {
19
19
  return escapeText(value).replace(/"/g, "&quot;").replace(/'/g, "&#39;");
20
20
  }
21
+ /**
22
+ * The plurals this package's own output actually uses, where an `s` is wrong.
23
+ *
24
+ * Deliberately a short list rather than a pluralisation library: this is the
25
+ * vocabulary of a handful of report lines, and every entry here was added
26
+ * because something printed "2 entrys" or "4 criterions" at somebody.
27
+ */
28
+ const IRREGULAR = {
29
+ entry: "entries",
30
+ criterion: "criteria"
31
+ };
21
32
  /** `plural(1, 'page')` is `page`, `plural(2, 'page')` is `pages`. */
22
33
  function plural(value, noun) {
23
- return value === 1 ? noun : `${noun}s`;
34
+ if (value === 1) return noun;
35
+ return IRREGULAR[noun] ?? `${noun}s`;
24
36
  }
25
37
  /** `count(2, 'page')` is `2 pages`. */
26
38
  function count(value, noun) {
@@ -39,5 +51,13 @@ function collapse(html, max) {
39
51
  function standardsReference(successCriteria, enClauses) {
40
52
  return [...successCriteria.map((criterion) => `WCAG ${criterion}`), ...enClauses.map((clause) => `EN 301 549 ${clause}`)].join(", ");
41
53
  }
54
+ /**
55
+ * A date as the ISO day this package records everywhere it writes one: the day
56
+ * a baseline entry was accepted, and the day a criterion was reviewed. Always
57
+ * UTC, so two people on either side of a date line write the same file.
58
+ */
59
+ function isoDate(date) {
60
+ return date.toISOString().slice(0, 10);
61
+ }
42
62
  //#endregion
43
- export { plural as a, escapeText as i, count as n, standardsReference as o, escapeAttribute as r, collapse as t };
63
+ export { isoDate as a, escapeText as i, count as n, plural as o, escapeAttribute as r, standardsReference as s, collapse as t };
@@ -1,4 +1,4 @@
1
- import { n as IntegrationOptions, t as BuildAuditError } from "../run-CtcEUhbe.js";
1
+ import { n as IntegrationOptions, t as BuildAuditError } from "../run-BK2blxMI.js";
2
2
  //#region src/vite/index.d.ts
3
3
  interface EaaKitPluginOptions extends IntegrationOptions {
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { n as auditBuild, t as BuildAuditError } from "../run-C2nKFcb-.js";
1
+ import { n as auditBuild, t as BuildAuditError } from "../run-DrS0Komf.js";
2
2
  import path from "node:path";
3
3
  //#region src/vite/index.ts
4
4
  function eaaKit(options = {}) {
@@ -1,4 +1,4 @@
1
- import { n as IntegrationOptions, t as BuildAuditError } from "../run-CtcEUhbe.js";
1
+ import { n as IntegrationOptions, t as BuildAuditError } from "../run-BK2blxMI.js";
2
2
  //#region src/webpack/index.d.ts
3
3
  /** The part of a webpack compilation this reads. */
4
4
  interface CompilationLike {