eaa-kit 0.4.0 → 0.6.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.
- package/README.md +66 -11
- package/dist/astro/index.d.ts +1 -1
- package/dist/astro/index.js +1 -1
- package/dist/audit/runners/worker.js +5 -1
- package/dist/audit-DK2StT1_.js +2 -0
- package/dist/{audit-CPoZMXGM.js → audit-e_uixhPG.js} +123 -54
- package/dist/baseline-BscHfFSW.js +2 -0
- package/dist/{baseline-DB9CZGnV.js → baseline-D2qWmUC6.js} +40 -12
- package/dist/checklist-BtgkxMEa.js +44 -0
- package/dist/cli/index.js +153 -25
- package/dist/{collect-CFM8gEVv.js → collect-Cu1q9NTB.js} +34 -3
- package/dist/command-CZKp9Wi_.js +251 -0
- package/dist/{remediation-Dtowi2EC.js → completeness-Dwq3CPB3.js} +61 -43
- package/dist/{component-C3GL1Mnu.js → component-ChisoFyY.js} +1 -1
- package/dist/{component-DKd3EHOg.js → component-DcCn3BJS.js} +1 -1
- package/dist/coverage-7bQqWNfN.js +2 -0
- package/dist/{coverage-B4IBKMO8.js → coverage-BD2_CYns.js} +46 -8
- package/dist/{crawl-BiI1Lau_.js → crawl-BHkJmUkA.js} +119 -11
- package/dist/eleventy/index.d.ts +1 -1
- package/dist/eleventy/index.js +1 -1
- package/dist/fingerprint-BjYV_0F7.js +67 -0
- package/dist/{html-BGTO3ypW.js → html-Bmh7X_sM.js} +52 -30
- package/dist/{impact-DZt2oBCP.js → impact-luGCnN8F.js} +11 -1
- package/dist/index.d.ts +187 -5
- package/dist/index.js +3 -3
- package/dist/{init-DIWDE35F.js → init-BjKYttxc.js} +10 -4
- package/dist/{jsdom-DCpGSLfW.js → jsdom-CQar6OQS.js} +12 -4
- package/dist/jsdom-DMvU2h-f.js +3 -0
- package/dist/{json-QQuFIw1W.js → json-HJDgJp09.js} +1 -1
- package/dist/{json-DjEvy1nX.js → json-PNg6BeXp.js} +13 -18
- package/dist/load-Bc_xDGAh.js +2 -0
- package/dist/{load-5wRGLvub.js → load-vZdV_fD1.js} +137 -8
- package/dist/nuxt/index.d.ts +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/{playwright-BWniOain.js → playwright-C-miJP2b.js} +32 -7
- package/dist/{pool-BMevaLWD.js → pool-dkexq5xo.js} +52 -2
- package/dist/{render-DrvXRCEn.js → render-CtsqR0k-.js} +150 -11
- package/dist/{result-DoamKFsp.js → result-DfUru6y_.js} +60 -3
- package/dist/review-CdMK2GpQ.js +161 -0
- package/dist/review-DIbOTmOM.js +2 -0
- package/dist/{run-DB34BSOZ.js → run-D7hdVXLA.js} +1 -1
- package/dist/{run-BMASMmwO.d.ts → run-YiqyQA2b.d.ts} +17 -0
- package/dist/{sarif-SR3_lLYd.js → sarif-BKvq_AUm.js} +25 -14
- package/dist/{schema-is6CGX2D.js → schema-DJSF4K05.js} +15 -1
- package/dist/statement/templates/es.en.md +125 -0
- package/dist/statement/templates/es.es.md +127 -0
- package/dist/statement/templates/fr.en.md +128 -0
- package/dist/statement/templates/fr.fr.md +131 -0
- package/dist/statement/templates/it.en.md +127 -0
- package/dist/statement/templates/it.it.md +130 -0
- package/dist/statement/templates/nl.en.md +125 -0
- package/dist/statement/templates/nl.nl.md +127 -0
- package/dist/{text-CKKpzkYM.js → text-BF1LHMiV.js} +22 -2
- package/dist/vite/index.d.ts +1 -1
- package/dist/vite/index.js +1 -1
- package/dist/webpack/index.d.ts +1 -1
- package/dist/webpack/index.js +1 -1
- package/dist/worksheet-eUjwYLxC.js +63 -0
- package/package.json +7 -3
- package/dist/audit-CpXH2Mk8.js +0 -2
- package/dist/baseline-22Y1NWxM.js +0 -2
- package/dist/command-D8l_oYbV.js +0 -77
- package/dist/fingerprint-DRoneAjj.js +0 -20
- package/dist/jsdom-4IMzv0eE.js +0 -3
package/dist/index.d.ts
CHANGED
|
@@ -60,10 +60,17 @@ type DefaultedSchema<T> = Schema<T> & {
|
|
|
60
60
|
//#endregion
|
|
61
61
|
//#region src/config/define.d.ts
|
|
62
62
|
/** Countries with their own supervisory body and statute text. */
|
|
63
|
-
declare const COUNTRIES: readonly ['AT', 'DE', 'CH'];
|
|
63
|
+
declare const COUNTRIES: readonly ['AT', 'DE', 'CH', 'ES', 'FR', 'IT', 'NL'];
|
|
64
64
|
type Country = (typeof COUNTRIES)[number];
|
|
65
|
-
/**
|
|
66
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Languages a statement can be rendered in.
|
|
67
|
+
*
|
|
68
|
+
* Not every country has every one: a statement is a document under a particular
|
|
69
|
+
* legal regime, not a translation of a document under another, so each country
|
|
70
|
+
* has the language it is published in and English. `renderStatement` says which
|
|
71
|
+
* ones a country has when asked for one it does not.
|
|
72
|
+
*/
|
|
73
|
+
declare const STATEMENT_LOCALES: readonly ['de', 'en', 'es', 'fr', 'it', 'nl'];
|
|
67
74
|
type StatementLocale = (typeof STATEMENT_LOCALES)[number];
|
|
68
75
|
/**
|
|
69
76
|
* Wording follows the EU model statement: fully, partially, or not conformant
|
|
@@ -81,6 +88,65 @@ type AssessmentMethod = (typeof ASSESSMENT_METHODS)[number];
|
|
|
81
88
|
*/
|
|
82
89
|
declare const ISSUE_REASONS: readonly ['disproportionate-burden', 'out-of-scope', 'fix-planned'];
|
|
83
90
|
type IssueReason = (typeof ISSUE_REASONS)[number];
|
|
91
|
+
/**
|
|
92
|
+
* Defaults for `eaa-kit audit` and `eaa-kit baseline`, so a project says once
|
|
93
|
+
* what every invocation would otherwise repeat.
|
|
94
|
+
*
|
|
95
|
+
* Every field is optional and every one is a default: a flag actually typed on
|
|
96
|
+
* the command line wins, because the file is the project's usual answer and the
|
|
97
|
+
* flag is somebody asking for something else right now.
|
|
98
|
+
*
|
|
99
|
+
* `baseline` reads the subset that means the same thing to it. `output`,
|
|
100
|
+
* `format`, `failOn` and `baseline` are audit-only on purpose — a baseline
|
|
101
|
+
* written to the report's path would overwrite the report, and a threshold for
|
|
102
|
+
* failing a run means nothing to a command that records what it finds.
|
|
103
|
+
*/
|
|
104
|
+
declare const auditSchema: Schema<ObjectOf<{
|
|
105
|
+
/** Build directory. The positional argument wins over it. */
|
|
106
|
+
dir: OptionalSchema<string>;
|
|
107
|
+
include: OptionalSchema<string[]>;
|
|
108
|
+
exclude: OptionalSchema<string[]>;
|
|
109
|
+
/** Audit pages under their real site URL instead of file://. */
|
|
110
|
+
baseUrl: OptionalSchema<string>;
|
|
111
|
+
/** Audit a running site instead of a directory. */
|
|
112
|
+
url: OptionalSchema<string>;
|
|
113
|
+
/** Crawl a host that is not loopback. Off unless a project says otherwise. */
|
|
114
|
+
allowRemote: OptionalSchema<boolean>;
|
|
115
|
+
ignoreRobots: OptionalSchema<boolean>;
|
|
116
|
+
/** Where the site lists its pages, when that is not /sitemap.xml. */
|
|
117
|
+
sitemap: OptionalSchema<string>;
|
|
118
|
+
maxPages: OptionalSchema<number>;
|
|
119
|
+
/** 0 audits the entry page alone. */
|
|
120
|
+
maxDepth: OptionalSchema<number>;
|
|
121
|
+
/** Lowest impact that exits 1. */
|
|
122
|
+
failOn: OptionalSchema<"critical" | "minor" | "moderate" | "serious">;
|
|
123
|
+
format: OptionalSchema<"console" | "html" | "json" | "sarif">;
|
|
124
|
+
/** Write the report here instead of stdout. */
|
|
125
|
+
output: OptionalSchema<string>;
|
|
126
|
+
/** Audit in real Chromium. Needs the playwright peer. */
|
|
127
|
+
browser: OptionalSchema<boolean>;
|
|
128
|
+
/** Skip the rules the browserless engine cannot decide. No effect with `browser`. */
|
|
129
|
+
fast: OptionalSchema<boolean>;
|
|
130
|
+
concurrency: OptionalSchema<number>;
|
|
131
|
+
/** Path to a baseline; violations it accounts for do not fail the run. */
|
|
132
|
+
baseline: OptionalSchema<string>;
|
|
133
|
+
/** List every page and its result under the issues. */
|
|
134
|
+
perPage: OptionalSchema<boolean>;
|
|
135
|
+
/** Print the manual check for each rule the engine could not evaluate. */
|
|
136
|
+
manual: OptionalSchema<boolean>;
|
|
137
|
+
/** List every WCAG 2.2 A/AA criterion and what the run reached on it. */
|
|
138
|
+
coverage: OptionalSchema<boolean>;
|
|
139
|
+
/** Path to a review record: what a person checked, for the criteria no engine reaches. */
|
|
140
|
+
review: OptionalSchema<string>;
|
|
141
|
+
/** Days after which a recorded review stops counting. */
|
|
142
|
+
reviewMaxAge: OptionalSchema<number>;
|
|
143
|
+
/**
|
|
144
|
+
* False is `--no-build`: never run the project's build or start its server to
|
|
145
|
+
* find something to audit. Written in the positive because that is the state
|
|
146
|
+
* being described, and because a config file has no flags to negate.
|
|
147
|
+
*/
|
|
148
|
+
build: OptionalSchema<boolean>;
|
|
149
|
+
}>>;
|
|
84
150
|
declare const configSchema: Schema<ObjectOf<{
|
|
85
151
|
site: Schema<ObjectOf<{
|
|
86
152
|
name: Schema<string>;
|
|
@@ -132,7 +198,54 @@ declare const configSchema: Schema<ObjectOf<{
|
|
|
132
198
|
}>>;
|
|
133
199
|
enforcement: Schema<ObjectOf<{
|
|
134
200
|
/** Drives which supervisory body and statute the template names. */
|
|
135
|
-
country: Schema<"AT" | "CH" | "DE">;
|
|
201
|
+
country: Schema<"AT" | "CH" | "DE" | "ES" | "FR" | "IT" | "NL">;
|
|
202
|
+
}>>;
|
|
203
|
+
/** Defaults for the audit commands. Nothing here reaches the statement. */
|
|
204
|
+
audit: OptionalSchema<ObjectOf<{
|
|
205
|
+
/** Build directory. The positional argument wins over it. */
|
|
206
|
+
dir: OptionalSchema<string>;
|
|
207
|
+
include: OptionalSchema<string[]>;
|
|
208
|
+
exclude: OptionalSchema<string[]>;
|
|
209
|
+
/** Audit pages under their real site URL instead of file://. */
|
|
210
|
+
baseUrl: OptionalSchema<string>;
|
|
211
|
+
/** Audit a running site instead of a directory. */
|
|
212
|
+
url: OptionalSchema<string>;
|
|
213
|
+
/** Crawl a host that is not loopback. Off unless a project says otherwise. */
|
|
214
|
+
allowRemote: OptionalSchema<boolean>;
|
|
215
|
+
ignoreRobots: OptionalSchema<boolean>;
|
|
216
|
+
/** Where the site lists its pages, when that is not /sitemap.xml. */
|
|
217
|
+
sitemap: OptionalSchema<string>;
|
|
218
|
+
maxPages: OptionalSchema<number>;
|
|
219
|
+
/** 0 audits the entry page alone. */
|
|
220
|
+
maxDepth: OptionalSchema<number>;
|
|
221
|
+
/** Lowest impact that exits 1. */
|
|
222
|
+
failOn: OptionalSchema<"critical" | "minor" | "moderate" | "serious">;
|
|
223
|
+
format: OptionalSchema<"console" | "html" | "json" | "sarif">;
|
|
224
|
+
/** Write the report here instead of stdout. */
|
|
225
|
+
output: OptionalSchema<string>;
|
|
226
|
+
/** Audit in real Chromium. Needs the playwright peer. */
|
|
227
|
+
browser: OptionalSchema<boolean>;
|
|
228
|
+
/** Skip the rules the browserless engine cannot decide. No effect with `browser`. */
|
|
229
|
+
fast: OptionalSchema<boolean>;
|
|
230
|
+
concurrency: OptionalSchema<number>;
|
|
231
|
+
/** Path to a baseline; violations it accounts for do not fail the run. */
|
|
232
|
+
baseline: OptionalSchema<string>;
|
|
233
|
+
/** List every page and its result under the issues. */
|
|
234
|
+
perPage: OptionalSchema<boolean>;
|
|
235
|
+
/** Print the manual check for each rule the engine could not evaluate. */
|
|
236
|
+
manual: OptionalSchema<boolean>;
|
|
237
|
+
/** List every WCAG 2.2 A/AA criterion and what the run reached on it. */
|
|
238
|
+
coverage: OptionalSchema<boolean>;
|
|
239
|
+
/** Path to a review record: what a person checked, for the criteria no engine reaches. */
|
|
240
|
+
review: OptionalSchema<string>;
|
|
241
|
+
/** Days after which a recorded review stops counting. */
|
|
242
|
+
reviewMaxAge: OptionalSchema<number>;
|
|
243
|
+
/**
|
|
244
|
+
* False is `--no-build`: never run the project's build or start its server to
|
|
245
|
+
* find something to audit. Written in the positive because that is the state
|
|
246
|
+
* being described, and because a config file has no flags to negate.
|
|
247
|
+
*/
|
|
248
|
+
build: OptionalSchema<boolean>;
|
|
136
249
|
}>>;
|
|
137
250
|
}>>;
|
|
138
251
|
/**
|
|
@@ -167,6 +280,7 @@ interface EaaConfigInput {
|
|
|
167
280
|
enforcement: {
|
|
168
281
|
country: Country;
|
|
169
282
|
};
|
|
283
|
+
audit?: AuditConfig;
|
|
170
284
|
}
|
|
171
285
|
/** One barrier, as written in a config file. */
|
|
172
286
|
interface KnownIssueInput {
|
|
@@ -178,6 +292,15 @@ interface KnownIssueInput {
|
|
|
178
292
|
}
|
|
179
293
|
type EaaConfig = Infer<typeof configSchema>;
|
|
180
294
|
type KnownIssue = EaaConfig['compliance']['knownIssues'][number];
|
|
295
|
+
/**
|
|
296
|
+
* The `audit` block, as written and as parsed — every field is optional.
|
|
297
|
+
*
|
|
298
|
+
* `undefined` is mapped out of the value types rather than left in them:
|
|
299
|
+
* `s.object` never writes a key it did not parse, so an absent field is an
|
|
300
|
+
* absent key, and the commands spread this over their own options where a
|
|
301
|
+
* present-but-undefined key would overwrite a real value.
|
|
302
|
+
*/
|
|
303
|
+
type AuditConfig = { [K in keyof Infer<typeof auditSchema>]?: Exclude<Infer<typeof auditSchema>[K], undefined>; };
|
|
181
304
|
/**
|
|
182
305
|
* Identity function that gives `eaa.config.ts` its types. Deliberately does not
|
|
183
306
|
* validate: a config file is loaded and checked in one place, so that an error
|
|
@@ -234,6 +357,24 @@ declare class StatementError extends Error {
|
|
|
234
357
|
readonly name = "StatementError";
|
|
235
358
|
}
|
|
236
359
|
//#endregion
|
|
360
|
+
//#region src/audit/review.d.ts
|
|
361
|
+
declare const reviewSchema: Schema<ObjectOf<{
|
|
362
|
+
schemaVersion: Schema<number>;
|
|
363
|
+
/** Who carried out the review, for the record as a whole. */
|
|
364
|
+
reviewedBy: OptionalSchema<string>;
|
|
365
|
+
/** Keyed by success criterion number, e.g. '1.2.1'. */
|
|
366
|
+
criteria: DefaultedSchema<Record<string, ObjectOf<{
|
|
367
|
+
result: DefaultedSchema<"met" | "not-applicable" | "not-met" | "unreviewed">;
|
|
368
|
+
/** ISO date the check was done. Without it the entry cannot be aged. */
|
|
369
|
+
reviewedOn: OptionalSchema<string>;
|
|
370
|
+
/** Who did it, when that is not the person named on the record. */
|
|
371
|
+
reviewedBy: OptionalSchema<string>;
|
|
372
|
+
/** What was checked and what was found. Free text, for whoever reads it. */
|
|
373
|
+
note: OptionalSchema<string>;
|
|
374
|
+
}>>>;
|
|
375
|
+
}>>;
|
|
376
|
+
type ReviewRecord = Infer<typeof reviewSchema>;
|
|
377
|
+
//#endregion
|
|
237
378
|
//#region src/statement/findings.d.ts
|
|
238
379
|
/** One rule that failed, folded across every page it failed on. */
|
|
239
380
|
interface AuditFinding {
|
|
@@ -279,6 +420,47 @@ declare function summariseAuditReport(value: unknown, source?: string): AuditSum
|
|
|
279
420
|
/** Read and summarise a report written by `eaa-kit audit --format json`. */
|
|
280
421
|
declare function readAuditReport(file: string, cwd?: string): Promise<AuditSummary>;
|
|
281
422
|
//#endregion
|
|
423
|
+
//#region src/statement/evidence.d.ts
|
|
424
|
+
/**
|
|
425
|
+
* Whether the statement's claim survives contact with the evidence beside it.
|
|
426
|
+
*
|
|
427
|
+
* The README has said since 0.1 that "a statement claiming full conformance for
|
|
428
|
+
* a site that is not conformant is worse than no statement at all", and until
|
|
429
|
+
* now the tool did nothing about it: `compliance.status` came out of the config
|
|
430
|
+
* file, the audit report came in through `--audit`, and nothing ever put the
|
|
431
|
+
* two in the same room. A run could print a document claiming full conformance
|
|
432
|
+
* directly above the list of barriers that disproves it.
|
|
433
|
+
*
|
|
434
|
+
* This is the check that was missing. It is deliberately narrow: it does not
|
|
435
|
+
* decide whether a site is accessible, and it cannot — most of WCAG is not
|
|
436
|
+
* automatable and the whole tool is built around saying so. It refuses only
|
|
437
|
+
* claims the evidence in hand already contradicts, and warns where a document
|
|
438
|
+
* is citing evidence that no longer describes the site.
|
|
439
|
+
*
|
|
440
|
+
* Nothing here needs an audit report. Given none, only the dates are checked,
|
|
441
|
+
* and a project that has never run one gets exactly the statement it always
|
|
442
|
+
* got — the tool cannot audit what it was not shown.
|
|
443
|
+
*/
|
|
444
|
+
/** How much a problem matters. `refuses` stops the statement being written. */
|
|
445
|
+
type EvidenceSeverity = 'refuses' | 'warns';
|
|
446
|
+
interface EvidenceProblem {
|
|
447
|
+
severity: EvidenceSeverity;
|
|
448
|
+
/** One sentence stating the contradiction, and one naming the fix. */
|
|
449
|
+
message: string;
|
|
450
|
+
}
|
|
451
|
+
interface EvidenceInput {
|
|
452
|
+
config: EaaConfig;
|
|
453
|
+
/** From `--audit`. Without it only the dates can be checked. */
|
|
454
|
+
audit?: AuditSummary;
|
|
455
|
+
/** From `--review`. Read for this check alone; it does not reach the text. */
|
|
456
|
+
review?: ReviewRecord;
|
|
457
|
+
/** Injectable so the ageing checks can be tested without waiting. */
|
|
458
|
+
today?: Date;
|
|
459
|
+
}
|
|
460
|
+
declare function checkStatementEvidence(input: EvidenceInput): EvidenceProblem[];
|
|
461
|
+
/** Whether any problem is bad enough to stop the document being written. */
|
|
462
|
+
declare function refuses(problems: readonly EvidenceProblem[]): boolean;
|
|
463
|
+
//#endregion
|
|
282
464
|
//#region src/statement/html.d.ts
|
|
283
465
|
/**
|
|
284
466
|
* Markdown-to-HTML for exactly the subset the statement templates emit, and
|
|
@@ -351,4 +533,4 @@ interface RenderedStatement {
|
|
|
351
533
|
*/
|
|
352
534
|
declare function renderStatement(config: EaaConfig, options?: RenderStatementOptions): Promise<RenderedStatement>;
|
|
353
535
|
//#endregion
|
|
354
|
-
export { ASSESSMENT_METHODS, type AssessmentMethod, type AuditFinding, type AuditSummary, COMPLIANCE_STATUSES, CONFIG_FILENAMES, COUNTRIES, type ComplianceStatus, ConfigError, type Country, type EaaConfig, type EaaConfigInput, type HtmlDocumentOptions, ISSUE_REASONS, type IssueReason, type KnownIssue, type LoadConfigOptions, type LoadedConfig, type RenderStatementOptions, type RenderedStatement, STATEMENT_LOCALES, StatementError, type StatementLocale, configSchema, defineConfig, findConfigFile, loadConfig, parseConfig, readAuditReport, renderStatement, summariseAuditReport, toHtmlBody, toHtmlDocument };
|
|
536
|
+
export { ASSESSMENT_METHODS, type AssessmentMethod, type AuditFinding, type AuditSummary, COMPLIANCE_STATUSES, CONFIG_FILENAMES, COUNTRIES, type ComplianceStatus, ConfigError, type Country, type EaaConfig, type EaaConfigInput, type EvidenceInput, type EvidenceProblem, type EvidenceSeverity, type HtmlDocumentOptions, ISSUE_REASONS, type IssueReason, type KnownIssue, type LoadConfigOptions, type LoadedConfig, type RenderStatementOptions, type RenderedStatement, STATEMENT_LOCALES, StatementError, type StatementLocale, checkStatementEvidence, configSchema, defineConfig, findConfigFile, loadConfig, parseConfig, readAuditReport, refuses, renderStatement, summariseAuditReport, toHtmlBody, toHtmlDocument };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { a as summariseAuditReport, i as readAuditReport, n as toHtmlBody, o as
|
|
3
|
-
export { ASSESSMENT_METHODS, COMPLIANCE_STATUSES, CONFIG_FILENAMES, COUNTRIES, ConfigError, ISSUE_REASONS, STATEMENT_LOCALES, StatementError, configSchema, defineConfig, findConfigFile, loadConfig, parseConfig, readAuditReport, renderStatement, summariseAuditReport, toHtmlBody, toHtmlDocument };
|
|
1
|
+
import { a as ASSESSMENT_METHODS, c as ConfigError, d as configSchema, f as defineConfig, i as loadConfig, l as ISSUE_REASONS, n as findConfigFile, o as COMPLIANCE_STATUSES, p as parseConfig, s as COUNTRIES, t as CONFIG_FILENAMES, u as STATEMENT_LOCALES } from "./load-vZdV_fD1.js";
|
|
2
|
+
import { a as summariseAuditReport, c as StatementError, i as readAuditReport, n as toHtmlBody, o as checkStatementEvidence, r as toHtmlDocument, s as refuses, t as renderStatement } from "./render-CtsqR0k-.js";
|
|
3
|
+
export { ASSESSMENT_METHODS, COMPLIANCE_STATUSES, CONFIG_FILENAMES, COUNTRIES, ConfigError, ISSUE_REASONS, STATEMENT_LOCALES, StatementError, checkStatementEvidence, configSchema, defineConfig, findConfigFile, loadConfig, parseConfig, readAuditReport, refuses, renderStatement, summariseAuditReport, toHtmlBody, toHtmlDocument };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as DEFAULT_FAIL_ON } from "./impact-luGCnN8F.js";
|
|
2
|
+
import { s as COUNTRIES, t as CONFIG_FILENAMES } from "./load-vZdV_fD1.js";
|
|
2
3
|
import { t as exists } from "./fs-BmPtmFke.js";
|
|
3
|
-
import {
|
|
4
|
+
import { l as warn, o as fail, s as note } from "./command-CZKp9Wi_.js";
|
|
4
5
|
import { readFile, writeFile } from "node:fs/promises";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import pc from "picocolors";
|
|
@@ -9,7 +10,11 @@ import { createInterface } from "node:readline/promises";
|
|
|
9
10
|
const COUNTRY_LOCALES = {
|
|
10
11
|
AT: "de-AT",
|
|
11
12
|
DE: "de-DE",
|
|
12
|
-
CH: "de-CH"
|
|
13
|
+
CH: "de-CH",
|
|
14
|
+
ES: "es-ES",
|
|
15
|
+
FR: "fr-FR",
|
|
16
|
+
IT: "it-IT",
|
|
17
|
+
NL: "nl-NL"
|
|
13
18
|
};
|
|
14
19
|
/**
|
|
15
20
|
* Everything the project already says about itself.
|
|
@@ -83,7 +88,8 @@ async function runInitCommand(options = {}) {
|
|
|
83
88
|
assessmentMethod: "self-assessment",
|
|
84
89
|
knownIssues: []
|
|
85
90
|
},
|
|
86
|
-
enforcement: { country }
|
|
91
|
+
enforcement: { country },
|
|
92
|
+
audit: { failOn: DEFAULT_FAIL_ON }
|
|
87
93
|
};
|
|
88
94
|
try {
|
|
89
95
|
await writeFile(target, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as failedPage, i as blindRulesInScope, l as runOptions, n as DEFAULT_TAGS, s as pageUrl, t as DEFAULT_PAGE_TIMEOUT_MS, u as shapeResults } from "./result-DfUru6y_.js";
|
|
2
2
|
import axe from "axe-core";
|
|
3
3
|
import { Script } from "node:vm";
|
|
4
4
|
import { JSDOM, VirtualConsole } from "jsdom";
|
|
5
5
|
//#region src/audit/runners/jsdom.ts
|
|
6
|
-
/**
|
|
7
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Per-page ceiling.
|
|
8
|
+
*
|
|
9
|
+
* A soft one, and the limit is worth stating: this races axe-core against a
|
|
10
|
+
* timer, so it only fires where the work yields to the event loop. Neither
|
|
11
|
+
* jsdom's parse nor axe-core's walk of the tree does, so a document pathological
|
|
12
|
+
* enough to hold the thread runs past this unimpeded. The hard ceiling is the
|
|
13
|
+
* worker pool's, which terminates the thread; see the note on `runWorkers`.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_TIMEOUT_MS = DEFAULT_PAGE_TIMEOUT_MS;
|
|
8
16
|
/**
|
|
9
17
|
* Audit collected pages with axe-core inside jsdom.
|
|
10
18
|
*
|
|
@@ -32,7 +40,7 @@ async function auditPage(page, options = {}) {
|
|
|
32
40
|
dom = createDom(page.html, url);
|
|
33
41
|
injectAxe(dom);
|
|
34
42
|
const { axe: pageAxe } = dom.window;
|
|
35
|
-
const results = await withTimeout(pageAxe.run(dom.window.document, runOptions(tags)), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
43
|
+
const results = await withTimeout(pageAxe.run(dom.window.document, runOptions(tags, { skipBlindRules: options.fast === true })), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
36
44
|
return shapeResults(results, {
|
|
37
45
|
...identity,
|
|
38
46
|
durationMs: Date.now() - startedAt,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { r as serialiseJsonReport, t as buildJsonReport } from "./json-
|
|
1
|
+
import { r as serialiseJsonReport, t as buildJsonReport } from "./json-PNg6BeXp.js";
|
|
2
2
|
export { buildJsonReport, serialiseJsonReport };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as impactLabel, i as countAtOrAbove, s as isImpactLevel } from "./impact-luGCnN8F.js";
|
|
2
2
|
import { t as TOOL_VERSION } from "./version-B3v4rNoG.js";
|
|
3
|
-
import { t as elementFingerprint } from "./fingerprint-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { t as elementFingerprint } from "./fingerprint-BjYV_0F7.js";
|
|
4
|
+
import { c as runEngine, f as uniqueRuleOutcomes } from "./result-DfUru6y_.js";
|
|
5
|
+
import { n as buildCoverage } from "./coverage-BD2_CYns.js";
|
|
6
6
|
import axe from "axe-core";
|
|
7
7
|
/**
|
|
8
8
|
* Build the machine-readable report.
|
|
@@ -17,14 +17,14 @@ import axe from "axe-core";
|
|
|
17
17
|
function buildJsonReport(audits, options) {
|
|
18
18
|
const generatedAt = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
19
19
|
return {
|
|
20
|
-
schemaVersion:
|
|
20
|
+
schemaVersion: 2,
|
|
21
21
|
tool: {
|
|
22
22
|
name: "eaa-kit",
|
|
23
23
|
version: TOOL_VERSION,
|
|
24
24
|
axeCore: axe.version
|
|
25
25
|
},
|
|
26
26
|
generatedAt,
|
|
27
|
-
engine: audits
|
|
27
|
+
engine: runEngine(audits),
|
|
28
28
|
target: {
|
|
29
29
|
source: options.directory,
|
|
30
30
|
kind: options.sourceKind ?? "directory",
|
|
@@ -33,24 +33,19 @@ function buildJsonReport(audits, options) {
|
|
|
33
33
|
},
|
|
34
34
|
summary: buildSummary(audits, options.failOn),
|
|
35
35
|
completeness: options.completeness,
|
|
36
|
-
coverage: buildCoverage(audits),
|
|
36
|
+
coverage: buildCoverage(audits, void 0, options.review),
|
|
37
37
|
rules: buildRuleIndex(audits),
|
|
38
38
|
pages: audits.map(toJsonPage)
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
/** Every rule mentioned by any page, keyed by id and sorted for stable diffs. */
|
|
42
42
|
function buildRuleIndex(audits) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
successCriteria: outcome.successCriteria,
|
|
50
|
-
en301549: outcome.enClauses
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
return Object.fromEntries([...index].sort(([a], [b]) => a.localeCompare(b)));
|
|
43
|
+
return Object.fromEntries(uniqueRuleOutcomes(audits).map((outcome) => [outcome.ruleId, {
|
|
44
|
+
help: outcome.help,
|
|
45
|
+
helpUrl: outcome.helpUrl,
|
|
46
|
+
successCriteria: outcome.successCriteria,
|
|
47
|
+
en301549: outcome.enClauses
|
|
48
|
+
}]));
|
|
54
49
|
}
|
|
55
50
|
/** Serialised form written to stdout or to --output, with a trailing newline. */
|
|
56
51
|
function serialiseJsonReport(report) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as IMPACT_LEVELS } from "./impact-luGCnN8F.js";
|
|
2
|
+
import { _ as union, a as integer, d as optional, f as pipe, g as transform, h as string, i as enumeration, m as safeParse, n as boolean, o as isoDate, r as email, t as array, u as object, v as url, y as withDefault } from "./schema-DJSF4K05.js";
|
|
2
3
|
import { r as isFile } from "./fs-BmPtmFke.js";
|
|
3
4
|
import { readFile } from "node:fs/promises";
|
|
4
5
|
import path from "node:path";
|
|
@@ -8,10 +9,28 @@ import { pathToFileURL } from "node:url";
|
|
|
8
9
|
const COUNTRIES = [
|
|
9
10
|
"AT",
|
|
10
11
|
"DE",
|
|
11
|
-
"CH"
|
|
12
|
+
"CH",
|
|
13
|
+
"ES",
|
|
14
|
+
"FR",
|
|
15
|
+
"IT",
|
|
16
|
+
"NL"
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Languages a statement can be rendered in.
|
|
20
|
+
*
|
|
21
|
+
* Not every country has every one: a statement is a document under a particular
|
|
22
|
+
* legal regime, not a translation of a document under another, so each country
|
|
23
|
+
* has the language it is published in and English. `renderStatement` says which
|
|
24
|
+
* ones a country has when asked for one it does not.
|
|
25
|
+
*/
|
|
26
|
+
const STATEMENT_LOCALES = [
|
|
27
|
+
"de",
|
|
28
|
+
"en",
|
|
29
|
+
"es",
|
|
30
|
+
"fr",
|
|
31
|
+
"it",
|
|
32
|
+
"nl"
|
|
12
33
|
];
|
|
13
|
-
/** Languages a statement can be rendered in. */
|
|
14
|
-
const STATEMENT_LOCALES = ["de", "en"];
|
|
15
34
|
/**
|
|
16
35
|
* Wording follows the EU model statement: fully, partially, or not conformant
|
|
17
36
|
* with the standard. "partially-compliant" is the honest answer for most sites
|
|
@@ -50,6 +69,70 @@ const knownIssueObject = object({
|
|
|
50
69
|
* rather than a union that callers have to narrow before reading `remedyBy`.
|
|
51
70
|
*/
|
|
52
71
|
const knownIssueSchema = union([pipe(transform(string({ min: 1 }), (description) => ({ description })), knownIssueObject), knownIssueObject], "expected a description, or an object with one");
|
|
72
|
+
/**
|
|
73
|
+
* Defaults for `eaa-kit audit` and `eaa-kit baseline`, so a project says once
|
|
74
|
+
* what every invocation would otherwise repeat.
|
|
75
|
+
*
|
|
76
|
+
* Every field is optional and every one is a default: a flag actually typed on
|
|
77
|
+
* the command line wins, because the file is the project's usual answer and the
|
|
78
|
+
* flag is somebody asking for something else right now.
|
|
79
|
+
*
|
|
80
|
+
* `baseline` reads the subset that means the same thing to it. `output`,
|
|
81
|
+
* `format`, `failOn` and `baseline` are audit-only on purpose — a baseline
|
|
82
|
+
* written to the report's path would overwrite the report, and a threshold for
|
|
83
|
+
* failing a run means nothing to a command that records what it finds.
|
|
84
|
+
*/
|
|
85
|
+
const auditSchema = object({
|
|
86
|
+
/** Build directory. The positional argument wins over it. */
|
|
87
|
+
dir: optional(string({ min: 1 })),
|
|
88
|
+
include: optional(array(string({ min: 1 }))),
|
|
89
|
+
exclude: optional(array(string({ min: 1 }))),
|
|
90
|
+
/** Audit pages under their real site URL instead of file://. */
|
|
91
|
+
baseUrl: optional(url()),
|
|
92
|
+
/** Audit a running site instead of a directory. */
|
|
93
|
+
url: optional(url()),
|
|
94
|
+
/** Crawl a host that is not loopback. Off unless a project says otherwise. */
|
|
95
|
+
allowRemote: optional(boolean()),
|
|
96
|
+
ignoreRobots: optional(boolean()),
|
|
97
|
+
/** Where the site lists its pages, when that is not /sitemap.xml. */
|
|
98
|
+
sitemap: optional(string({ min: 1 })),
|
|
99
|
+
maxPages: optional(integer({ min: 1 })),
|
|
100
|
+
/** 0 audits the entry page alone. */
|
|
101
|
+
maxDepth: optional(integer({ min: 0 })),
|
|
102
|
+
/** Lowest impact that exits 1. */
|
|
103
|
+
failOn: optional(enumeration(IMPACT_LEVELS)),
|
|
104
|
+
format: optional(enumeration([
|
|
105
|
+
"console",
|
|
106
|
+
"json",
|
|
107
|
+
"sarif",
|
|
108
|
+
"html"
|
|
109
|
+
])),
|
|
110
|
+
/** Write the report here instead of stdout. */
|
|
111
|
+
output: optional(string({ min: 1 })),
|
|
112
|
+
/** Audit in real Chromium. Needs the playwright peer. */
|
|
113
|
+
browser: optional(boolean()),
|
|
114
|
+
/** Skip the rules the browserless engine cannot decide. No effect with `browser`. */
|
|
115
|
+
fast: optional(boolean()),
|
|
116
|
+
concurrency: optional(integer({ min: 1 })),
|
|
117
|
+
/** Path to a baseline; violations it accounts for do not fail the run. */
|
|
118
|
+
baseline: optional(string({ min: 1 })),
|
|
119
|
+
/** List every page and its result under the issues. */
|
|
120
|
+
perPage: optional(boolean()),
|
|
121
|
+
/** Print the manual check for each rule the engine could not evaluate. */
|
|
122
|
+
manual: optional(boolean()),
|
|
123
|
+
/** List every WCAG 2.2 A/AA criterion and what the run reached on it. */
|
|
124
|
+
coverage: optional(boolean()),
|
|
125
|
+
/** Path to a review record: what a person checked, for the criteria no engine reaches. */
|
|
126
|
+
review: optional(string({ min: 1 })),
|
|
127
|
+
/** Days after which a recorded review stops counting. */
|
|
128
|
+
reviewMaxAge: optional(integer({ min: 0 })),
|
|
129
|
+
/**
|
|
130
|
+
* False is `--no-build`: never run the project's build or start its server to
|
|
131
|
+
* find something to audit. Written in the positive because that is the state
|
|
132
|
+
* being described, and because a config file has no flags to negate.
|
|
133
|
+
*/
|
|
134
|
+
build: optional(boolean())
|
|
135
|
+
});
|
|
53
136
|
const configSchema = object({
|
|
54
137
|
site: object({
|
|
55
138
|
name: string({ min: 1 }),
|
|
@@ -91,9 +174,20 @@ const configSchema = object({
|
|
|
91
174
|
}),
|
|
92
175
|
enforcement: object({
|
|
93
176
|
/** Drives which supervisory body and statute the template names. */
|
|
94
|
-
country: enumeration(COUNTRIES) })
|
|
177
|
+
country: enumeration(COUNTRIES) }),
|
|
178
|
+
/** Defaults for the audit commands. Nothing here reaches the statement. */
|
|
179
|
+
audit: optional(auditSchema)
|
|
95
180
|
});
|
|
96
181
|
/**
|
|
182
|
+
* The `audit` block on its own.
|
|
183
|
+
*
|
|
184
|
+
* A project that only wants audit defaults should not have to write a complete
|
|
185
|
+
* statement config to get them, and `s.object` drops the keys it does not know,
|
|
186
|
+
* so the same file satisfies both readers: `statement` demands the whole
|
|
187
|
+
* document, `audit` reads this and ignores the rest.
|
|
188
|
+
*/
|
|
189
|
+
const auditConfigSchema = object({ audit: optional(auditSchema) });
|
|
190
|
+
/**
|
|
97
191
|
* Identity function that gives `eaa.config.ts` its types. Deliberately does not
|
|
98
192
|
* validate: a config file is loaded and checked in one place, so that an error
|
|
99
193
|
* points at the file rather than at wherever the module happened to be
|
|
@@ -112,7 +206,20 @@ var ConfigError = class extends Error {
|
|
|
112
206
|
};
|
|
113
207
|
/** Validate an already-loaded config object. */
|
|
114
208
|
function parseConfig(value, source = "config") {
|
|
115
|
-
|
|
209
|
+
return parse(configSchema, value, source);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Read only the `audit` block, ignoring whatever else the file holds.
|
|
213
|
+
*
|
|
214
|
+
* Returns undefined where there is no block, which is the common case: most
|
|
215
|
+
* config files exist for the statement alone, and finding one is not a reason
|
|
216
|
+
* to change how an audit runs.
|
|
217
|
+
*/
|
|
218
|
+
function parseAuditConfig(value, source = "config") {
|
|
219
|
+
return parse(auditConfigSchema, value, source).audit;
|
|
220
|
+
}
|
|
221
|
+
function parse(schema, value, source) {
|
|
222
|
+
const result = safeParse(schema, value);
|
|
116
223
|
if (result.success) return result.data;
|
|
117
224
|
const issues = result.error.issues.map((issue) => {
|
|
118
225
|
const path = issue.path.join(".");
|
|
@@ -145,10 +252,32 @@ async function loadConfig(options = {}) {
|
|
|
145
252
|
if (!file) throw new ConfigError(`No config file found in ${cwd} or its parent directories`, CONFIG_FILENAMES.map((name) => `looked for ${name}`));
|
|
146
253
|
if (!await isFile(file)) throw new ConfigError(`Config file not found: ${file}`);
|
|
147
254
|
return {
|
|
148
|
-
config: parseConfig(
|
|
255
|
+
config: parseConfig(await readConfigFile(file), path.basename(file)),
|
|
256
|
+
path: file
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Find the config file and read its `audit` block, for the commands that take
|
|
261
|
+
* defaults from it.
|
|
262
|
+
*
|
|
263
|
+
* Returns undefined when there is no config file at all. That is not an error
|
|
264
|
+
* here as it is for `statement`: `eaa-kit audit` has always run against a
|
|
265
|
+
* project that has never heard of a config file, and it must keep doing so. An
|
|
266
|
+
* explicit path that is not there is still an error, because somebody named it.
|
|
267
|
+
*/
|
|
268
|
+
async function loadAuditConfig(options = {}) {
|
|
269
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
270
|
+
const file = options.path ? path.resolve(cwd, options.path) : await findConfigFile(cwd);
|
|
271
|
+
if (!file) return void 0;
|
|
272
|
+
if (!await isFile(file)) throw new ConfigError(`Config file not found: ${file}`);
|
|
273
|
+
return {
|
|
274
|
+
audit: parseAuditConfig(await readConfigFile(file), path.basename(file)),
|
|
149
275
|
path: file
|
|
150
276
|
};
|
|
151
277
|
}
|
|
278
|
+
function readConfigFile(file) {
|
|
279
|
+
return file.endsWith(".json") ? importJson(file) : importModule(file);
|
|
280
|
+
}
|
|
152
281
|
/** Walks up from `cwd`, so the CLI works from a subdirectory of the project. */
|
|
153
282
|
async function findConfigFile(cwd) {
|
|
154
283
|
let directory = path.resolve(cwd);
|
|
@@ -183,4 +312,4 @@ async function importModule(file) {
|
|
|
183
312
|
return module.default;
|
|
184
313
|
}
|
|
185
314
|
//#endregion
|
|
186
|
-
export {
|
|
315
|
+
export { ASSESSMENT_METHODS as a, ConfigError as c, configSchema as d, defineConfig as f, loadConfig as i, ISSUE_REASONS as l, findConfigFile as n, COMPLIANCE_STATUSES as o, parseConfig as p, loadAuditConfig as r, COUNTRIES as s, CONFIG_FILENAMES as t, STATEMENT_LOCALES as u };
|
package/dist/nuxt/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as IntegrationOptions, t as BuildAuditError } from "../run-
|
|
1
|
+
import { n as IntegrationOptions, t as BuildAuditError } from "../run-YiqyQA2b.js";
|
|
2
2
|
//#region src/nuxt/index.d.ts
|
|
3
3
|
/** The part of the Nitro instance this reads, handed over by `nitro:init`. */
|
|
4
4
|
interface NitroLike {
|
package/dist/nuxt/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as auditBuild, r as stderrLogger, t as BuildAuditError } from "../run-
|
|
1
|
+
import { n as auditBuild, r as stderrLogger, t as BuildAuditError } from "../run-D7hdVXLA.js";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
//#region src/nuxt/index.ts
|
|
4
4
|
function eaaKitModule(options = {}, nuxt) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as isFile } from "./fs-BmPtmFke.js";
|
|
2
|
-
import {
|
|
2
|
+
import { a as failedPage, l as runOptions, n as DEFAULT_TAGS, s as pageUrl, u as shapeResults } from "./result-DfUru6y_.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { stat } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
@@ -122,6 +122,21 @@ const DEFAULT_VIEWPORT = {
|
|
|
122
122
|
height: 720
|
|
123
123
|
};
|
|
124
124
|
/**
|
|
125
|
+
* Pages open at once.
|
|
126
|
+
*
|
|
127
|
+
* This runner used to audit strictly one page at a time while the browserless
|
|
128
|
+
* one had a whole measured worker pool — which had it backwards, since the
|
|
129
|
+
* browser is the slow engine: it fetches the stylesheets and images a real
|
|
130
|
+
* visitor would, and spends most of a page waiting on them rather than on the
|
|
131
|
+
* CPU. Waiting on four at once is close to free.
|
|
132
|
+
*
|
|
133
|
+
* Four rather than more because each open page holds a document tree, its
|
|
134
|
+
* decoded images and its own copy of axe-core, and Chromium's memory is the
|
|
135
|
+
* limit here rather than cores. Past this the gain flattens and the cost does
|
|
136
|
+
* not.
|
|
137
|
+
*/
|
|
138
|
+
const DEFAULT_CONCURRENCY = 4;
|
|
139
|
+
/**
|
|
125
140
|
* Audit a built site in real Chromium.
|
|
126
141
|
*
|
|
127
142
|
* This is the engine that can answer the rules jsdom is blind to: colour
|
|
@@ -150,13 +165,23 @@ async function runBrowserAudit(directory, pages, options = {}) {
|
|
|
150
165
|
try {
|
|
151
166
|
const context = await browser.newContext({
|
|
152
167
|
viewport,
|
|
153
|
-
bypassCSP: true
|
|
168
|
+
bypassCSP: true,
|
|
169
|
+
...options.headers === void 0 ? {} : { extraHTTPHeaders: options.headers }
|
|
154
170
|
});
|
|
155
|
-
const audits =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
171
|
+
const audits = Array.from({ length: pages.length });
|
|
172
|
+
const lanes = Math.max(1, Math.min(options.concurrency ?? DEFAULT_CONCURRENCY, pages.length));
|
|
173
|
+
let next = 0;
|
|
174
|
+
await Promise.all(Array.from({ length: lanes }, async () => {
|
|
175
|
+
while (true) {
|
|
176
|
+
const index = next;
|
|
177
|
+
if (index >= pages.length) return;
|
|
178
|
+
next += 1;
|
|
179
|
+
audits[index] = await auditOne(context, server?.origin, pages[index], {
|
|
180
|
+
tags,
|
|
181
|
+
timeout,
|
|
182
|
+
...options
|
|
183
|
+
});
|
|
184
|
+
}
|
|
160
185
|
}));
|
|
161
186
|
await context.close();
|
|
162
187
|
return audits;
|