@diegovelasquezweb/a11y-engine 0.7.2 → 0.7.3
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 +3 -25
- package/docs/api-reference.md +42 -3
- package/package.json +1 -1
- package/src/cli/audit.mjs +11 -2
- package/src/source-patterns/source-scanner.mjs +44 -21
package/README.md
CHANGED
|
@@ -62,29 +62,7 @@ const payload = await runAudit({
|
|
|
62
62
|
});
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
**`runAudit` options**
|
|
68
|
-
|
|
69
|
-
| Option | Type | Description |
|
|
70
|
-
| :--- | :--- | :--- |
|
|
71
|
-
| `baseUrl` | `string` | Target URL to scan |
|
|
72
|
-
| `maxRoutes` | `number` | Maximum routes to discover and scan |
|
|
73
|
-
| `crawlDepth` | `number` | How many link levels to follow from the starting URL |
|
|
74
|
-
| `axeTags` | `string[]` | WCAG tag filters (e.g. `["wcag2a", "wcag2aa"]`) |
|
|
75
|
-
| `engines` | `{ axe?, cdp?, pa11y? }` | Enable or disable individual scan engines |
|
|
76
|
-
| `waitUntil` | `string` | Page load strategy: `"domcontentloaded"`, `"load"`, or `"networkidle"` |
|
|
77
|
-
| `timeoutMs` | `number` | Per-page timeout in milliseconds |
|
|
78
|
-
| `viewport` | `{ width, height }` | Browser viewport size |
|
|
79
|
-
| `colorScheme` | `string` | Emulated color scheme: `"light"` or `"dark"` |
|
|
80
|
-
| `projectDir` | `string` | Local project path for stack detection and source pattern scanning |
|
|
81
|
-
| `repoUrl` | `string` | GitHub repo URL for remote stack detection and source pattern scanning |
|
|
82
|
-
| `githubToken` | `string` | GitHub token for API access when using `repoUrl` |
|
|
83
|
-
| `skipPatterns` | `boolean` | Disable source pattern scanning |
|
|
84
|
-
| `ai` | `{ enabled?, apiKey?, githubToken?, model? }` | AI enrichment configuration |
|
|
85
|
-
| `onProgress` | `(step, status, extra?) => void` | Progress callback for UI updates |
|
|
86
|
-
|
|
87
|
-
See [API Reference](docs/api-reference.md) for the full `RunAuditOptions` contract.
|
|
65
|
+
See [API Reference](docs/api-reference.md) for options, progress steps, and return types.
|
|
88
66
|
|
|
89
67
|
#### getFindings
|
|
90
68
|
|
|
@@ -133,13 +111,13 @@ These functions render final artifacts from scan payload data.
|
|
|
133
111
|
|
|
134
112
|
### Knowledge API
|
|
135
113
|
|
|
136
|
-
These functions expose scanner help content, persona explanations, conformance levels, and UI copy so frontends or agents can render
|
|
114
|
+
These functions expose scanner help content, persona explanations, conformance levels, and UI copy so frontends or agents can render guidance from engine-owned data.
|
|
137
115
|
|
|
138
116
|
| Function | Returns | Description |
|
|
139
117
|
| :--- | :--- | :--- |
|
|
140
118
|
| `getScannerHelp(options?)` | `{ locale, version, title, engines, options }` | Scanner option and engine help metadata |
|
|
141
119
|
| `getPersonaReference(options?)` | `{ locale, version, personas }` | Persona labels, descriptions, and mapping hints |
|
|
142
|
-
| `getUiHelp(options?)` | `{ locale, version,
|
|
120
|
+
| `getUiHelp(options?)` | `{ locale, version, concepts, glossary }` | Shared concept definitions and glossary entries |
|
|
143
121
|
| `getConformanceLevels(options?)` | `{ locale, version, conformanceLevels }` | WCAG conformance level definitions with axe tag mappings |
|
|
144
122
|
| `getWcagPrinciples(options?)` | `{ locale, version, wcagPrinciples }` | The four WCAG principles with criterion prefix patterns |
|
|
145
123
|
| `getSeverityLevels(options?)` | `{ locale, version, severityLevels }` | Severity level definitions with labels and ordering |
|
package/docs/api-reference.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
### `runAudit(options)`
|
|
10
10
|
|
|
11
|
-
Runs route discovery, runtime scan, merge, and
|
|
11
|
+
Runs route discovery, runtime scan, merge, analyzer enrichment, and optional AI enrichment. Supports local project paths or remote GitHub repos for stack detection and source pattern scanning.
|
|
12
12
|
|
|
13
13
|
`options` (`RunAuditOptions`):
|
|
14
14
|
|
|
@@ -30,10 +30,28 @@ Runs route discovery, runtime scan, merge, and analyzer enrichment.
|
|
|
30
30
|
| `ignoreFindings` | `string[]` |
|
|
31
31
|
| `framework` | `string` |
|
|
32
32
|
| `projectDir` | `string` |
|
|
33
|
+
| `repoUrl` | `string` |
|
|
34
|
+
| `githubToken` | `string` |
|
|
33
35
|
| `skipPatterns` | `boolean` |
|
|
34
36
|
| `screenshotsDir` | `string` |
|
|
37
|
+
| `engines` | `{ axe?: boolean; cdp?: boolean; pa11y?: boolean }` |
|
|
38
|
+
| `ai` | `{ enabled?: boolean; apiKey?: string; githubToken?: string; model?: string }` |
|
|
35
39
|
| `onProgress` | `(step: string, status: string, extra?: Record<string, unknown>) => void` |
|
|
36
40
|
|
|
41
|
+
Progress steps emitted via `onProgress`:
|
|
42
|
+
|
|
43
|
+
| Step | When |
|
|
44
|
+
| :--- | :--- |
|
|
45
|
+
| `page` | Always — page load |
|
|
46
|
+
| `axe` | Always — axe-core scan |
|
|
47
|
+
| `cdp` | Always — CDP accessibility tree check |
|
|
48
|
+
| `pa11y` | Always — pa11y HTML CodeSniffer scan |
|
|
49
|
+
| `merge` | Always — finding deduplication |
|
|
50
|
+
| `intelligence` | Always — enrichment and WCAG mapping |
|
|
51
|
+
| `repo` | When `repoUrl` is set |
|
|
52
|
+
| `patterns` | When source scanning is active |
|
|
53
|
+
| `ai` | When AI enrichment is configured |
|
|
54
|
+
|
|
37
55
|
Returns: `Promise<ScanPayload>`
|
|
38
56
|
|
|
39
57
|
### `getFindings(input, options?)`
|
|
@@ -123,14 +141,35 @@ Returns: `PersonaReference` (`{ locale, version, personas }`)
|
|
|
123
141
|
- `options`: `KnowledgeOptions`
|
|
124
142
|
- `locale?: string`
|
|
125
143
|
|
|
126
|
-
Returns: `UiHelp` (`{ locale, version,
|
|
144
|
+
Returns: `UiHelp` (`{ locale, version, concepts, glossary }`)
|
|
145
|
+
|
|
146
|
+
### `getConformanceLevels(options?)`
|
|
147
|
+
|
|
148
|
+
- `options`: `KnowledgeOptions`
|
|
149
|
+
- `locale?: string`
|
|
150
|
+
|
|
151
|
+
Returns: `ConformanceLevelsResult` (`{ locale, version, conformanceLevels }`)
|
|
152
|
+
|
|
153
|
+
### `getWcagPrinciples(options?)`
|
|
154
|
+
|
|
155
|
+
- `options`: `KnowledgeOptions`
|
|
156
|
+
- `locale?: string`
|
|
157
|
+
|
|
158
|
+
Returns: `WcagPrinciplesResult` (`{ locale, version, wcagPrinciples }`)
|
|
159
|
+
|
|
160
|
+
### `getSeverityLevels(options?)`
|
|
161
|
+
|
|
162
|
+
- `options`: `KnowledgeOptions`
|
|
163
|
+
- `locale?: string`
|
|
164
|
+
|
|
165
|
+
Returns: `SeverityLevelsResult` (`{ locale, version, severityLevels }`)
|
|
127
166
|
|
|
128
167
|
### `getKnowledge(options?)`
|
|
129
168
|
|
|
130
169
|
- `options`: `KnowledgeOptions`
|
|
131
170
|
- `locale?: string`
|
|
132
171
|
|
|
133
|
-
Returns: `EngineKnowledge` (`{ locale, version, scanner, personas,
|
|
172
|
+
Returns: `EngineKnowledge` (`{ locale, version, scanner, personas, concepts, glossary, docs, conformanceLevels, wcagPrinciples, severityLevels }`)
|
|
134
173
|
|
|
135
174
|
---
|
|
136
175
|
|
package/package.json
CHANGED
package/src/cli/audit.mjs
CHANGED
|
@@ -140,6 +140,9 @@ async function main() {
|
|
|
140
140
|
const timeoutMs = getArgValue("timeout-ms") || DEFAULTS.timeoutMs;
|
|
141
141
|
const axeTags = getArgValue("axe-tags");
|
|
142
142
|
|
|
143
|
+
const repoUrl = getArgValue("repo-url");
|
|
144
|
+
const githubToken = getArgValue("github-token");
|
|
145
|
+
|
|
143
146
|
const sessionFile = getInternalPath("a11y-session.json");
|
|
144
147
|
let projectDir = getArgValue("project-dir");
|
|
145
148
|
if (projectDir) {
|
|
@@ -268,8 +271,14 @@ async function main() {
|
|
|
268
271
|
if (framework) analyzerArgs.push("--framework", framework);
|
|
269
272
|
await runScript("../enrichment/analyzer.mjs", analyzerArgs);
|
|
270
273
|
|
|
271
|
-
if (projectDir && !skipPatterns) {
|
|
272
|
-
const patternArgs = [
|
|
274
|
+
if ((projectDir || repoUrl) && !skipPatterns) {
|
|
275
|
+
const patternArgs = [];
|
|
276
|
+
if (projectDir) {
|
|
277
|
+
patternArgs.push("--project-dir", path.resolve(projectDir));
|
|
278
|
+
} else {
|
|
279
|
+
patternArgs.push("--repo-url", repoUrl);
|
|
280
|
+
if (githubToken) patternArgs.push("--github-token", githubToken);
|
|
281
|
+
}
|
|
273
282
|
let resolvedFramework = framework;
|
|
274
283
|
if (!resolvedFramework) {
|
|
275
284
|
try {
|
|
@@ -46,6 +46,8 @@ function parseArgs(argv) {
|
|
|
46
46
|
|
|
47
47
|
const args = {
|
|
48
48
|
projectDir: null,
|
|
49
|
+
repoUrl: null,
|
|
50
|
+
githubToken: null,
|
|
49
51
|
framework: null,
|
|
50
52
|
output: getInternalPath("a11y-pattern-findings.json"),
|
|
51
53
|
onlyPattern: null,
|
|
@@ -56,13 +58,15 @@ function parseArgs(argv) {
|
|
|
56
58
|
const value = argv[i + 1];
|
|
57
59
|
if (!key.startsWith("--") || value === undefined) continue;
|
|
58
60
|
if (key === "--project-dir") args.projectDir = value;
|
|
61
|
+
if (key === "--repo-url") args.repoUrl = value;
|
|
62
|
+
if (key === "--github-token") args.githubToken = value;
|
|
59
63
|
if (key === "--framework") args.framework = value;
|
|
60
64
|
if (key === "--output") args.output = value;
|
|
61
65
|
if (key === "--only-pattern") args.onlyPattern = value;
|
|
62
66
|
i++;
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
if (!args.projectDir) throw new Error("Missing required --project-dir");
|
|
69
|
+
if (!args.projectDir && !args.repoUrl) throw new Error("Missing required --project-dir or --repo-url");
|
|
66
70
|
return args;
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -320,7 +324,7 @@ export async function scanPatternRemote(pattern, repoUrl, githubToken, framework
|
|
|
320
324
|
/**
|
|
321
325
|
* Main execution function for the pattern scanner.
|
|
322
326
|
*/
|
|
323
|
-
function main() {
|
|
327
|
+
async function main() {
|
|
324
328
|
const args = parseArgs(process.argv.slice(2));
|
|
325
329
|
const { patterns } = loadAssetJson(
|
|
326
330
|
ASSET_PATHS.remediation.codePatterns,
|
|
@@ -339,23 +343,44 @@ function main() {
|
|
|
339
343
|
process.exit(0);
|
|
340
344
|
}
|
|
341
345
|
|
|
342
|
-
const scanDirs = resolveScanDirs(args.framework, args.projectDir);
|
|
343
|
-
log.info(`Scanning source code at: ${args.projectDir}`);
|
|
344
|
-
if (scanDirs.length > 1 || scanDirs[0] !== args.projectDir) {
|
|
345
|
-
log.info(` Scoped to: ${scanDirs.map((d) => relative(args.projectDir, d)).join(", ")}`);
|
|
346
|
-
}
|
|
347
|
-
log.info(`Running ${activePatterns.length} pattern(s)...`);
|
|
348
|
-
|
|
349
346
|
const allFindings = [];
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
347
|
+
|
|
348
|
+
if (args.repoUrl) {
|
|
349
|
+
// Remote scan via GitHub API — no clone needed
|
|
350
|
+
log.info(`Scanning source code at: ${args.repoUrl}`);
|
|
351
|
+
log.info(`Running ${activePatterns.length} pattern(s) via GitHub API...`);
|
|
352
|
+
|
|
353
|
+
for (const pattern of activePatterns) {
|
|
354
|
+
const findings = await scanPatternRemote(
|
|
355
|
+
pattern,
|
|
356
|
+
args.repoUrl,
|
|
357
|
+
args.githubToken || null,
|
|
358
|
+
args.framework || null,
|
|
359
|
+
);
|
|
360
|
+
if (findings.length > 0) {
|
|
361
|
+
log.info(` ${pattern.id}: ${findings.length} match(es)`);
|
|
362
|
+
}
|
|
363
|
+
allFindings.push(...findings);
|
|
354
364
|
}
|
|
355
|
-
|
|
356
|
-
|
|
365
|
+
} else {
|
|
366
|
+
// Local filesystem scan
|
|
367
|
+
const scanDirs = resolveScanDirs(args.framework, args.projectDir);
|
|
368
|
+
log.info(`Scanning source code at: ${args.projectDir}`);
|
|
369
|
+
if (scanDirs.length > 1 || scanDirs[0] !== args.projectDir) {
|
|
370
|
+
log.info(` Scoped to: ${scanDirs.map((d) => relative(args.projectDir, d)).join(", ")}`);
|
|
371
|
+
}
|
|
372
|
+
log.info(`Running ${activePatterns.length} pattern(s)...`);
|
|
373
|
+
|
|
374
|
+
for (const pattern of activePatterns) {
|
|
375
|
+
const findings = [];
|
|
376
|
+
for (const scanDir of scanDirs) {
|
|
377
|
+
findings.push(...scanPattern(pattern, scanDir, args.projectDir));
|
|
378
|
+
}
|
|
379
|
+
if (findings.length > 0) {
|
|
380
|
+
log.info(` ${pattern.id}: ${findings.length} match(es)`);
|
|
381
|
+
}
|
|
382
|
+
allFindings.push(...findings);
|
|
357
383
|
}
|
|
358
|
-
allFindings.push(...findings);
|
|
359
384
|
}
|
|
360
385
|
|
|
361
386
|
const confirmed = allFindings.filter((f) => f.status === "confirmed").length;
|
|
@@ -363,7 +388,7 @@ function main() {
|
|
|
363
388
|
|
|
364
389
|
writeJson(args.output, {
|
|
365
390
|
generated_at: new Date().toISOString(),
|
|
366
|
-
project_dir: args.projectDir,
|
|
391
|
+
project_dir: args.repoUrl || args.projectDir,
|
|
367
392
|
findings: allFindings,
|
|
368
393
|
summary: {
|
|
369
394
|
total: allFindings.length,
|
|
@@ -378,10 +403,8 @@ function main() {
|
|
|
378
403
|
}
|
|
379
404
|
|
|
380
405
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
381
|
-
|
|
382
|
-
main();
|
|
383
|
-
} catch (error) {
|
|
406
|
+
main().catch((error) => {
|
|
384
407
|
log.error(error.message);
|
|
385
408
|
process.exit(1);
|
|
386
|
-
}
|
|
409
|
+
});
|
|
387
410
|
}
|