@diegovelasquezweb/a11y-engine 0.8.2 → 0.8.4
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/CHANGELOG.md +70 -0
- package/README.md +26 -5
- package/docs/api-reference.md +372 -100
- package/docs/architecture.md +18 -6
- package/docs/cli-handbook.md +76 -2
- package/docs/engine-manifest.md +12 -1
- package/docs/intelligence.md +61 -7
- package/docs/outputs.md +60 -1
- package/package.json +1 -1
- package/src/ai/claude.mjs +16 -10
- package/src/enrichment/analyzer.mjs +4 -2
- package/src/index.d.mts +18 -9
- package/src/index.mjs +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,76 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.8.2] — 2026-03-16
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Smarter AI source file selection** — `fetchSourceFilesForFindings` now scores candidate files by how many terms extracted from the finding's selector, class names, IDs, and title match the file path. Files most relevant to the specific failing element are fetched first instead of picking the first 3 files by extension.
|
|
13
|
+
- Extracted `extractSearchTermsFromFinding()` and `scoreFilePath()` helpers for reusable relevance scoring logic.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## [0.8.1] — 2026-03-16
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Custom AI system prompt** — `enrichWithAI()` now accepts `options.systemPrompt` to override the default Claude system prompt at runtime.
|
|
22
|
+
- `enrich.mjs` reads `AI_SYSTEM_PROMPT` env var and passes it to `enrichWithAI()` — enabling per-scan prompt customization without code changes.
|
|
23
|
+
- `audit.mjs` forwards `AI_SYSTEM_PROMPT` env var to the `enrich.mjs` child process.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## [0.8.0] — 2026-03-16
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **AI enrichment no longer overwrites original fix** — `enrich.mjs` now preserves the original `fix_description`/`fix_code` from the engine and stores Claude's output in separate fields: `ai_fix_description`, `ai_fix_code`, `ai_fix_code_lang`. Findings improved by AI are flagged with `aiEnhanced: true`.
|
|
32
|
+
- **AI system prompt rewritten** — Claude is now explicitly instructed to go beyond the generic fix: explain why the issue matters for real users, what specifically to look for in the codebase, and provide a production-quality code example different from the existing one.
|
|
33
|
+
- Default AI model updated to `claude-haiku-4-5-20251001`.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## [0.7.9] — 2026-03-16
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **AI enrichment CLI step** — `audit.mjs` now runs `src/ai/enrich.mjs` after the analyzer step when `ANTHROPIC_API_KEY` env var is present. Non-fatal: if AI fails, the pipeline continues with unenriched findings.
|
|
42
|
+
- `src/ai/enrich.mjs` — new CLI script that reads `a11y-findings.json`, calls `enrichWithAI()`, and writes enriched findings back. Reads `A11Y_REPO_URL` and `GH_TOKEN` env vars for repo-aware enrichment.
|
|
43
|
+
- `src/ai/claude.mjs` — Claude AI enrichment module. Enriches Critical and Serious findings with context-aware fix descriptions and code snippets. Uses `claude-haiku-4-5-20251001` by default. Fetches source files from the GitHub repo when `repoUrl` is available.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## [0.7.8] — 2026-03-16
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- **pa11y ruleId normalization** — pa11y violation IDs (e.g. `WCAG2AAA.Principle1.Guideline1_4.1_4_6.G17`) are now normalized to a short, readable form (e.g. `pa11y-g17`) by taking only the last segment of the dotted code. Previously the full dotted path was used, producing unreadable badges like `Pa11y Wcag2aaa Principle1 Guideline1 4 1 4 6 G17`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## [0.7.7] — 2026-03-15
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- **`--repo-url` and `--github-token` CLI flags** — `audit.mjs` now accepts `--repo-url <github-url>` and `--github-token <token>`. When a repo URL is provided, the engine fetches `package.json` via the GitHub API to detect the project framework before running the analyzer, and passes the detected framework to both the analyzer and the source pattern scanner. No `git clone` required.
|
|
60
|
+
- `source-scanner.mjs` CLI now accepts `--repo-url` and `--github-token`. When `--repo-url` is provided (without `--project-dir`), it runs `scanPatternRemote()` against the GitHub API instead of the local filesystem.
|
|
61
|
+
- `detectProjectContext()` is now called in `audit.mjs` when a remote repo is provided, enabling framework-aware fix suggestions without a local clone.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- `source-scanner.mjs`: `--project-dir` is no longer required when `--repo-url` is provided. `main()` is now async to support remote API calls.
|
|
66
|
+
- `audit.mjs`: pattern scanning is now triggered when either `--project-dir` or `--repo-url` is provided.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## [0.7.6] — 2026-03-15
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- HTML report renderer: updated Tailwind class syntax (`flex-shrink-0` → `shrink-0`, `bg-gradient-to-br` → `bg-linear-to-br`, `max-h-[360px]` → `max-h-90`).
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
8
78
|
## [0.4.2] — 2026-03-15
|
|
9
79
|
|
|
10
80
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @diegovelasquezweb/a11y-engine
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@diegovelasquezweb/a11y-engine)
|
|
4
|
+
|
|
3
5
|
Accessibility automation engine for web applications. It orchestrates multi engine scanning, stack aware enrichment, and report generation for apps and services through a stable API.
|
|
4
6
|
|
|
5
7
|
## What it does
|
|
@@ -12,7 +14,7 @@ Accessibility automation engine for web applications. It orchestrates multi engi
|
|
|
12
14
|
| **Fix intelligence** | Enriches each finding with WCAG mapping, fix code snippets, framework and CMS specific notes, UI library ownership hints, effort estimates, and persona impact |
|
|
13
15
|
| **AI enrichment** | Optional Claude-powered analysis that adds contextual fix suggestions based on detected stack, repo structure, and finding patterns |
|
|
14
16
|
| **Report generation** | Produces HTML dashboard, PDF compliance report, manual testing checklist, and Markdown remediation guide |
|
|
15
|
-
| **Source code scanning** | Static regex analysis of project source for accessibility patterns that runtime engines cannot detect
|
|
17
|
+
| **Source code scanning** | Static regex analysis of project source for accessibility patterns that runtime engines cannot detect. Works with local paths or remote GitHub repos |
|
|
16
18
|
|
|
17
19
|
## Installation
|
|
18
20
|
|
|
@@ -50,7 +52,7 @@ import {
|
|
|
50
52
|
|
|
51
53
|
#### runAudit
|
|
52
54
|
|
|
53
|
-
Runs the full scan pipeline: route discovery, scan, merge, analyze, and optional
|
|
55
|
+
Runs the full scan pipeline: route discovery, scan, merge, analyze, AI enrichment (when configured), and optional source pattern scanning. Returns a payload ready for `getFindings`.
|
|
54
56
|
|
|
55
57
|
```ts
|
|
56
58
|
const payload = await runAudit({
|
|
@@ -58,6 +60,14 @@ const payload = await runAudit({
|
|
|
58
60
|
maxRoutes: 5,
|
|
59
61
|
axeTags: ["wcag2a", "wcag2aa", "best-practice"],
|
|
60
62
|
engines: { axe: true, cdp: true, pa11y: true },
|
|
63
|
+
repoUrl: "https://github.com/owner/repo", // optional, enables source pattern scan and stack detection
|
|
64
|
+
githubToken: process.env.GH_TOKEN, // optional, required for private repos
|
|
65
|
+
ai: {
|
|
66
|
+
enabled: true,
|
|
67
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
68
|
+
githubToken: process.env.GH_TOKEN,
|
|
69
|
+
systemPrompt: "Custom prompt...", // optional, overrides default Claude system prompt
|
|
70
|
+
},
|
|
61
71
|
onProgress: (step, status, extra) => console.log(`${step}: ${status}`, extra),
|
|
62
72
|
});
|
|
63
73
|
```
|
|
@@ -125,10 +135,21 @@ These functions expose scanner help content, persona explanations, conformance l
|
|
|
125
135
|
|
|
126
136
|
See [API Reference](docs/api-reference.md) for exact options and return types.
|
|
127
137
|
|
|
128
|
-
##
|
|
138
|
+
## CLI
|
|
139
|
+
|
|
140
|
+
The package exposes an `a11y-audit` binary for terminal execution. See the [CLI Handbook](docs/cli-handbook.md) for all flags, env vars, and examples.
|
|
141
|
+
|
|
142
|
+
## AI enrichment
|
|
143
|
+
|
|
144
|
+
When `ANTHROPIC_API_KEY` is set, the engine runs a post-scan enrichment step that sends Critical and Serious findings to Claude. Claude generates:
|
|
145
|
+
|
|
146
|
+
- A specific fix description referencing the actual selector, colors, and violation data
|
|
147
|
+
- A production-quality code snippet in the correct framework syntax
|
|
148
|
+
- Context-aware suggestions when repo source files are available
|
|
149
|
+
|
|
150
|
+
AI output is stored in separate fields (`ai_fix_description`, `ai_fix_code`). The original engine fixes are always preserved. Findings improved by AI are flagged with `aiEnhanced: true`.
|
|
129
151
|
|
|
130
|
-
|
|
131
|
-
See the [CLI Handbook](docs/cli-handbook.md) for command flags and examples.
|
|
152
|
+
The system prompt is fully customizable via `options.ai.systemPrompt` (programmatic API) or the `AI_SYSTEM_PROMPT` env var (CLI).
|
|
132
153
|
|
|
133
154
|
## Documentation
|
|
134
155
|
|
package/docs/api-reference.md
CHANGED
|
@@ -4,172 +4,444 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Import](#import)
|
|
11
|
+
- [End-to-end example](#end-to-end-example)
|
|
12
|
+
- [Core API](#core-api)
|
|
13
|
+
- [runAudit](#runauditoptions)
|
|
14
|
+
- [getFindings](#getfindingsinput-options)
|
|
15
|
+
- [getOverview](#getoverviewfindings-payload)
|
|
16
|
+
- [Output API](#output-api)
|
|
17
|
+
- [getPDFReport](#getpdfreportpayload-options)
|
|
18
|
+
- [getHTMLReport](#gethtmlreportpayload-options)
|
|
19
|
+
- [getChecklist](#getchecklistoptions)
|
|
20
|
+
- [getRemediationGuide](#getremediationguidepayload-options)
|
|
21
|
+
- [getSourcePatterns](#getsourcepatternsprojdir-options)
|
|
22
|
+
- [Knowledge API](#knowledge-api)
|
|
23
|
+
- [getKnowledge](#getknowledgeoptions)
|
|
24
|
+
- [getScannerHelp](#getscannerhelpoptions)
|
|
25
|
+
- [getPersonaReference](#getpersonareferenceoptions)
|
|
26
|
+
- [getUiHelp](#getuihelpoptions)
|
|
27
|
+
- [getConformanceLevels](#getconformancelevelsoptions)
|
|
28
|
+
- [getWcagPrinciples](#getwcagprinciplesoptions)
|
|
29
|
+
- [getSeverityLevels](#getseveritylevelsoptions)
|
|
8
30
|
|
|
9
|
-
|
|
31
|
+
---
|
|
10
32
|
|
|
11
|
-
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @diegovelasquezweb/a11y-engine
|
|
37
|
+
npx playwright install chromium
|
|
38
|
+
npx puppeteer browsers install chrome
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Import
|
|
42
|
+
|
|
43
|
+
All functions are named exports from the package root:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import {
|
|
47
|
+
runAudit,
|
|
48
|
+
getFindings,
|
|
49
|
+
getOverview,
|
|
50
|
+
getPDFReport,
|
|
51
|
+
getHTMLReport,
|
|
52
|
+
getChecklist,
|
|
53
|
+
getRemediationGuide,
|
|
54
|
+
getSourcePatterns,
|
|
55
|
+
getKnowledge,
|
|
56
|
+
getScannerHelp,
|
|
57
|
+
getPersonaReference,
|
|
58
|
+
getUiHelp,
|
|
59
|
+
getConformanceLevels,
|
|
60
|
+
getWcagPrinciples,
|
|
61
|
+
getSeverityLevels,
|
|
62
|
+
} from "@diegovelasquezweb/a11y-engine";
|
|
63
|
+
```
|
|
12
64
|
|
|
13
|
-
|
|
65
|
+
---
|
|
14
66
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
## End-to-end example
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { runAudit, getFindings, getOverview } from "@diegovelasquezweb/a11y-engine";
|
|
71
|
+
|
|
72
|
+
// 1. Run the scan
|
|
73
|
+
const payload = await runAudit({
|
|
74
|
+
baseUrl: "https://example.com",
|
|
75
|
+
maxRoutes: 5,
|
|
76
|
+
engines: { axe: true, cdp: true, pa11y: true },
|
|
77
|
+
onProgress: (step, status) => console.log(`[${step}] ${status}`),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// 2. Get enriched findings
|
|
81
|
+
const findings = getFindings(payload);
|
|
82
|
+
|
|
83
|
+
// 3. Get compliance summary
|
|
84
|
+
const { score, scoreLabel, wcagStatus, totals, quickWins } = getOverview(findings, payload);
|
|
85
|
+
|
|
86
|
+
console.log(`Score: ${score}/100 (${scoreLabel})`);
|
|
87
|
+
console.log(`WCAG Status: ${wcagStatus}`);
|
|
88
|
+
console.log(`Critical: ${totals.Critical}, Serious: ${totals.Serious}`);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Core API
|
|
94
|
+
|
|
95
|
+
### `runAudit(options)`
|
|
96
|
+
|
|
97
|
+
Runs the full audit pipeline: route discovery → axe/CDP/pa11y scan → merge/dedup → analyzer enrichment → optional source pattern scanning → optional AI enrichment.
|
|
98
|
+
|
|
99
|
+
Returns a `ScanPayload` object consumed by all other functions.
|
|
100
|
+
|
|
101
|
+
**Options:**
|
|
102
|
+
|
|
103
|
+
| Option | Type | Default | Range / Values | Description |
|
|
104
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
105
|
+
| `baseUrl` | `string` | — | Required | Starting URL including protocol (`https://` or `http://`) |
|
|
106
|
+
| `maxRoutes` | `number` | `10` | 1 – 50 | Maximum unique pages to discover and scan |
|
|
107
|
+
| `crawlDepth` | `number` | `2` | 1 – 3 | BFS link-follow depth from `baseUrl`. Has no effect when `routes` is set |
|
|
108
|
+
| `routes` | `string` | — | CSV paths | Explicit paths to scan (e.g. `"/,/about,/contact"`). Overrides auto-discovery entirely |
|
|
109
|
+
| `waitUntil` | `string` | `"domcontentloaded"` | `"domcontentloaded"` \| `"load"` \| `"networkidle"` | Page load strategy. Use `"networkidle"` for SPAs that render after `DOMContentLoaded` |
|
|
110
|
+
| `waitMs` | `number` | `2000` | 0 – 10000 | Fixed delay (ms) after page load before engines run |
|
|
111
|
+
| `timeoutMs` | `number` | `30000` | 5000 – 120000 | Network timeout per page (ms) |
|
|
112
|
+
| `headless` | `boolean` | `true` | — | Set `false` to open a visible browser for debugging |
|
|
113
|
+
| `viewport` | `object` | `{ width: 1280, height: 800 }` | width: 320–2560, height: 320–2560 | Browser viewport dimensions in pixels |
|
|
114
|
+
| `colorScheme` | `string` | `"light"` | `"light"` \| `"dark"` | Emulates `prefers-color-scheme` media query |
|
|
115
|
+
| `engines` | `object` | all `true` | `{ axe?, cdp?, pa11y? }` | Which engines to run. At least one must be enabled |
|
|
116
|
+
| `axeTags` | `string[]` | WCAG 2.x A+AA | See below | axe-core rule tag filter. Also determines pa11y standard |
|
|
117
|
+
| `onlyRule` | `string` | — | axe rule ID | Run a single axe rule only (e.g. `"color-contrast"`) |
|
|
118
|
+
| `ignoreFindings` | `string[]` | — | axe rule IDs | Suppress specific rules from output entirely |
|
|
119
|
+
| `excludeSelectors` | `string[]` | — | CSS selectors | Skip elements matching these selectors during axe scan |
|
|
120
|
+
| `framework` | `string` | auto-detected | See below | Override framework detection for fix notes and source boundaries |
|
|
121
|
+
| `projectDir` | `string` | — | local path | Local project source directory. Enables source pattern scanning and package.json stack detection |
|
|
122
|
+
| `repoUrl` | `string` | — | GitHub URL | Remote repo URL. Enables source pattern scanning via GitHub API — no clone required |
|
|
123
|
+
| `githubToken` | `string` | — | GitHub PAT | Increases GitHub API rate limit from 60 to 5,000 req/hr. Required for private repos |
|
|
124
|
+
| `skipPatterns` | `boolean` | `false` | — | Disable source pattern scanning even when `projectDir` or `repoUrl` is set |
|
|
125
|
+
| `screenshotsDir` | `string` | `.audit/screenshots` | dir path | Directory where element screenshots are saved |
|
|
126
|
+
| `ai.enabled` | `boolean` | `false` | — | Enable Claude AI enrichment for Critical and Serious findings |
|
|
127
|
+
| `ai.apiKey` | `string` | — | Anthropic API key | Required when `ai.enabled` is `true` |
|
|
128
|
+
| `ai.githubToken` | `string` | — | GitHub PAT | Used to fetch source files from the repo for AI context |
|
|
129
|
+
| `ai.model` | `string` | `"claude-haiku-4-5-20251001"` | Anthropic model ID | Claude model to use |
|
|
130
|
+
| `ai.systemPrompt` | `string` | Built-in prompt | — | Overrides the default Claude system prompt for the entire scan |
|
|
131
|
+
| `onProgress` | `function` | — | — | Callback fired at each pipeline step |
|
|
132
|
+
|
|
133
|
+
**`axeTags` common values:**
|
|
134
|
+
|
|
135
|
+
| Tag | Covers |
|
|
44
136
|
| :--- | :--- |
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
|
|
137
|
+
| `wcag2a` | WCAG 2.0 Level A |
|
|
138
|
+
| `wcag2aa` | WCAG 2.0 Level AA |
|
|
139
|
+
| `wcag21a` | WCAG 2.1 Level A additions |
|
|
140
|
+
| `wcag21aa` | WCAG 2.1 Level AA additions |
|
|
141
|
+
| `wcag22a` | WCAG 2.2 Level A additions |
|
|
142
|
+
| `wcag22aa` | WCAG 2.2 Level AA additions |
|
|
143
|
+
| `wcag2aaa` | WCAG 2.0 Level AAA |
|
|
144
|
+
| `best-practice` | Non-WCAG best practices |
|
|
145
|
+
|
|
146
|
+
**Supported `framework` values:** `nextjs`, `gatsby`, `react`, `nuxt`, `vue`, `angular`, `astro`, `svelte`, `remix`, `shopify`, `wordpress`, `drupal`
|
|
147
|
+
|
|
148
|
+
**`onProgress` callback:**
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
onProgress: (step, status, extra) => {
|
|
152
|
+
// step: "page" | "axe" | "cdp" | "pa11y" | "merge" | "intelligence" | "repo" | "patterns" | "ai"
|
|
153
|
+
// status: "running" | "done" | "error" | "skipped"
|
|
154
|
+
// extra: { found?: number, merged?: number, ... } — step-specific data
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
const payload = await runAudit({
|
|
160
|
+
baseUrl: "https://example.com",
|
|
161
|
+
maxRoutes: 5,
|
|
162
|
+
engines: { axe: true, cdp: true, pa11y: true },
|
|
163
|
+
repoUrl: "https://github.com/owner/repo",
|
|
164
|
+
githubToken: process.env.GH_TOKEN,
|
|
165
|
+
ai: { enabled: true, apiKey: process.env.ANTHROPIC_API_KEY },
|
|
166
|
+
onProgress: (step, status) => console.log(`[${step}] ${status}`),
|
|
167
|
+
});
|
|
168
|
+
```
|
|
54
169
|
|
|
55
170
|
Returns: `Promise<ScanPayload>`
|
|
56
171
|
|
|
57
|
-
|
|
172
|
+
> **`ai_enriched_findings` fast path**: When AI enrichment runs, `getFindings()` uses `payload.ai_enriched_findings` directly instead of re-normalizing the raw findings array.
|
|
58
173
|
|
|
59
|
-
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### `getFindings(input, options?)`
|
|
60
177
|
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
178
|
+
Normalizes raw scan results into enriched, UI-ready findings sorted by severity.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { getFindings } from "@diegovelasquezweb/a11y-engine";
|
|
182
|
+
|
|
183
|
+
const findings = getFindings(payload, {
|
|
184
|
+
// Optional: rewrite internal screenshot paths to app URLs
|
|
185
|
+
screenshotUrlBuilder: (rawPath) =>
|
|
186
|
+
`/api/scan/${scanId}/screenshot?path=${encodeURIComponent(rawPath)}`,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// findings[0] example:
|
|
190
|
+
// {
|
|
191
|
+
// id: "A11Y-001",
|
|
192
|
+
// ruleId: "color-contrast",
|
|
193
|
+
// title: "Elements must meet minimum color contrast ratio thresholds",
|
|
194
|
+
// severity: "Serious",
|
|
195
|
+
// wcag: "1.4.3",
|
|
196
|
+
// selector: ".hero-text",
|
|
197
|
+
// actual: "Element has insufficient color contrast of 2.5:1 ...",
|
|
198
|
+
// expected: "Text contrast ratio must be at least 4.5:1 ...",
|
|
199
|
+
// fixDescription: "Increase the foreground color contrast ...",
|
|
200
|
+
// fixCode: "/* Change #aaa to #767676 */",
|
|
201
|
+
// effort: "low",
|
|
202
|
+
// aiEnhanced: true, // present when AI ran
|
|
203
|
+
// aiFixDescription: "...", // Claude-generated (more specific)
|
|
204
|
+
// aiFixCode: "...", // Claude-generated code snippet
|
|
205
|
+
// }
|
|
206
|
+
```
|
|
64
207
|
|
|
65
208
|
Returns: `EnrichedFinding[]`
|
|
66
209
|
|
|
67
|
-
|
|
210
|
+
---
|
|
68
211
|
|
|
69
|
-
|
|
212
|
+
### `getOverview(findings, payload?)`
|
|
70
213
|
|
|
71
|
-
|
|
72
|
-
|
|
214
|
+
Computes the compliance score, WCAG status, severity totals, persona groups, and quick wins from enriched findings.
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
import { getFindings, getOverview } from "@diegovelasquezweb/a11y-engine";
|
|
218
|
+
|
|
219
|
+
const findings = getFindings(payload);
|
|
220
|
+
const overview = getOverview(findings, payload);
|
|
221
|
+
|
|
222
|
+
// overview example:
|
|
223
|
+
// {
|
|
224
|
+
// score: 72, // 0–100. Formula: 100 - (Critical×15) - (Serious×5) - (Moderate×2) - (Minor×0.5)
|
|
225
|
+
// label: "Fair", // "Excellent" (90–100) | "Good" (75–89) | "Fair" (55–74) | "Poor" (35–54) | "Critical" (0–34)
|
|
226
|
+
// wcagStatus: "Fail", // "Pass" | "Conditional Pass" | "Fail"
|
|
227
|
+
// totals: { Critical: 1, Serious: 3, Moderate: 5, Minor: 2 },
|
|
228
|
+
// personaGroups: {
|
|
229
|
+
// screenReader: { count: 4, findings: [...] },
|
|
230
|
+
// keyboard: { count: 2, findings: [...] },
|
|
231
|
+
// vision: { count: 3, findings: [...] },
|
|
232
|
+
// cognitive: { count: 1, findings: [...] },
|
|
233
|
+
// },
|
|
234
|
+
// quickWins: [...], // top Critical/Serious findings with fix code ready
|
|
235
|
+
// targetUrl: "https://example.com",
|
|
236
|
+
// detectedStack: { framework: "nextjs", cms: null, uiLibraries: ["radix-ui"] },
|
|
237
|
+
// }
|
|
238
|
+
```
|
|
73
239
|
|
|
74
240
|
Returns: `AuditSummary`
|
|
75
241
|
|
|
242
|
+
---
|
|
243
|
+
|
|
76
244
|
## Output API
|
|
77
245
|
|
|
78
246
|
### `getPDFReport(payload, options?)`
|
|
79
247
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
248
|
+
Generates a formal A4 PDF compliance report.
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
import { getPDFReport } from "@diegovelasquezweb/a11y-engine";
|
|
84
252
|
|
|
85
|
-
|
|
253
|
+
const { buffer, contentType } = await getPDFReport(payload, {
|
|
254
|
+
baseUrl: "https://example.com",
|
|
255
|
+
target: "WCAG 2.2 AA",
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// In a Next.js API route:
|
|
259
|
+
return new Response(buffer, { headers: { "Content-Type": contentType } });
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Returns: `Promise<{ buffer: Buffer, contentType: string }>`
|
|
263
|
+
|
|
264
|
+
---
|
|
86
265
|
|
|
87
266
|
### `getHTMLReport(payload, options?)`
|
|
88
267
|
|
|
89
|
-
|
|
90
|
-
- `options`: `HTMLReportOptions`
|
|
91
|
-
- `baseUrl?: string`
|
|
92
|
-
- `target?: string`
|
|
93
|
-
- `screenshotsDir?: string`
|
|
268
|
+
Generates an interactive HTML audit dashboard with finding cards, score gauge, and persona breakdown.
|
|
94
269
|
|
|
95
|
-
|
|
270
|
+
```ts
|
|
271
|
+
import { getHTMLReport } from "@diegovelasquezweb/a11y-engine";
|
|
272
|
+
|
|
273
|
+
const { html, contentType } = await getHTMLReport(payload, {
|
|
274
|
+
baseUrl: "https://example.com",
|
|
275
|
+
screenshotsDir: "/path/to/screenshots",
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Returns: `Promise<{ html: string, contentType: string }>`
|
|
280
|
+
|
|
281
|
+
---
|
|
96
282
|
|
|
97
283
|
### `getChecklist(options?)`
|
|
98
284
|
|
|
99
|
-
|
|
100
|
-
- `baseUrl?: string`
|
|
285
|
+
Generates an interactive HTML manual testing checklist with 41 WCAG checks.
|
|
101
286
|
|
|
102
|
-
|
|
287
|
+
```ts
|
|
288
|
+
import { getChecklist } from "@diegovelasquezweb/a11y-engine";
|
|
289
|
+
|
|
290
|
+
const { html, contentType } = await getChecklist({
|
|
291
|
+
baseUrl: "https://example.com",
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Returns: `Promise<{ html: string, contentType: string }>`
|
|
296
|
+
|
|
297
|
+
---
|
|
103
298
|
|
|
104
299
|
### `getRemediationGuide(payload, options?)`
|
|
105
300
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- `patternFindings?: Record<string, unknown> | null`
|
|
301
|
+
Generates a Markdown remediation guide optimized for AI agents and developers. Includes finding details, fix code, verify commands, and source pattern findings.
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
import { getRemediationGuide } from "@diegovelasquezweb/a11y-engine";
|
|
111
305
|
|
|
112
|
-
|
|
306
|
+
const { markdown, contentType } = await getRemediationGuide(payload, {
|
|
307
|
+
baseUrl: "https://example.com",
|
|
308
|
+
patternFindings: payload.patternFindings ?? null,
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Write to disk or return as download
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Returns: `Promise<{ markdown: string, contentType: string }>`
|
|
315
|
+
|
|
316
|
+
---
|
|
113
317
|
|
|
114
318
|
### `getSourcePatterns(projectDir, options?)`
|
|
115
319
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
320
|
+
Scans a local project directory for source code accessibility patterns that runtime engines cannot detect.
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
import { getSourcePatterns } from "@diegovelasquezweb/a11y-engine";
|
|
324
|
+
|
|
325
|
+
const result = await getSourcePatterns("./", {
|
|
326
|
+
framework: "nextjs", // optional — scopes scan to framework source dirs
|
|
327
|
+
onlyPattern: "placeholder-only-label", // optional — run a single pattern
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// result example:
|
|
331
|
+
// {
|
|
332
|
+
// findings: [
|
|
333
|
+
// {
|
|
334
|
+
// id: "PAT-a1b2c3",
|
|
335
|
+
// pattern_id: "placeholder-only-label",
|
|
336
|
+
// title: "Input uses placeholder as its only label",
|
|
337
|
+
// severity: "Critical",
|
|
338
|
+
// status: "confirmed",
|
|
339
|
+
// file: "src/components/SearchBar.tsx",
|
|
340
|
+
// line: 12,
|
|
341
|
+
// match: ' <input placeholder="Search..." />',
|
|
342
|
+
// context: "...",
|
|
343
|
+
// fix_description: "Add an aria-label or visible <label> element",
|
|
344
|
+
// }
|
|
345
|
+
// ],
|
|
346
|
+
// summary: { total: 3, confirmed: 2, potential: 1 }
|
|
347
|
+
// }
|
|
348
|
+
```
|
|
120
349
|
|
|
121
350
|
Returns: `Promise<SourcePatternResult>`
|
|
122
351
|
|
|
352
|
+
---
|
|
353
|
+
|
|
123
354
|
## Knowledge API
|
|
124
355
|
|
|
356
|
+
These functions expose engine-owned content for UIs and agents to render. All accept an optional `{ locale?: string }` option (default: `"en"`).
|
|
357
|
+
|
|
358
|
+
### `getKnowledge(options?)`
|
|
359
|
+
|
|
360
|
+
Returns the full knowledge pack — combines all knowledge functions into one call. Useful for pre-loading UI help content.
|
|
361
|
+
|
|
362
|
+
```ts
|
|
363
|
+
import { getKnowledge } from "@diegovelasquezweb/a11y-engine";
|
|
364
|
+
|
|
365
|
+
const knowledge = getKnowledge({ locale: "en" });
|
|
366
|
+
|
|
367
|
+
// knowledge.scanner → scan options help and engine descriptions
|
|
368
|
+
// knowledge.personas → persona labels, icons, descriptions
|
|
369
|
+
// knowledge.concepts → UI concept definitions
|
|
370
|
+
// knowledge.glossary → accessibility glossary
|
|
371
|
+
// knowledge.conformanceLevels → WCAG A/AA/AAA definitions with axe tags
|
|
372
|
+
// knowledge.wcagPrinciples → the 4 WCAG principles
|
|
373
|
+
// knowledge.severityLevels → Critical/Serious/Moderate/Minor definitions
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Returns: `EngineKnowledge`
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
125
380
|
### `getScannerHelp(options?)`
|
|
126
381
|
|
|
127
|
-
|
|
128
|
-
- `locale?: string`
|
|
382
|
+
Returns scan option descriptions, allowed values, and engine metadata — used to render Advanced Settings UI.
|
|
129
383
|
|
|
130
|
-
|
|
384
|
+
```ts
|
|
385
|
+
const help = getScannerHelp();
|
|
386
|
+
// help.engines → [{ id: "axe", label: "axe-core", description: "..." }, ...]
|
|
387
|
+
// help.options → [{ id: "maxRoutes", label: "Max Routes", type: "number", ... }, ...]
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
131
391
|
|
|
132
392
|
### `getPersonaReference(options?)`
|
|
133
393
|
|
|
134
|
-
|
|
135
|
-
- `locale?: string`
|
|
394
|
+
Returns persona labels, descriptions, and disability group definitions.
|
|
136
395
|
|
|
137
|
-
|
|
396
|
+
```ts
|
|
397
|
+
const ref = getPersonaReference();
|
|
398
|
+
// ref.personas → [{ id: "screenReader", label: "Screen Readers", icon: "...", description: "..." }, ...]
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
138
402
|
|
|
139
403
|
### `getUiHelp(options?)`
|
|
140
404
|
|
|
141
|
-
|
|
142
|
-
- `locale?: string`
|
|
405
|
+
Returns shared concept definitions and a glossary of accessibility terms.
|
|
143
406
|
|
|
144
|
-
|
|
407
|
+
```ts
|
|
408
|
+
const ui = getUiHelp();
|
|
409
|
+
// ui.concepts → { wcag: "...", aria: "...", ... }
|
|
410
|
+
// ui.glossary → [{ term: "ARIA", definition: "..." }, ...]
|
|
411
|
+
```
|
|
145
412
|
|
|
146
|
-
|
|
413
|
+
---
|
|
147
414
|
|
|
148
|
-
|
|
149
|
-
- `locale?: string`
|
|
415
|
+
### `getConformanceLevels(options?)`
|
|
150
416
|
|
|
151
|
-
Returns
|
|
417
|
+
Returns WCAG conformance level definitions with their corresponding axe-core tag sets.
|
|
152
418
|
|
|
153
|
-
|
|
419
|
+
```ts
|
|
420
|
+
const { conformanceLevels } = getConformanceLevels();
|
|
421
|
+
// conformanceLevels[0] → { id: "AA", label: "WCAG 2.2 AA", axeTags: ["wcag2a", "wcag2aa", ...] }
|
|
422
|
+
```
|
|
154
423
|
|
|
155
|
-
|
|
156
|
-
- `locale?: string`
|
|
424
|
+
---
|
|
157
425
|
|
|
158
|
-
|
|
426
|
+
### `getWcagPrinciples(options?)`
|
|
159
427
|
|
|
160
|
-
|
|
428
|
+
Returns the four WCAG principles (Perceivable, Operable, Understandable, Robust) with criterion prefix patterns.
|
|
161
429
|
|
|
162
|
-
|
|
163
|
-
|
|
430
|
+
```ts
|
|
431
|
+
const { wcagPrinciples } = getWcagPrinciples();
|
|
432
|
+
// wcagPrinciples[0] → { id: "perceivable", label: "Perceivable", prefix: "1.", description: "..." }
|
|
433
|
+
```
|
|
164
434
|
|
|
165
|
-
|
|
435
|
+
---
|
|
166
436
|
|
|
167
|
-
### `
|
|
437
|
+
### `getSeverityLevels(options?)`
|
|
168
438
|
|
|
169
|
-
|
|
170
|
-
- `locale?: string`
|
|
439
|
+
Returns severity level definitions with labels, descriptions, and ordering.
|
|
171
440
|
|
|
172
|
-
|
|
441
|
+
```ts
|
|
442
|
+
const { severityLevels } = getSeverityLevels();
|
|
443
|
+
// severityLevels[0] → { id: "Critical", label: "Critical", order: 0, description: "..." }
|
|
444
|
+
```
|
|
173
445
|
|
|
174
446
|
---
|
|
175
447
|
|
package/docs/architecture.md
CHANGED
|
@@ -33,12 +33,21 @@ flowchart TD
|
|
|
33
33
|
|
|
34
34
|
M --> R[a11y-scan-results.json]
|
|
35
35
|
R --> AN[Analyzer]
|
|
36
|
-
AN --> F[a11y-findings.json]
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
REPO[GitHub Repo] -->|fetchPackageJson| AN
|
|
38
|
+
REPO -->|scanPatternRemote| PAT[a11y-pattern-findings.json]
|
|
39
|
+
|
|
40
|
+
AN --> F[a11y-findings.json]
|
|
41
|
+
F --> AI{ANTHROPIC_API_KEY?}
|
|
42
|
+
AI -->|yes| CL[Claude AI enrichment]
|
|
43
|
+
AI -->|no| SKIP[skip]
|
|
44
|
+
CL --> F2[a11y-findings.json enriched]
|
|
45
|
+
SKIP --> F2
|
|
46
|
+
|
|
47
|
+
F2 --> MD[remediation.md]
|
|
48
|
+
F2 --> HTML[report.html]
|
|
49
|
+
F2 --> PDF[report.pdf]
|
|
50
|
+
F2 --> CHK[checklist.html]
|
|
42
51
|
```
|
|
43
52
|
|
|
44
53
|
## Execution Modes
|
|
@@ -75,7 +84,10 @@ flowchart LR
|
|
|
75
84
|
| :--- | :--- |
|
|
76
85
|
| `src/pipeline/dom-scanner.mjs` | Route discovery, engine execution (axe/CDP/pa11y), merge/dedup, progress updates, screenshots |
|
|
77
86
|
| `src/enrichment/analyzer.mjs` | Rule enrichment, selector strategy, ownership hints, recommendations, scoring metadata |
|
|
78
|
-
| `src/
|
|
87
|
+
| `src/ai/enrich.mjs` | CLI subprocess that runs AI enrichment after the analyzer. Reads `ANTHROPIC_API_KEY` and `AI_SYSTEM_PROMPT` env vars. Non-fatal. |
|
|
88
|
+
| `src/ai/claude.mjs` | Anthropic API client. Sends Critical/Serious findings to Claude and parses improved fix suggestions. Supports custom system prompt and repo source file context. |
|
|
89
|
+
| `src/core/github-api.mjs` | GitHub API client. Provides `fetchPackageJson`, `fetchRepoFile`, `listRepoFiles`, and `parseRepoUrl`. Used for remote repo scanning and AI source file fetching without cloning. |
|
|
90
|
+
| `src/source-patterns/source-scanner.mjs` | Source code pattern scanner. Works against local `--project-dir` or remote `--repo-url` via the GitHub API. |
|
|
79
91
|
| `src/reports/*.mjs` | Report builders for markdown/html/pdf/checklist |
|
|
80
92
|
| `src/reports/renderers/*.mjs` | Shared rendering and normalization helpers |
|
|
81
93
|
| `src/core/asset-loader.mjs` | Centralized access to bundled assets |
|
package/docs/cli-handbook.md
CHANGED
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
- [Prerequisites](#prerequisites)
|
|
11
11
|
- [Flag groups](#flag-groups)
|
|
12
12
|
- [Targeting & scope](#targeting--scope)
|
|
13
|
+
- [Repository & remote scanning](#repository--remote-scanning)
|
|
14
|
+
- [AI enrichment](#ai-enrichment)
|
|
13
15
|
- [Audit intelligence](#audit-intelligence)
|
|
14
16
|
- [Execution & emulation](#execution--emulation)
|
|
15
17
|
- [Output generation](#output-generation)
|
|
18
|
+
- [Environment variables](#environment-variables)
|
|
16
19
|
- [Examples](#examples)
|
|
17
20
|
- [Exit codes](#exit-codes)
|
|
18
21
|
|
|
@@ -62,7 +65,7 @@ Controls what gets scanned.
|
|
|
62
65
|
| `--max-routes` | `<num>` | `10` | Maximum unique same-origin paths to discover and scan. |
|
|
63
66
|
| `--crawl-depth` | `<num>` | `2` | How deep to follow links during BFS discovery (1-3). Has no effect when `--routes` is set. |
|
|
64
67
|
| `--routes` | `<csv>` | — | Explicit paths to scan (e.g. `/,/about,/contact`). Overrides auto-discovery entirely. |
|
|
65
|
-
| `--project-dir` | `<path>` | — | Path to the audited project source. Enables
|
|
68
|
+
| `--project-dir` | `<path>` | — | Path to the audited project source on disk. Enables source code pattern scanning and framework auto-detection from the local `package.json`. |
|
|
66
69
|
|
|
67
70
|
**Route discovery logic**:
|
|
68
71
|
1. If the target has a `sitemap.xml`, all listed URLs are used (up to `--max-routes`).
|
|
@@ -71,6 +74,41 @@ Controls what gets scanned.
|
|
|
71
74
|
|
|
72
75
|
---
|
|
73
76
|
|
|
77
|
+
### Repository & remote scanning
|
|
78
|
+
|
|
79
|
+
Enables source code analysis via the GitHub API — no `git clone` required.
|
|
80
|
+
|
|
81
|
+
| Flag | Argument | Default | Description |
|
|
82
|
+
| :--- | :--- | :--- | :--- |
|
|
83
|
+
| `--repo-url` | `<url>` | — | GitHub repository URL (e.g. `https://github.com/owner/repo`). Fetches `package.json` for framework detection and runs source code pattern scanning against the repo via the GitHub API. Mutually exclusive with `--project-dir` for remote usage. |
|
|
84
|
+
| `--github-token` | `<token>` | — | GitHub personal access token. Increases the GitHub API rate limit from 60 to 5,000 req/hour. Required for private repositories. Falls back to `GH_TOKEN` env var if not provided. |
|
|
85
|
+
|
|
86
|
+
When `--repo-url` is provided:
|
|
87
|
+
1. The engine fetches `package.json` via `raw.githubusercontent.com` to detect the project framework.
|
|
88
|
+
2. Source code patterns are run against the repo file tree using the GitHub Trees API and Contents API, with no local filesystem access.
|
|
89
|
+
3. The detected framework is passed to the analyzer for framework-specific fix notes.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### AI enrichment
|
|
94
|
+
|
|
95
|
+
Controls Claude-powered fix suggestion enrichment. Requires `ANTHROPIC_API_KEY` to be set.
|
|
96
|
+
|
|
97
|
+
| Flag | Argument | Default | Description |
|
|
98
|
+
| :--- | :--- | :--- | :--- |
|
|
99
|
+
| *(no flag)* | — | — | AI enrichment is activated automatically when `ANTHROPIC_API_KEY` env var is present. There is no `--ai-enabled` flag — set or unset the env var to control it. |
|
|
100
|
+
|
|
101
|
+
AI enrichment runs after the analyzer step and enriches Critical and Serious findings (up to 20 per scan) with:
|
|
102
|
+
- A specific fix description referencing the actual selector, colors, and violation data
|
|
103
|
+
- A production-quality code snippet in the correct framework syntax
|
|
104
|
+
- Context-aware suggestions when repo source files are available via `--repo-url`
|
|
105
|
+
|
|
106
|
+
Original engine fixes are always preserved. AI output is stored in separate fields (`ai_fix_description`, `ai_fix_code`). Enriched findings are flagged with `aiEnhanced: true`.
|
|
107
|
+
|
|
108
|
+
The system prompt is customizable via `AI_SYSTEM_PROMPT` env var.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
74
112
|
### Audit intelligence
|
|
75
113
|
|
|
76
114
|
Controls how findings are interpreted and filtered.
|
|
@@ -117,6 +155,16 @@ Controls what artifacts are written.
|
|
|
117
155
|
|
|
118
156
|
---
|
|
119
157
|
|
|
158
|
+
## Environment variables
|
|
159
|
+
|
|
160
|
+
| Variable | Description |
|
|
161
|
+
| :--- | :--- |
|
|
162
|
+
| `ANTHROPIC_API_KEY` | Enables Claude AI enrichment. Set to a valid Anthropic API key. When absent, AI enrichment is silently skipped. |
|
|
163
|
+
| `AI_SYSTEM_PROMPT` | Custom system prompt for Claude. Overrides the default prompt for the entire scan. Useful for domain-specific fix guidance or custom output formats. |
|
|
164
|
+
| `GH_TOKEN` | GitHub personal access token. Used by the AI enrichment step when fetching source files from the repo. Equivalent to `--github-token` but read from the environment. |
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
120
168
|
## Examples
|
|
121
169
|
|
|
122
170
|
### Minimal scan
|
|
@@ -135,7 +183,7 @@ a11y-audit \
|
|
|
135
183
|
--output ./audit/report.html
|
|
136
184
|
```
|
|
137
185
|
|
|
138
|
-
### Include source code intelligence
|
|
186
|
+
### Include source code intelligence (local)
|
|
139
187
|
|
|
140
188
|
```bash
|
|
141
189
|
a11y-audit \
|
|
@@ -145,6 +193,32 @@ a11y-audit \
|
|
|
145
193
|
--output ./audit/report.html
|
|
146
194
|
```
|
|
147
195
|
|
|
196
|
+
### Scan with remote GitHub repository (no clone)
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
a11y-audit \
|
|
200
|
+
--base-url https://example.com \
|
|
201
|
+
--repo-url https://github.com/owner/repo \
|
|
202
|
+
--github-token ghp_...
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Scan with AI enrichment
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
ANTHROPIC_API_KEY=sk-ant-... a11y-audit \
|
|
209
|
+
--base-url https://example.com \
|
|
210
|
+
--repo-url https://github.com/owner/repo \
|
|
211
|
+
--github-token ghp_...
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Scan with custom AI system prompt
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
AI_SYSTEM_PROMPT="You are an expert in Vue.js accessibility. Focus on component-level fixes." \
|
|
218
|
+
ANTHROPIC_API_KEY=sk-ant-... \
|
|
219
|
+
a11y-audit --base-url https://example.com --repo-url https://github.com/owner/repo
|
|
220
|
+
```
|
|
221
|
+
|
|
148
222
|
### Focused re-audit — single rule, single route
|
|
149
223
|
|
|
150
224
|
```bash
|
package/docs/engine-manifest.md
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Source Modules](#1-source-modules)
|
|
10
|
+
- [Asset Modules](#2-asset-modules)
|
|
11
|
+
- [Test Suite](#3-test-suite)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
7
15
|
This document is the current technical inventory of the engine package.
|
|
8
16
|
|
|
9
17
|
## 1) Source Modules
|
|
@@ -16,9 +24,12 @@ This document is the current technical inventory of the engine package.
|
|
|
16
24
|
| `src/core/utils.mjs` | Logging, JSON I/O, shared helpers |
|
|
17
25
|
| `src/core/asset-loader.mjs` | Centralized asset map and loader |
|
|
18
26
|
| `src/core/toolchain.mjs` | Environment/toolchain checks |
|
|
27
|
+
| `src/core/github-api.mjs` | GitHub API client — `fetchPackageJson`, `fetchRepoFile`, `listRepoFiles`, `parseRepoUrl`. Used for remote repo scanning and AI source file fetching. |
|
|
19
28
|
| `src/pipeline/dom-scanner.mjs` | Runtime scan stage (axe/CDP/pa11y + merge) |
|
|
20
29
|
| `src/enrichment/analyzer.mjs` | Finding enrichment and metadata synthesis |
|
|
21
|
-
| `src/
|
|
30
|
+
| `src/ai/claude.mjs` | Claude AI client — calls the Anthropic API to enrich findings with context-aware fix suggestions. Accepts custom system prompt via `options.systemPrompt`. |
|
|
31
|
+
| `src/ai/enrich.mjs` | CLI AI enrichment subprocess — reads `a11y-findings.json`, calls `enrichWithAI()`, writes enriched findings back. Activated by `ANTHROPIC_API_KEY` env var. |
|
|
32
|
+
| `src/source-patterns/source-scanner.mjs` | Source code pattern scanner — works with local `--project-dir` or remote `--repo-url` via GitHub API |
|
|
22
33
|
| `src/reports/html.mjs` | HTML report builder |
|
|
23
34
|
| `src/reports/pdf.mjs` | PDF report builder |
|
|
24
35
|
| `src/reports/md.mjs` | Markdown remediation builder |
|
package/docs/intelligence.md
CHANGED
|
@@ -152,8 +152,22 @@ A single finding can match multiple personas. The persona configuration (`person
|
|
|
152
152
|
The compliance score is computed from severity totals using weights defined in `assets/reporting/compliance-config.mjs`:
|
|
153
153
|
|
|
154
154
|
1. **Severity totals** — counts findings by `Critical`, `Serious`, `Moderate`, `Minor` (excluding AAA and Best Practice findings).
|
|
155
|
-
2. **Score** — starts at 100, deducts weighted points per finding
|
|
156
|
-
|
|
155
|
+
2. **Score** — starts at 100, deducts weighted points per finding:
|
|
156
|
+
- Critical: −15 per finding
|
|
157
|
+
- Serious: −5 per finding
|
|
158
|
+
- Moderate: −2 per finding
|
|
159
|
+
- Minor: −0.5 per finding
|
|
160
|
+
- Score is clamped to 0–100 and rounded to nearest integer.
|
|
161
|
+
3. **Label** — maps score ranges to grades:
|
|
162
|
+
|
|
163
|
+
| Score | Label |
|
|
164
|
+
| :--- | :--- |
|
|
165
|
+
| 90 – 100 | `Excellent` |
|
|
166
|
+
| 75 – 89 | `Good` |
|
|
167
|
+
| 55 – 74 | `Fair` |
|
|
168
|
+
| 35 – 54 | `Poor` |
|
|
169
|
+
| 0 – 34 | `Critical` |
|
|
170
|
+
|
|
157
171
|
4. **WCAG status** — `Pass` (no findings), `Conditional Pass` (only Moderate/Minor), or `Fail` (any Critical/Serious).
|
|
158
172
|
|
|
159
173
|
The `overallAssessment` in metadata follows the same logic for the formal compliance verdict.
|
|
@@ -187,14 +201,54 @@ The source scanner (`src/source-patterns/source-scanner.mjs`) detects accessibil
|
|
|
187
201
|
|
|
188
202
|
5. Output includes a summary with `total`, `confirmed`, and `potential` counts.
|
|
189
203
|
|
|
204
|
+
### Remote scanning via GitHub API
|
|
205
|
+
|
|
206
|
+
When `--repo-url` (CLI) or `options.repoUrl` (programmatic API) is provided instead of `--project-dir`, the source scanner uses the GitHub API — no `git clone` required:
|
|
207
|
+
|
|
208
|
+
1. `listRepoFiles()` fetches the repo file tree using the GitHub Trees API. Falls back to the Contents API for truncated responses (large repos).
|
|
209
|
+
2. Files matching each pattern's `globs` are fetched individually via `raw.githubusercontent.com`.
|
|
210
|
+
3. The same regex and context rejection logic runs against the fetched content.
|
|
211
|
+
4. Results are identical to local scanning.
|
|
212
|
+
|
|
213
|
+
A GitHub token (`--github-token` or `GH_TOKEN` env var) increases the API rate limit from 60 to 5,000 req/hour and enables private repo access.
|
|
214
|
+
|
|
190
215
|
### Integration with the audit pipeline
|
|
191
216
|
|
|
192
|
-
When `runAudit` is called with `projectDir` and without `skipPatterns`:
|
|
217
|
+
When `runAudit` is called with `projectDir` or `repoUrl` and without `skipPatterns`:
|
|
218
|
+
|
|
219
|
+
1. The engine fetches `package.json` from the repo (remote) or reads it from disk (local) to detect the framework before the analyzer runs.
|
|
220
|
+
2. The analyzer runs with the detected framework context.
|
|
221
|
+
3. Source patterns run after enrichment.
|
|
222
|
+
4. Pattern findings are attached to the payload as `patternFindings` with their own `generated_at`, `project_dir`, `findings`, and `summary`.
|
|
223
|
+
5. The remediation guide (`getRemediationGuide`) renders pattern findings in a dedicated section.
|
|
224
|
+
|
|
225
|
+
### pa11y ruleId normalization
|
|
226
|
+
|
|
227
|
+
pa11y reports violations using dotted WCAG criterion codes (e.g. `WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail`). The engine normalizes these in two places:
|
|
228
|
+
|
|
229
|
+
1. **Equivalence mapping** (`assets/scanning/pa11y-config.mjs`, `equivalenceMap`) — known pa11y codes are mapped to their axe-core equivalent rule ID (e.g. `Principle1.Guideline1_4.1_4_3.G145` → `color-contrast`). These findings are merged and deduplicated with axe findings.
|
|
230
|
+
|
|
231
|
+
2. **Fallback normalization** (`src/pipeline/dom-scanner.mjs`) — pa11y codes without an axe equivalent are shortened to their last segment (e.g. `WCAG2AAA.Principle1.Guideline1_4.1_4_6.G17` → `pa11y-g17`). This produces a readable rule ID without the full dotted path.
|
|
232
|
+
|
|
233
|
+
## AI Enrichment
|
|
234
|
+
|
|
235
|
+
After the analyzer step, the engine optionally runs Claude-powered enrichment on Critical and Serious findings (up to 20 per scan).
|
|
236
|
+
|
|
237
|
+
### How it works
|
|
238
|
+
|
|
239
|
+
1. `src/ai/enrich.mjs` reads `a11y-findings.json`, identifies Critical and Serious findings, and sends them to `enrichWithAI()`.
|
|
240
|
+
2. `src/ai/claude.mjs` calls the Anthropic API with a system prompt instructing Claude to generate specific, production-quality fix suggestions using the actual violation data (selector, colors, ratio, etc.).
|
|
241
|
+
3. When a repo URL is available (`A11Y_REPO_URL` env var), Claude also receives relevant source files fetched via the GitHub API. File selection is scored by how well each file path matches terms extracted from the finding's selector and title.
|
|
242
|
+
4. Claude returns a JSON array of improvements. Each improvement contains a `fixDescription` and `fixCode` specific to the finding's context.
|
|
243
|
+
5. The engine stores Claude's output in separate fields (`ai_fix_description`, `ai_fix_code`, `ai_fix_code_lang`) — the original engine fixes are preserved unchanged. Improved findings are flagged with `aiEnhanced: true`.
|
|
244
|
+
|
|
245
|
+
### Activation
|
|
246
|
+
|
|
247
|
+
AI enrichment runs automatically when `ANTHROPIC_API_KEY` is present in the environment. It is non-fatal — if the API call fails, the pipeline continues with unenriched findings.
|
|
248
|
+
|
|
249
|
+
### Custom system prompt
|
|
193
250
|
|
|
194
|
-
|
|
195
|
-
2. Source patterns run after enrichment.
|
|
196
|
-
3. Pattern findings are attached to the payload as `patternFindings` with their own `generated_at`, `project_dir`, `findings`, and `summary`.
|
|
197
|
-
4. The remediation guide (`getRemediationGuide`) renders pattern findings in a dedicated section.
|
|
251
|
+
The default system prompt instructs Claude to go beyond the generic fix: explain why the issue matters for users, reference the specific selector and violation data, and provide a more complete code example than the engine's default. The prompt can be overridden per-scan via the `AI_SYSTEM_PROMPT` env var or `options.ai.systemPrompt` in the programmatic API.
|
|
198
252
|
|
|
199
253
|
## Assets Reference
|
|
200
254
|
|
package/docs/outputs.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- [progress.json](#progressjson)
|
|
11
11
|
- [a11y-scan-results.json](#a11y-scan-resultsjson)
|
|
12
12
|
- [a11y-findings.json](#a11y-findingsjson)
|
|
13
|
+
- [a11y-pattern-findings.json](#a11y-pattern-findingsjson)
|
|
13
14
|
- [remediation.md](#remediationmd)
|
|
14
15
|
- [report.html](#reporthtml)
|
|
15
16
|
- [report.pdf](#reportpdf)
|
|
@@ -90,7 +91,7 @@ Merged results from all three engines (axe-core + CDP + pa11y) per route. Writte
|
|
|
90
91
|
}
|
|
91
92
|
```
|
|
92
93
|
|
|
93
|
-
Each violation in the `violations` array includes a `source` field
|
|
94
|
+
Each violation in the `violations` array includes a `source` field: `"cdp"` for CDP checks, `"pa11y"` for pa11y, and absent (field not set) for axe-core violations.
|
|
94
95
|
|
|
95
96
|
This file is consumed by `analyzer.mjs` and also used by `--affected-only` to determine which routes to re-scan on subsequent runs.
|
|
96
97
|
|
|
@@ -176,6 +177,25 @@ The primary enriched data artifact. Written by `src/enrichment/analyzer.mjs`. Th
|
|
|
176
177
|
| `verification_command_fallback` | `string\|null` | Fallback verify command |
|
|
177
178
|
| `pages_affected` | `number\|null` | Number of pages with this violation |
|
|
178
179
|
| `affected_urls` | `string[]\|null` | All URLs where this violation appears |
|
|
180
|
+
| `aiEnhanced` | `boolean` | `true` when Claude improved the fix for this finding. Only present on AI-enriched findings. |
|
|
181
|
+
| `ai_fix_description` | `string\|null` | Claude-generated fix description. More specific than `fix_description` — references the actual selector, colors, and violation data. Only present when `aiEnhanced` is `true`. |
|
|
182
|
+
| `ai_fix_code` | `string\|null` | Claude-generated code snippet in the correct framework syntax. Separate from the engine's `fix_code`. Only present when `aiEnhanced` is `true`. |
|
|
183
|
+
| `ai_fix_code_lang` | `string\|null` | Language of `ai_fix_code` (e.g. `jsx`, `tsx`, `vue`, `css`). Only present when `aiEnhanced` is `true`. |
|
|
184
|
+
|
|
185
|
+
> **Note on `ownership_status`**: Values are `"primary"` (issue is in the project's source), `"outside_primary_source"` (issue is in a third-party component), or `"unknown"`. These are different from the pattern finding `status` field which uses `"confirmed"` and `"potential"`.
|
|
186
|
+
|
|
187
|
+
### Top-level payload keys (after AI enrichment)
|
|
188
|
+
|
|
189
|
+
When AI enrichment runs, the engine appends `ai_enriched_findings` to the payload root. `getFindings()` uses this as a fast path — if present, it returns `ai_enriched_findings` directly without re-normalizing the raw `findings` array.
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"metadata": { ... },
|
|
194
|
+
"findings": [ ... ],
|
|
195
|
+
"ai_enriched_findings": [ ... ],
|
|
196
|
+
"incomplete_findings": [ ... ]
|
|
197
|
+
}
|
|
198
|
+
```
|
|
179
199
|
|
|
180
200
|
### `incomplete_findings`
|
|
181
201
|
|
|
@@ -183,6 +203,45 @@ Violations that axe-core flagged as "needs review" (not confirmed pass or fail).
|
|
|
183
203
|
|
|
184
204
|
---
|
|
185
205
|
|
|
206
|
+
## a11y-pattern-findings.json
|
|
207
|
+
|
|
208
|
+
Source code pattern scan results. Written by `src/source-patterns/source-scanner.mjs` when `--project-dir` or `--repo-url` is provided (and `--skip-patterns` is not set).
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"generated_at": "2026-03-16T00:00:00.000Z",
|
|
213
|
+
"project_dir": "https://github.com/owner/repo",
|
|
214
|
+
"findings": [ ... ],
|
|
215
|
+
"summary": {
|
|
216
|
+
"total": 5,
|
|
217
|
+
"confirmed": 3,
|
|
218
|
+
"potential": 2
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Per-finding fields
|
|
224
|
+
|
|
225
|
+
| Field | Type | Description |
|
|
226
|
+
| :--- | :--- | :--- |
|
|
227
|
+
| `id` | `string` | Deterministic finding ID |
|
|
228
|
+
| `pattern_id` | `string` | Pattern definition ID (e.g. `placeholder-only-label`) |
|
|
229
|
+
| `title` | `string` | Pattern title |
|
|
230
|
+
| `severity` | `string` | `Critical`, `Serious`, `Moderate`, or `Minor` |
|
|
231
|
+
| `wcag` | `string` | WCAG success criterion string |
|
|
232
|
+
| `wcag_criterion` | `string` | WCAG criterion ID |
|
|
233
|
+
| `wcag_level` | `string` | `A`, `AA`, or `AAA` |
|
|
234
|
+
| `type` | `string` | Pattern type (`structural`, `css`, etc.) |
|
|
235
|
+
| `fix_description` | `string\|null` | How to fix this pattern |
|
|
236
|
+
| `status` | `string` | `confirmed` (regex match without reject context) or `potential` (match with uncertainty) |
|
|
237
|
+
| `file` | `string` | File path within the repo (e.g. `src/components/Button.tsx`) |
|
|
238
|
+
| `line` | `number` | Line number of the match |
|
|
239
|
+
| `match` | `string` | The matched line content |
|
|
240
|
+
| `context` | `string` | 7-line code context window around the match |
|
|
241
|
+
| `source` | `string` | Always `"code-pattern"` |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
186
245
|
## remediation.md
|
|
187
246
|
|
|
188
247
|
AI agent-optimized remediation guide. Always generated (even without `--with-reports`). Written to `.audit/remediation.md`.
|
package/package.json
CHANGED
package/src/ai/claude.mjs
CHANGED
|
@@ -25,18 +25,10 @@ const MAX_AI_FINDINGS = 20; // cap to control cost
|
|
|
25
25
|
* @param {object} context
|
|
26
26
|
* @returns {string}
|
|
27
27
|
*/
|
|
28
|
-
|
|
29
|
-
const { framework, cms, uiLibraries } = context.stack || {};
|
|
30
|
-
|
|
31
|
-
let stackInfo = "";
|
|
32
|
-
if (framework) stackInfo += `Framework: ${framework}\n`;
|
|
33
|
-
if (cms) stackInfo += `CMS: ${cms}\n`;
|
|
34
|
-
if (uiLibraries?.length) stackInfo += `UI Libraries: ${uiLibraries.join(", ")}\n`;
|
|
35
|
-
|
|
36
|
-
return `You are an expert web accessibility engineer specializing in WCAG 2.2 AA remediation.
|
|
28
|
+
export const DEFAULT_AI_SYSTEM_PROMPT = `You are an expert web accessibility engineer specializing in WCAG 2.2 AA remediation.
|
|
37
29
|
|
|
38
30
|
Your task is to provide a developer-friendly AI hint for each accessibility finding — something MORE USEFUL than the generic automated fix already provided.
|
|
39
|
-
|
|
31
|
+
|
|
40
32
|
For each finding, provide:
|
|
41
33
|
1. fixDescription: A 2-3 sentence explanation that goes BEYOND the generic fix. Explain WHY this matters for real users, WHAT specifically to look for in the codebase, and HOW to verify the fix works. Be specific to the selector and actual violation data provided.
|
|
42
34
|
2. fixCode: A ready-to-use, production-quality code snippet in the correct syntax for the stack. Do NOT copy the existing fix code — write a BETTER, more complete example that a developer can use directly.
|
|
@@ -48,6 +40,20 @@ Rules:
|
|
|
48
40
|
- Reference the actual selector or element from the finding when possible
|
|
49
41
|
- If the violation data contains specific values (colors, ratios, labels), use them in your response
|
|
50
42
|
- Respond in JSON only — no markdown, no explanation outside the JSON structure`;
|
|
43
|
+
|
|
44
|
+
function buildSystemPrompt(context) {
|
|
45
|
+
const { framework, cms, uiLibraries } = context.stack || {};
|
|
46
|
+
|
|
47
|
+
let stackInfo = "";
|
|
48
|
+
if (framework) stackInfo += `Framework: ${framework}\n`;
|
|
49
|
+
if (cms) stackInfo += `CMS: ${cms}\n`;
|
|
50
|
+
if (uiLibraries?.length) stackInfo += `UI Libraries: ${uiLibraries.join(", ")}\n`;
|
|
51
|
+
|
|
52
|
+
const base = DEFAULT_AI_SYSTEM_PROMPT;
|
|
53
|
+
return stackInfo ? base.replace(
|
|
54
|
+
"For each finding, provide:",
|
|
55
|
+
`Project context:\n${stackInfo}\nFor each finding, provide:`
|
|
56
|
+
) : base;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
/**
|
|
@@ -856,8 +856,10 @@ function buildFindings(inputPayload, cliArgs) {
|
|
|
856
856
|
selector: selectors.join(", "),
|
|
857
857
|
impacted_users: getImpactedUsers(v.id, v.tags),
|
|
858
858
|
primary_selector: bestSelector,
|
|
859
|
-
actual:
|
|
860
|
-
firstNode?.failureSummary || `Found ${nodes.length} instance(s)
|
|
859
|
+
actual: (() => {
|
|
860
|
+
const raw = firstNode?.failureSummary || `Found ${nodes.length} instance(s).`;
|
|
861
|
+
return raw.replace(/^Fix any of the following:\s*/i, "").trim();
|
|
862
|
+
})(),
|
|
861
863
|
primary_failure_mode: failureInsights.primaryFailureMode,
|
|
862
864
|
relationship_hint: failureInsights.relationshipHint,
|
|
863
865
|
failure_checks: failureInsights.failureChecks,
|
package/src/index.d.mts
CHANGED
|
@@ -403,15 +403,6 @@ export interface RunAuditOptions {
|
|
|
403
403
|
onProgress?: (step: string, status: string, extra?: Record<string, unknown>) => void;
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
-
export interface AiOptions {
|
|
407
|
-
enabled?: boolean;
|
|
408
|
-
apiKey?: string;
|
|
409
|
-
githubToken?: string;
|
|
410
|
-
model?: string;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
406
|
|
|
416
407
|
|
|
417
408
|
export interface EnrichmentOptions {
|
|
@@ -471,3 +462,21 @@ export function getWcagPrinciples(options?: KnowledgeOptions): WcagPrinciplesRes
|
|
|
471
462
|
export function getSeverityLevels(options?: KnowledgeOptions): SeverityLevelsResult;
|
|
472
463
|
|
|
473
464
|
export function getKnowledge(options?: KnowledgeOptions): EngineKnowledge;
|
|
465
|
+
|
|
466
|
+
export const DEFAULT_AI_SYSTEM_PROMPT: string;
|
|
467
|
+
|
|
468
|
+
export interface ViewportPreset {
|
|
469
|
+
label: string;
|
|
470
|
+
width: number;
|
|
471
|
+
height: number;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export const VIEWPORT_PRESETS: ViewportPreset[];
|
|
475
|
+
|
|
476
|
+
export interface AiOptions {
|
|
477
|
+
enabled?: boolean;
|
|
478
|
+
apiKey?: string;
|
|
479
|
+
githubToken?: string;
|
|
480
|
+
model?: string;
|
|
481
|
+
systemPrompt?: string;
|
|
482
|
+
}
|
package/src/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { ASSET_PATHS, loadAssetJson } from "./core/asset-loader.mjs";
|
|
8
|
+
export { DEFAULT_AI_SYSTEM_PROMPT } from "./ai/claude.mjs";
|
|
8
9
|
|
|
9
10
|
// ---------------------------------------------------------------------------
|
|
10
11
|
// Lazy-loaded asset cache
|
|
@@ -238,7 +239,7 @@ export function getFindings(input, options = {}) {
|
|
|
238
239
|
recommendedFix: finding.recommended_fix,
|
|
239
240
|
evidence: finding.evidence,
|
|
240
241
|
totalInstances: finding.total_instances,
|
|
241
|
-
effort: finding.effort,
|
|
242
|
+
effort: finding.effort ?? (finding.fix_code ? "low" : "high"),
|
|
242
243
|
relatedRules: finding.related_rules,
|
|
243
244
|
screenshotPath: finding.screenshot_path,
|
|
244
245
|
falsePositiveRisk: finding.false_positive_risk,
|
|
@@ -583,6 +584,13 @@ export function getSeverityLevels(options = {}) {
|
|
|
583
584
|
};
|
|
584
585
|
}
|
|
585
586
|
|
|
587
|
+
export const VIEWPORT_PRESETS = [
|
|
588
|
+
{ label: "Desktop", width: 1280, height: 800 },
|
|
589
|
+
{ label: "Laptop", width: 1440, height: 900 },
|
|
590
|
+
{ label: "Tablet", width: 768, height: 1024 },
|
|
591
|
+
{ label: "Mobile", width: 375, height: 812 },
|
|
592
|
+
];
|
|
593
|
+
|
|
586
594
|
export function getKnowledge(options = {}) {
|
|
587
595
|
const scanner = getScannerHelp(options);
|
|
588
596
|
const personas = getPersonaReference(options);
|