@hypoth-ui/a11y-audit 0.1.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.
@@ -0,0 +1,515 @@
1
+ // src/lib/validator.ts
2
+ import Ajv from "ajv";
3
+ import addFormats from "ajv-formats";
4
+
5
+ // src/schemas/audit-checklist.schema.json
6
+ var audit_checklist_schema_default = {
7
+ $schema: "https://json-schema.org/draft/2020-12/schema",
8
+ $id: "https://ds.hypoth.dev/schemas/audit-checklist.schema.json",
9
+ title: "AuditChecklist",
10
+ description: "Template defining manual accessibility tests for a component category",
11
+ type: "object",
12
+ required: ["id", "name", "description", "wcagVersion", "conformanceLevel", "items", "version"],
13
+ properties: {
14
+ id: {
15
+ type: "string",
16
+ pattern: "^[a-z][a-z0-9-]*$",
17
+ description: "Unique identifier (e.g., 'form-controls')"
18
+ },
19
+ name: {
20
+ type: "string",
21
+ minLength: 1,
22
+ description: "Human-readable name"
23
+ },
24
+ description: {
25
+ type: "string",
26
+ minLength: 1,
27
+ description: "Purpose of this checklist"
28
+ },
29
+ wcagVersion: {
30
+ type: "string",
31
+ enum: ["2.0", "2.1", "2.2"],
32
+ description: "WCAG version"
33
+ },
34
+ conformanceLevel: {
35
+ type: "string",
36
+ enum: ["A", "AA", "AAA"],
37
+ description: "Target conformance level"
38
+ },
39
+ version: {
40
+ type: "string",
41
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
42
+ description: "Checklist template version (semver)"
43
+ },
44
+ items: {
45
+ type: "array",
46
+ minItems: 1,
47
+ items: {
48
+ $ref: "#/$defs/ChecklistItem"
49
+ },
50
+ description: "Array of test items"
51
+ }
52
+ },
53
+ $defs: {
54
+ ChecklistItem: {
55
+ type: "object",
56
+ required: ["id", "criterion", "description", "procedure", "expectedOutcome"],
57
+ properties: {
58
+ id: {
59
+ type: "string",
60
+ pattern: "^[a-z]{2,3}-\\d{3}$",
61
+ description: "Unique item ID (e.g., 'fc-001')"
62
+ },
63
+ criterion: {
64
+ type: "string",
65
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
66
+ description: "WCAG success criterion (e.g., '1.3.1')"
67
+ },
68
+ description: {
69
+ type: "string",
70
+ minLength: 1,
71
+ description: "What to test"
72
+ },
73
+ procedure: {
74
+ type: "string",
75
+ minLength: 1,
76
+ description: "How to test"
77
+ },
78
+ expectedOutcome: {
79
+ type: "string",
80
+ minLength: 1,
81
+ description: "What passing looks like"
82
+ },
83
+ tools: {
84
+ type: "array",
85
+ items: { type: "string" },
86
+ description: "Recommended testing tools"
87
+ },
88
+ screenReaders: {
89
+ type: "array",
90
+ items: { type: "string" },
91
+ description: "Screen readers to test with"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ };
97
+
98
+ // src/schemas/audit-record.schema.json
99
+ var audit_record_schema_default = {
100
+ $schema: "https://json-schema.org/draft/2020-12/schema",
101
+ $id: "https://ds.hypoth.dev/schemas/audit-record.schema.json",
102
+ title: "AuditRecord",
103
+ description: "Completed manual accessibility audit for a specific component version",
104
+ type: "object",
105
+ required: [
106
+ "id",
107
+ "component",
108
+ "version",
109
+ "checklistId",
110
+ "checklistVersion",
111
+ "auditor",
112
+ "auditDate",
113
+ "items",
114
+ "overallStatus"
115
+ ],
116
+ properties: {
117
+ id: {
118
+ type: "string",
119
+ format: "uuid",
120
+ description: "Auto-generated UUID"
121
+ },
122
+ component: {
123
+ type: "string",
124
+ pattern: "^ds-[a-z][a-z0-9-]*$",
125
+ description: "Component ID (e.g., 'ds-button')"
126
+ },
127
+ version: {
128
+ type: "string",
129
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
130
+ description: "Component version audited"
131
+ },
132
+ checklistId: {
133
+ type: "string",
134
+ description: "Reference to checklist template"
135
+ },
136
+ checklistVersion: {
137
+ type: "string",
138
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
139
+ description: "Version of checklist used"
140
+ },
141
+ auditor: {
142
+ type: "string",
143
+ format: "email",
144
+ description: "Auditor email/identifier"
145
+ },
146
+ auditDate: {
147
+ type: "string",
148
+ format: "date-time",
149
+ description: "Timestamp of audit completion (ISO8601)"
150
+ },
151
+ items: {
152
+ type: "array",
153
+ minItems: 1,
154
+ items: {
155
+ $ref: "#/$defs/AuditItem"
156
+ },
157
+ description: "Completed audit items"
158
+ },
159
+ overallStatus: {
160
+ type: "string",
161
+ enum: ["conformant", "partial", "non-conformant"],
162
+ description: "Overall conformance status"
163
+ },
164
+ notes: {
165
+ type: "string",
166
+ description: "General audit notes"
167
+ },
168
+ exceptions: {
169
+ type: "array",
170
+ items: {
171
+ $ref: "#/$defs/Exception"
172
+ },
173
+ description: "Documented accessibility exceptions"
174
+ }
175
+ },
176
+ $defs: {
177
+ AuditItem: {
178
+ type: "object",
179
+ required: ["itemId", "status"],
180
+ properties: {
181
+ itemId: {
182
+ type: "string",
183
+ description: "Reference to ChecklistItem.id"
184
+ },
185
+ status: {
186
+ type: "string",
187
+ enum: ["pass", "fail", "na", "blocked"],
188
+ description: "Test result status"
189
+ },
190
+ notes: {
191
+ type: "string",
192
+ description: "Auditor notes"
193
+ },
194
+ evidence: {
195
+ type: "string",
196
+ description: "Screenshot/recording reference"
197
+ }
198
+ }
199
+ },
200
+ Exception: {
201
+ type: "object",
202
+ required: ["criterion", "rationale"],
203
+ properties: {
204
+ criterion: {
205
+ type: "string",
206
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
207
+ description: "WCAG criterion with exception"
208
+ },
209
+ rationale: {
210
+ type: "string",
211
+ minLength: 10,
212
+ description: "Why exception is acceptable"
213
+ },
214
+ workaround: {
215
+ type: "string",
216
+ description: "Alternative approach for users"
217
+ },
218
+ plannedFix: {
219
+ type: "string",
220
+ description: "Roadmap reference if temporary"
221
+ }
222
+ }
223
+ }
224
+ }
225
+ };
226
+
227
+ // src/schemas/conformance-report.schema.json
228
+ var conformance_report_schema_default = {
229
+ $schema: "https://json-schema.org/draft/2020-12/schema",
230
+ $id: "https://ds.hypoth.dev/schemas/conformance-report.schema.json",
231
+ title: "ConformanceReport",
232
+ description: "Release-level accessibility conformance summary",
233
+ type: "object",
234
+ required: [
235
+ "id",
236
+ "version",
237
+ "generatedAt",
238
+ "generatedBy",
239
+ "wcagVersion",
240
+ "conformanceLevel",
241
+ "components",
242
+ "summary",
243
+ "metadata"
244
+ ],
245
+ properties: {
246
+ id: {
247
+ type: "string",
248
+ format: "uuid",
249
+ description: "Report identifier"
250
+ },
251
+ version: {
252
+ type: "string",
253
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
254
+ description: "Release version"
255
+ },
256
+ generatedAt: {
257
+ type: "string",
258
+ format: "date-time",
259
+ description: "Report generation timestamp (ISO8601)"
260
+ },
261
+ generatedBy: {
262
+ type: "string",
263
+ description: "Generator (CI job ID or user)"
264
+ },
265
+ wcagVersion: {
266
+ type: "string",
267
+ enum: ["2.0", "2.1", "2.2"],
268
+ description: "Target WCAG version"
269
+ },
270
+ conformanceLevel: {
271
+ type: "string",
272
+ enum: ["A", "AA", "AAA"],
273
+ description: "Target conformance level"
274
+ },
275
+ components: {
276
+ type: "array",
277
+ items: {
278
+ $ref: "#/$defs/ComponentStatus"
279
+ },
280
+ description: "Per-component conformance status"
281
+ },
282
+ summary: {
283
+ $ref: "#/$defs/ConformanceSummary",
284
+ description: "Aggregate statistics"
285
+ },
286
+ metadata: {
287
+ $ref: "#/$defs/ReportMetadata",
288
+ description: "Report metadata"
289
+ }
290
+ },
291
+ $defs: {
292
+ ComponentStatus: {
293
+ type: "object",
294
+ required: ["component", "version", "status", "automatedResult", "lastUpdated"],
295
+ properties: {
296
+ component: {
297
+ type: "string",
298
+ description: "Component ID"
299
+ },
300
+ version: {
301
+ type: "string",
302
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
303
+ description: "Component version"
304
+ },
305
+ status: {
306
+ type: "string",
307
+ enum: ["conformant", "partial", "non-conformant", "pending"],
308
+ description: "Overall conformance status"
309
+ },
310
+ automatedResult: {
311
+ $ref: "#/$defs/AutomatedSummary",
312
+ description: "CI test summary"
313
+ },
314
+ manualAudit: {
315
+ $ref: "#/$defs/ManualAuditSummary",
316
+ description: "Manual audit summary (optional if pending)"
317
+ },
318
+ lastUpdated: {
319
+ type: "string",
320
+ format: "date-time",
321
+ description: "Most recent audit date"
322
+ }
323
+ }
324
+ },
325
+ AutomatedSummary: {
326
+ type: "object",
327
+ required: ["passed", "violationCount", "runId"],
328
+ properties: {
329
+ passed: {
330
+ type: "boolean",
331
+ description: "Whether automated tests passed"
332
+ },
333
+ violationCount: {
334
+ type: "integer",
335
+ minimum: 0,
336
+ description: "Number of violations detected"
337
+ },
338
+ criticalCount: {
339
+ type: "integer",
340
+ minimum: 0,
341
+ description: "Critical severity violations"
342
+ },
343
+ seriousCount: {
344
+ type: "integer",
345
+ minimum: 0,
346
+ description: "Serious severity violations"
347
+ },
348
+ runId: {
349
+ type: "string",
350
+ description: "CI run identifier"
351
+ },
352
+ runDate: {
353
+ type: "string",
354
+ format: "date-time",
355
+ description: "CI run timestamp"
356
+ }
357
+ }
358
+ },
359
+ ManualAuditSummary: {
360
+ type: "object",
361
+ required: ["status", "auditId", "auditor", "auditDate"],
362
+ properties: {
363
+ status: {
364
+ type: "string",
365
+ enum: ["conformant", "partial", "non-conformant"],
366
+ description: "Manual audit status"
367
+ },
368
+ auditId: {
369
+ type: "string",
370
+ format: "uuid",
371
+ description: "Reference to full audit record"
372
+ },
373
+ auditor: {
374
+ type: "string",
375
+ description: "Auditor identifier"
376
+ },
377
+ auditDate: {
378
+ type: "string",
379
+ format: "date-time",
380
+ description: "Audit completion date"
381
+ },
382
+ passCount: {
383
+ type: "integer",
384
+ minimum: 0,
385
+ description: "Passing items"
386
+ },
387
+ failCount: {
388
+ type: "integer",
389
+ minimum: 0,
390
+ description: "Failing items"
391
+ },
392
+ exceptionCount: {
393
+ type: "integer",
394
+ minimum: 0,
395
+ description: "Documented exceptions"
396
+ }
397
+ }
398
+ },
399
+ ConformanceSummary: {
400
+ type: "object",
401
+ required: [
402
+ "totalComponents",
403
+ "conformant",
404
+ "partial",
405
+ "nonConformant",
406
+ "pending",
407
+ "conformancePercentage"
408
+ ],
409
+ properties: {
410
+ totalComponents: {
411
+ type: "integer",
412
+ minimum: 0,
413
+ description: "Total component count"
414
+ },
415
+ conformant: {
416
+ type: "integer",
417
+ minimum: 0,
418
+ description: "Fully conformant count"
419
+ },
420
+ partial: {
421
+ type: "integer",
422
+ minimum: 0,
423
+ description: "Partially conformant count"
424
+ },
425
+ nonConformant: {
426
+ type: "integer",
427
+ minimum: 0,
428
+ description: "Non-conformant count"
429
+ },
430
+ pending: {
431
+ type: "integer",
432
+ minimum: 0,
433
+ description: "Awaiting audit count"
434
+ },
435
+ conformancePercentage: {
436
+ type: "number",
437
+ minimum: 0,
438
+ maximum: 100,
439
+ description: "Percentage of conformant components"
440
+ }
441
+ }
442
+ },
443
+ ReportMetadata: {
444
+ type: "object",
445
+ required: ["schemaVersion", "toolVersion"],
446
+ properties: {
447
+ schemaVersion: {
448
+ type: "string",
449
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
450
+ description: "Schema version used"
451
+ },
452
+ toolVersion: {
453
+ type: "string",
454
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
455
+ description: "@hypoth-ui/a11y-audit version"
456
+ },
457
+ axeCoreVersion: {
458
+ type: "string",
459
+ description: "axe-core version used"
460
+ },
461
+ gitCommit: {
462
+ type: "string",
463
+ pattern: "^[a-f0-9]{40}$",
464
+ description: "Git SHA at report generation"
465
+ },
466
+ ciRunUrl: {
467
+ type: "string",
468
+ format: "uri",
469
+ description: "Link to CI run"
470
+ }
471
+ }
472
+ }
473
+ }
474
+ };
475
+
476
+ // src/lib/validator.ts
477
+ var ajv = new Ajv({ allErrors: true, strict: true });
478
+ addFormats(ajv);
479
+ var validateAuditChecklist = ajv.compile(audit_checklist_schema_default);
480
+ var validateAuditRecord = ajv.compile(audit_record_schema_default);
481
+ var validateConformanceReport = ajv.compile(conformance_report_schema_default);
482
+ function formatErrors(errors) {
483
+ if (!errors) return [];
484
+ return errors.map((err) => {
485
+ const path = err.instancePath || "/";
486
+ return `${path}: ${err.message}`;
487
+ });
488
+ }
489
+ function validateChecklist(data) {
490
+ const valid = validateAuditChecklist(data);
491
+ return {
492
+ valid,
493
+ errors: formatErrors(validateAuditChecklist.errors)
494
+ };
495
+ }
496
+ function validateRecord(data) {
497
+ const valid = validateAuditRecord(data);
498
+ return {
499
+ valid,
500
+ errors: formatErrors(validateAuditRecord.errors)
501
+ };
502
+ }
503
+ function validateReport(data) {
504
+ const valid = validateConformanceReport(data);
505
+ return {
506
+ valid,
507
+ errors: formatErrors(validateConformanceReport.errors)
508
+ };
509
+ }
510
+
511
+ export {
512
+ validateChecklist,
513
+ validateRecord,
514
+ validateReport
515
+ };
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ describeSeverityThreshold,
4
+ parseSeverityThreshold
5
+ } from "../chunk-AMA6KCPL.js";
6
+
7
+ // src/cli/index.ts
8
+ import { Command } from "commander";
9
+ var program = new Command();
10
+ program.name("a11y-audit").description(
11
+ "Accessibility audit tooling for automated checks, manual checklists, and conformance reporting"
12
+ ).version("0.0.0");
13
+ program.command("audit").description("Start a manual accessibility audit for a component").requiredOption("-c, --component <id>", "Component ID (e.g., ds-button)").requiredOption(
14
+ "--category <category>",
15
+ "Component category (form-controls, overlays, navigation, data-display, feedback)"
16
+ ).option("-v, --version <version>", "Component version (default: current)").action(async (options) => {
17
+ const { audit } = await import("../audit-Q3UXBYIW.js");
18
+ await audit(options);
19
+ });
20
+ program.command("validate").description("Validate audit records and checklist templates").option("-p, --path <path>", "Path to audit records directory", "a11y-audits/records").option("--strict", "Fail on any validation warning").action(async (options) => {
21
+ const { validate } = await import("../validate-MQQMU57I.js");
22
+ await validate(options);
23
+ });
24
+ program.command("report").description("Generate a conformance report for a release").requiredOption("-v, --version <version>", "Release version (e.g., 1.0.0)").option("-o, --output <dir>", "Output directory", "a11y-audits/reports").option("--format <formats>", "Output formats (json,html)", "json,html").action(async (options) => {
25
+ const { report } = await import("../report-6GBLBDLV.js");
26
+ await report(options);
27
+ });
28
+ program.command("check").description("Run automated accessibility checks (used by CI)").option(
29
+ "-s, --severity <levels>",
30
+ 'Severity threshold (critical,serious,moderate,minor or "all")'
31
+ ).option("--json", "Output results as JSON").action(async (options) => {
32
+ const threshold = parseSeverityThreshold(options.severity);
33
+ console.info(`Running a11y checks, failing on ${describeSeverityThreshold(threshold)}`);
34
+ console.info("Automated check command - implementation pending");
35
+ });
36
+ program.parse();
@@ -0,0 +1,156 @@
1
+ /**
2
+ * TypeScript types derived from JSON schemas
3
+ * @see ../schemas/audit-checklist.schema.json
4
+ * @see ../schemas/audit-record.schema.json
5
+ * @see ../schemas/conformance-report.schema.json
6
+ */
7
+ interface ChecklistItem {
8
+ id: string;
9
+ criterion: string;
10
+ description: string;
11
+ procedure: string;
12
+ expectedOutcome: string;
13
+ tools?: string[];
14
+ screenReaders?: string[];
15
+ }
16
+ interface AuditChecklist {
17
+ id: string;
18
+ name: string;
19
+ description: string;
20
+ wcagVersion: "2.0" | "2.1" | "2.2";
21
+ conformanceLevel: "A" | "AA" | "AAA";
22
+ version: string;
23
+ items: ChecklistItem[];
24
+ }
25
+ type AuditItemStatus = "pass" | "fail" | "na" | "blocked";
26
+ interface AuditItem {
27
+ itemId: string;
28
+ status: AuditItemStatus;
29
+ notes?: string;
30
+ evidence?: string;
31
+ }
32
+ interface Exception {
33
+ criterion: string;
34
+ rationale: string;
35
+ workaround?: string;
36
+ plannedFix?: string;
37
+ }
38
+ type OverallStatus = "conformant" | "partial" | "non-conformant";
39
+ interface AuditRecord {
40
+ id: string;
41
+ component: string;
42
+ version: string;
43
+ checklistId: string;
44
+ checklistVersion: string;
45
+ auditor: string;
46
+ auditDate: string;
47
+ items: AuditItem[];
48
+ overallStatus: OverallStatus;
49
+ notes?: string;
50
+ exceptions?: Exception[];
51
+ }
52
+ interface AutomatedSummary {
53
+ passed: boolean;
54
+ violationCount: number;
55
+ criticalCount?: number;
56
+ seriousCount?: number;
57
+ runId: string;
58
+ runDate?: string;
59
+ }
60
+ interface ManualAuditSummary {
61
+ status: OverallStatus;
62
+ auditId: string;
63
+ auditor: string;
64
+ auditDate: string;
65
+ passCount?: number;
66
+ failCount?: number;
67
+ exceptionCount?: number;
68
+ }
69
+ type ComponentConformanceStatus = "conformant" | "partial" | "non-conformant" | "pending";
70
+ interface ComponentStatus {
71
+ component: string;
72
+ version: string;
73
+ status: ComponentConformanceStatus;
74
+ automatedResult: AutomatedSummary;
75
+ manualAudit?: ManualAuditSummary;
76
+ lastUpdated: string;
77
+ }
78
+ interface ConformanceSummary {
79
+ totalComponents: number;
80
+ conformant: number;
81
+ partial: number;
82
+ nonConformant: number;
83
+ pending: number;
84
+ conformancePercentage: number;
85
+ }
86
+ interface ReportMetadata {
87
+ schemaVersion: string;
88
+ toolVersion: string;
89
+ axeCoreVersion?: string;
90
+ gitCommit?: string;
91
+ ciRunUrl?: string;
92
+ }
93
+ interface ConformanceReport {
94
+ id: string;
95
+ version: string;
96
+ generatedAt: string;
97
+ generatedBy: string;
98
+ wcagVersion: "2.0" | "2.1" | "2.2";
99
+ conformanceLevel: "A" | "AA" | "AAA";
100
+ components: ComponentStatus[];
101
+ summary: ConformanceSummary;
102
+ metadata: ReportMetadata;
103
+ }
104
+ type ViolationSeverity = "critical" | "serious" | "moderate" | "minor";
105
+ interface SeverityThreshold {
106
+ failOn: ViolationSeverity[];
107
+ }
108
+
109
+ interface ValidationResult {
110
+ valid: boolean;
111
+ errors: string[];
112
+ }
113
+ declare function validateChecklist(data: unknown): ValidationResult;
114
+ declare function validateRecord(data: unknown): ValidationResult;
115
+ declare function validateReport(data: unknown): ValidationResult;
116
+
117
+ /**
118
+ * Default severity threshold: fail on Critical + Serious violations
119
+ * This matches axe-core's default behavior and WCAG compliance requirements
120
+ */
121
+ declare const DEFAULT_SEVERITY_THRESHOLD: SeverityThreshold;
122
+ /**
123
+ * All available severity levels in order of importance
124
+ */
125
+ declare const SEVERITY_LEVELS: ViolationSeverity[];
126
+ /**
127
+ * Environment variable name for severity threshold override
128
+ */
129
+ declare const SEVERITY_ENV_VAR = "A11Y_SEVERITY";
130
+ /**
131
+ * Parse severity threshold from CLI flag or environment variable
132
+ *
133
+ * Accepts comma-separated severity levels:
134
+ * - "critical" - fail only on critical
135
+ * - "critical,serious" - fail on critical or serious (default)
136
+ * - "critical,serious,moderate" - fail on critical, serious, or moderate
137
+ * - "all" - fail on any violation
138
+ *
139
+ * @param value - CLI flag value or undefined to check env var
140
+ * @returns Parsed severity threshold
141
+ */
142
+ declare function parseSeverityThreshold(value?: string): SeverityThreshold;
143
+ /**
144
+ * Check if a violation severity should cause a failure
145
+ *
146
+ * @param severity - The violation severity to check
147
+ * @param threshold - The threshold configuration
148
+ * @returns true if this severity should cause a failure
149
+ */
150
+ declare function shouldFailOnSeverity(severity: ViolationSeverity, threshold?: SeverityThreshold): boolean;
151
+ /**
152
+ * Get human-readable description of the severity threshold
153
+ */
154
+ declare function describeSeverityThreshold(threshold: SeverityThreshold): string;
155
+
156
+ export { type AuditChecklist, type AuditItem, type AuditItemStatus, type AuditRecord, type AutomatedSummary, type ChecklistItem, type ComponentConformanceStatus, type ComponentStatus, type ConformanceReport, type ConformanceSummary, DEFAULT_SEVERITY_THRESHOLD, type Exception, type ManualAuditSummary, type OverallStatus, type ReportMetadata, SEVERITY_ENV_VAR, SEVERITY_LEVELS, type SeverityThreshold, type ValidationResult, type ViolationSeverity, describeSeverityThreshold, parseSeverityThreshold, shouldFailOnSeverity, validateChecklist, validateRecord, validateReport };