@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 CHANGED
@@ -62,29 +62,7 @@ const payload = await runAudit({
62
62
  });
63
63
  ```
64
64
 
65
- Progress steps emitted: `repo`, `page`, `axe`, `cdp`, `pa11y`, `merge`, `intelligence`, `patterns`, `ai`. Steps are conditional — `repo` only fires when `repoUrl` is set, `patterns` when source scanning is active, and `ai` when AI enrichment is configured.
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 tooltips and guidance from engine-owned data.
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, tooltips, glossary }` | Shared tooltip copy and glossary entries |
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 |
@@ -8,7 +8,7 @@
8
8
 
9
9
  ### `runAudit(options)`
10
10
 
11
- Runs route discovery, runtime scan, merge, and analyzer enrichment.
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, tooltips, glossary }`)
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, tooltips, glossary }`)
172
+ Returns: `EngineKnowledge` (`{ locale, version, scanner, personas, concepts, glossary, docs, conformanceLevels, wcagPrinciples, severityLevels }`)
134
173
 
135
174
  ---
136
175
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegovelasquezweb/a11y-engine",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "WCAG 2.2 accessibility audit engine — scanner, analyzer, and report builders",
5
5
  "type": "module",
6
6
  "license": "MIT",
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 = ["--project-dir", path.resolve(projectDir)];
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
- for (const pattern of activePatterns) {
351
- const findings = [];
352
- for (const scanDir of scanDirs) {
353
- findings.push(...scanPattern(pattern, scanDir, args.projectDir));
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
- if (findings.length > 0) {
356
- log.info(` ${pattern.id}: ${findings.length} match(es)`);
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
- try {
382
- main();
383
- } catch (error) {
406
+ main().catch((error) => {
384
407
  log.error(error.message);
385
408
  process.exit(1);
386
- }
409
+ });
387
410
  }