mcp-accessibility-scanner 2.0.5 → 2.0.6
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 +41 -1
- package/lib/tools/auditKeyboard.js +296 -0
- package/lib/tools/auditKeyboard.js.map +1 -0
- package/lib/tools/auditSite.js +398 -0
- package/lib/tools/auditSite.js.map +1 -0
- package/lib/tools/axe.js +58 -0
- package/lib/tools/axe.js.map +1 -0
- package/lib/tools/scanPageMatrix.js +207 -0
- package/lib/tools/scanPageMatrix.js.map +1 -0
- package/lib/tools/snapshot.js +5 -23
- package/lib/tools/snapshot.js.map +1 -1
- package/lib/tools.js +6 -0
- package/lib/tools.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -131,6 +131,47 @@ Performs a comprehensive accessibility scan on the current page using Axe-core.
|
|
|
131
131
|
- Section 508: `section508`
|
|
132
132
|
- Categories: `cat.aria`, `cat.color`, `cat.forms`, `cat.keyboard`, `cat.language`, `cat.name-role-value`, `cat.parsing`, `cat.semantics`, `cat.sensory-and-visual-cues`, `cat.structure`, `cat.tables`, `cat.text-alternatives`, `cat.time-and-media`
|
|
133
133
|
|
|
134
|
+
### Audit Tools
|
|
135
|
+
|
|
136
|
+
#### `audit_site`
|
|
137
|
+
Crawls and scans multiple internal pages, then aggregates violations across the site.
|
|
138
|
+
- Default strategy: link-based BFS from the current URL
|
|
139
|
+
- Supports `links`, `nav`, `sitemap`, and `provided` URL strategies
|
|
140
|
+
- Always writes a JSON report (default filename: `audit-site-{timestamp}.json`)
|
|
141
|
+
|
|
142
|
+
**Example flow:**
|
|
143
|
+
```text
|
|
144
|
+
1. Navigate to your site homepage with browser_navigate
|
|
145
|
+
2. Run audit_site with maxPages: 25 and maxDepth: 2
|
|
146
|
+
3. Review the report path returned by the tool (written to the MCP output directory)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### `scan_page_matrix`
|
|
150
|
+
Runs Axe scans on the same page across viewport/media/zoom variants and compares deltas against baseline.
|
|
151
|
+
- Default variants: baseline, mobile, desktop, forced-colors, reduced-motion, zoom-200
|
|
152
|
+
- Supports custom variants and optional reload between variants
|
|
153
|
+
- Always writes a JSON report (default filename: `scan-matrix-{timestamp}.json`)
|
|
154
|
+
|
|
155
|
+
**Example flow:**
|
|
156
|
+
```text
|
|
157
|
+
1. Navigate to a page state you want to validate
|
|
158
|
+
2. Run scan_page_matrix with defaults (or provide custom variants)
|
|
159
|
+
3. Review per-variant deltas and open the generated JSON report path
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### `audit_keyboard`
|
|
163
|
+
Audits real keyboard focus behavior by pressing Tab (and optional Shift+Tab) with practical heuristics.
|
|
164
|
+
- Checks skip links, focus visibility, focus jumps, and possible focus traps
|
|
165
|
+
- Optional issue screenshots (`screenshotOnIssue`)
|
|
166
|
+
- Always writes a JSON report (default filename: `audit-keyboard-{timestamp}.json`)
|
|
167
|
+
|
|
168
|
+
**Example flow:**
|
|
169
|
+
```text
|
|
170
|
+
1. Navigate to the target page and let it fully load
|
|
171
|
+
2. Run audit_keyboard with maxTabs: 50
|
|
172
|
+
3. Review focus findings and open the generated JSON report path
|
|
173
|
+
```
|
|
174
|
+
|
|
134
175
|
### Navigation Tools
|
|
135
176
|
|
|
136
177
|
#### `browser_navigate`
|
|
@@ -312,4 +353,3 @@ npm install
|
|
|
312
353
|
## License
|
|
313
354
|
|
|
314
355
|
MIT
|
|
315
|
-
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { defineTabTool } from './tool.js';
|
|
4
|
+
import { sanitizeForFilePath } from '../utils/fileUtils.js';
|
|
5
|
+
function buildFingerprint(point) {
|
|
6
|
+
return [
|
|
7
|
+
point.role ?? '',
|
|
8
|
+
point.name ?? '',
|
|
9
|
+
point.href ?? '',
|
|
10
|
+
point.tagName ?? '',
|
|
11
|
+
point.id ?? '',
|
|
12
|
+
].join('|');
|
|
13
|
+
}
|
|
14
|
+
function isLikelySkipLink(point) {
|
|
15
|
+
if (point.role !== 'link')
|
|
16
|
+
return false;
|
|
17
|
+
const value = `${point.name ?? ''} ${point.text ?? ''}`.toLowerCase();
|
|
18
|
+
return /\bskip\b/.test(value);
|
|
19
|
+
}
|
|
20
|
+
function didUrlHashChange(urlBefore, urlAfter) {
|
|
21
|
+
if (!urlBefore || !urlAfter)
|
|
22
|
+
return false;
|
|
23
|
+
try {
|
|
24
|
+
return new URL(urlBefore).hash !== new URL(urlAfter).hash;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function safeIsoTimestampForFileName() {
|
|
31
|
+
return sanitizeForFilePath(new Date().toISOString());
|
|
32
|
+
}
|
|
33
|
+
async function maybeCaptureIssueScreenshot(options, callbacks, screenshots, issueName) {
|
|
34
|
+
if (!options.screenshotOnIssue || !callbacks.captureScreenshot)
|
|
35
|
+
return;
|
|
36
|
+
if (screenshots.length >= options.maxIssueScreenshots)
|
|
37
|
+
return;
|
|
38
|
+
const path = await callbacks.captureScreenshot(issueName);
|
|
39
|
+
screenshots.push(path);
|
|
40
|
+
}
|
|
41
|
+
export async function runKeyboardFocusAudit(options, callbacks) {
|
|
42
|
+
const stops = [];
|
|
43
|
+
const uniqueFingerprints = new Set();
|
|
44
|
+
const screenshots = [];
|
|
45
|
+
let skipLinkStep = null;
|
|
46
|
+
let skipLinkActivation = null;
|
|
47
|
+
let skipLinkActivated = false;
|
|
48
|
+
let focusTrapDetectedAt = null;
|
|
49
|
+
let focusTrapFingerprint = null;
|
|
50
|
+
let focusTrapRecentFingerprints = [];
|
|
51
|
+
for (let step = 1; step <= options.maxTabs; step++) {
|
|
52
|
+
const key = options.includeShiftTab && step % 2 === 0 ? 'Shift+Tab' : 'Tab';
|
|
53
|
+
const before = await callbacks.getActiveElementInfo();
|
|
54
|
+
await callbacks.pressKey(key);
|
|
55
|
+
const after = await callbacks.getActiveElementInfo();
|
|
56
|
+
const stop = {
|
|
57
|
+
...after,
|
|
58
|
+
step,
|
|
59
|
+
key,
|
|
60
|
+
fingerprint: buildFingerprint(after),
|
|
61
|
+
scrollDeltaX: after.scrollX - before.scrollX,
|
|
62
|
+
scrollDeltaY: after.scrollY - before.scrollY,
|
|
63
|
+
issues: [],
|
|
64
|
+
};
|
|
65
|
+
uniqueFingerprints.add(stop.fingerprint);
|
|
66
|
+
if (options.checkFocusVisibility && !stop.hasVisibleIndicator) {
|
|
67
|
+
stop.issues.push('no-visible-focus-indicator');
|
|
68
|
+
await maybeCaptureIssueScreenshot(options, callbacks, screenshots, `focus-visibility-${step}`);
|
|
69
|
+
}
|
|
70
|
+
if (options.checkFocusJumps) {
|
|
71
|
+
const hasLargeJump = Math.abs(stop.scrollDeltaY) > options.jumpScrollThresholdPx;
|
|
72
|
+
const isNotVisible = stop.boundingBox === null || !stop.inViewport;
|
|
73
|
+
if (hasLargeJump || isNotVisible) {
|
|
74
|
+
stop.issues.push('focus-jump-or-not-visible');
|
|
75
|
+
await maybeCaptureIssueScreenshot(options, callbacks, screenshots, `focus-jump-${step}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (options.checkSkipLink && step <= options.skipLinkMaxTabs && isLikelySkipLink(stop) && skipLinkStep === null) {
|
|
79
|
+
skipLinkStep = step;
|
|
80
|
+
if (options.activateSkipLink && !skipLinkActivated) {
|
|
81
|
+
const beforeActivation = stop;
|
|
82
|
+
const urlBefore = callbacks.getCurrentUrl ? await callbacks.getCurrentUrl() : null;
|
|
83
|
+
await callbacks.pressKey('Enter');
|
|
84
|
+
const afterActivation = await callbacks.getActiveElementInfo();
|
|
85
|
+
const urlAfter = callbacks.getCurrentUrl ? await callbacks.getCurrentUrl() : null;
|
|
86
|
+
const hashChanged = didUrlHashChange(urlBefore, urlAfter);
|
|
87
|
+
const fullUrlChanged = urlBefore !== null && urlAfter !== null && urlBefore !== urlAfter;
|
|
88
|
+
const navigationOccurred = fullUrlChanged && !hashChanged;
|
|
89
|
+
skipLinkActivation = {
|
|
90
|
+
attempted: true,
|
|
91
|
+
hashChanged,
|
|
92
|
+
focusChanged: buildFingerprint(beforeActivation) !== buildFingerprint(afterActivation),
|
|
93
|
+
scrollChanged: beforeActivation.scrollY !== afterActivation.scrollY || beforeActivation.scrollX !== afterActivation.scrollX,
|
|
94
|
+
navigationOccurred,
|
|
95
|
+
urlBefore,
|
|
96
|
+
urlAfter,
|
|
97
|
+
};
|
|
98
|
+
if (navigationOccurred && callbacks.goBack)
|
|
99
|
+
await callbacks.goBack();
|
|
100
|
+
skipLinkActivated = true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (options.checkFocusTrap) {
|
|
104
|
+
let shouldStopOnCycle = false;
|
|
105
|
+
const recentStops = stops.slice(Math.max(0, stops.length - options.cycleWindow + 1));
|
|
106
|
+
const foundRepeat = recentStops.some(previous => previous.fingerprint === stop.fingerprint);
|
|
107
|
+
const touchedDocumentRoot = recentStops.some(previous => previous.tagName === 'HTML' || previous.tagName === 'BODY') || stop.tagName === 'HTML' || stop.tagName === 'BODY';
|
|
108
|
+
if (foundRepeat && !touchedDocumentRoot) {
|
|
109
|
+
focusTrapDetectedAt = step;
|
|
110
|
+
focusTrapFingerprint = stop.fingerprint;
|
|
111
|
+
focusTrapRecentFingerprints = [...recentStops.map(previous => previous.fingerprint), stop.fingerprint];
|
|
112
|
+
stop.issues.push('possible-focus-trap');
|
|
113
|
+
await maybeCaptureIssueScreenshot(options, callbacks, screenshots, `focus-trap-${step}`);
|
|
114
|
+
if (options.stopOnCycle)
|
|
115
|
+
shouldStopOnCycle = true;
|
|
116
|
+
}
|
|
117
|
+
stops.push(stop);
|
|
118
|
+
if (shouldStopOnCycle)
|
|
119
|
+
break;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
stops.push(stop);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
stops,
|
|
126
|
+
uniqueFingerprints: uniqueFingerprints.size,
|
|
127
|
+
skipLink: {
|
|
128
|
+
found: skipLinkStep !== null,
|
|
129
|
+
step: skipLinkStep,
|
|
130
|
+
activated: skipLinkActivated,
|
|
131
|
+
activation: skipLinkActivation,
|
|
132
|
+
},
|
|
133
|
+
focusVisibilityIssues: stops.filter(stop => stop.issues.includes('no-visible-focus-indicator')),
|
|
134
|
+
focusJumpIssues: stops.filter(stop => stop.issues.includes('focus-jump-or-not-visible')),
|
|
135
|
+
focusTrap: {
|
|
136
|
+
detected: focusTrapDetectedAt !== null,
|
|
137
|
+
step: focusTrapDetectedAt,
|
|
138
|
+
cycleFingerprint: focusTrapFingerprint,
|
|
139
|
+
recentFingerprints: focusTrapRecentFingerprints,
|
|
140
|
+
},
|
|
141
|
+
screenshots,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const auditKeyboardSchema = z.object({
|
|
145
|
+
maxTabs: z.number().int().min(1).max(200).default(50).describe('Maximum number of Tab keypresses.'),
|
|
146
|
+
includeShiftTab: z.boolean().default(false).describe('Alternate with Shift+Tab during the sequence.'),
|
|
147
|
+
stopOnCycle: z.boolean().default(true).describe('Stop once a focus cycle/trap is detected.'),
|
|
148
|
+
cycleWindow: z.number().int().min(2).max(50).default(10).describe('Recent-window size used for cycle detection.'),
|
|
149
|
+
checkSkipLink: z.boolean().default(true).describe('Check early focus stops for a skip link.'),
|
|
150
|
+
skipLinkMaxTabs: z.number().int().min(1).max(20).default(3).describe('Maximum early steps to look for a skip link.'),
|
|
151
|
+
activateSkipLink: z.boolean().default(false).describe('Press Enter when skip link is found.'),
|
|
152
|
+
checkFocusTrap: z.boolean().default(true).describe('Detect likely focus trap/cycle.'),
|
|
153
|
+
checkFocusVisibility: z.boolean().default(true).describe('Check focus ring visibility heuristic.'),
|
|
154
|
+
checkFocusJumps: z.boolean().default(true).describe('Detect large scroll jumps and invisible focus.'),
|
|
155
|
+
jumpScrollThresholdPx: z.number().int().min(1).default(800).describe('Scroll delta threshold for jump detection.'),
|
|
156
|
+
screenshotOnIssue: z.boolean().default(false).describe('Capture screenshots for detected issues.'),
|
|
157
|
+
maxIssueScreenshots: z.number().int().min(1).max(20).default(3).describe('Maximum screenshots saved when screenshotOnIssue=true.'),
|
|
158
|
+
reportFile: z.string().optional().describe('Output JSON report file name.'),
|
|
159
|
+
});
|
|
160
|
+
const auditKeyboard = defineTabTool({
|
|
161
|
+
capability: 'core',
|
|
162
|
+
schema: {
|
|
163
|
+
name: 'audit_keyboard',
|
|
164
|
+
title: 'Audit keyboard focus flow',
|
|
165
|
+
description: 'Audit keyboard tab order, focus visibility, jumps, skip links, and focus traps.',
|
|
166
|
+
inputSchema: auditKeyboardSchema,
|
|
167
|
+
type: 'destructive',
|
|
168
|
+
},
|
|
169
|
+
handle: async (tab, params, response) => {
|
|
170
|
+
const getActiveElementInfo = async () => {
|
|
171
|
+
return await tab.page.evaluate(() => {
|
|
172
|
+
const current = document.activeElement;
|
|
173
|
+
const scrollX = window.scrollX;
|
|
174
|
+
const scrollY = window.scrollY;
|
|
175
|
+
if (!current) {
|
|
176
|
+
return {
|
|
177
|
+
role: null,
|
|
178
|
+
name: null,
|
|
179
|
+
tagName: null,
|
|
180
|
+
id: null,
|
|
181
|
+
href: null,
|
|
182
|
+
text: null,
|
|
183
|
+
boundingBox: null,
|
|
184
|
+
inViewport: false,
|
|
185
|
+
hasVisibleIndicator: false,
|
|
186
|
+
scrollX,
|
|
187
|
+
scrollY,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const role = current.getAttribute('role') || current.tagName.toLowerCase();
|
|
191
|
+
const name = current.getAttribute('aria-label')
|
|
192
|
+
|| current.getAttribute('aria-labelledby') && document.getElementById(current.getAttribute('aria-labelledby'))?.textContent?.trim()
|
|
193
|
+
|| current.getAttribute('title')
|
|
194
|
+
|| (current instanceof HTMLInputElement || current instanceof HTMLTextAreaElement ? current.labels?.[0]?.textContent?.trim() : null)
|
|
195
|
+
|| current.textContent?.trim().slice(0, 200)
|
|
196
|
+
|| null;
|
|
197
|
+
const rect = current.getBoundingClientRect();
|
|
198
|
+
const style = window.getComputedStyle(current);
|
|
199
|
+
const outlineWidth = Number.parseFloat(style.outlineWidth || '0');
|
|
200
|
+
const hasOutline = outlineWidth > 0 && style.outlineStyle !== 'none';
|
|
201
|
+
const hasBoxShadow = style.boxShadow !== 'none';
|
|
202
|
+
const inViewport = rect.width > 0
|
|
203
|
+
&& rect.height > 0
|
|
204
|
+
&& rect.bottom >= 0
|
|
205
|
+
&& rect.right >= 0
|
|
206
|
+
&& rect.top <= window.innerHeight
|
|
207
|
+
&& rect.left <= window.innerWidth;
|
|
208
|
+
return {
|
|
209
|
+
role,
|
|
210
|
+
name: name ? name.slice(0, 200) : null,
|
|
211
|
+
tagName: current.tagName,
|
|
212
|
+
id: current.id || null,
|
|
213
|
+
href: current instanceof HTMLAnchorElement ? current.href : null,
|
|
214
|
+
text: current.textContent?.trim().slice(0, 200) || null,
|
|
215
|
+
boundingBox: rect.width > 0 || rect.height > 0 ? {
|
|
216
|
+
x: rect.x,
|
|
217
|
+
y: rect.y,
|
|
218
|
+
width: rect.width,
|
|
219
|
+
height: rect.height,
|
|
220
|
+
} : null,
|
|
221
|
+
inViewport,
|
|
222
|
+
hasVisibleIndicator: hasOutline || hasBoxShadow,
|
|
223
|
+
scrollX,
|
|
224
|
+
scrollY,
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
};
|
|
228
|
+
const captureScreenshot = async (label) => {
|
|
229
|
+
const fileName = await tab.context.outputFile(`${sanitizeForFilePath(label)}-${safeIsoTimestampForFileName()}.png`);
|
|
230
|
+
await tab.page.screenshot({ path: fileName, fullPage: true });
|
|
231
|
+
return fileName;
|
|
232
|
+
};
|
|
233
|
+
const result = await runKeyboardFocusAudit({
|
|
234
|
+
maxTabs: params.maxTabs,
|
|
235
|
+
includeShiftTab: params.includeShiftTab,
|
|
236
|
+
stopOnCycle: params.stopOnCycle,
|
|
237
|
+
cycleWindow: params.cycleWindow,
|
|
238
|
+
checkSkipLink: params.checkSkipLink,
|
|
239
|
+
skipLinkMaxTabs: params.skipLinkMaxTabs,
|
|
240
|
+
activateSkipLink: params.activateSkipLink,
|
|
241
|
+
checkFocusTrap: params.checkFocusTrap,
|
|
242
|
+
checkFocusVisibility: params.checkFocusVisibility,
|
|
243
|
+
checkFocusJumps: params.checkFocusJumps,
|
|
244
|
+
jumpScrollThresholdPx: params.jumpScrollThresholdPx,
|
|
245
|
+
screenshotOnIssue: params.screenshotOnIssue,
|
|
246
|
+
maxIssueScreenshots: params.maxIssueScreenshots,
|
|
247
|
+
}, {
|
|
248
|
+
pressKey: async (key) => {
|
|
249
|
+
await tab.waitForCompletion(async () => {
|
|
250
|
+
await tab.page.keyboard.press(key);
|
|
251
|
+
});
|
|
252
|
+
},
|
|
253
|
+
getActiveElementInfo,
|
|
254
|
+
getCurrentUrl: async () => tab.page.url(),
|
|
255
|
+
goBack: async () => {
|
|
256
|
+
await tab.page.goBack({ waitUntil: 'domcontentloaded' });
|
|
257
|
+
},
|
|
258
|
+
captureScreenshot,
|
|
259
|
+
});
|
|
260
|
+
const report = {
|
|
261
|
+
version: 'v1',
|
|
262
|
+
metadata: {
|
|
263
|
+
url: tab.page.url(),
|
|
264
|
+
options: params,
|
|
265
|
+
generatedAt: new Date().toISOString(),
|
|
266
|
+
},
|
|
267
|
+
...result,
|
|
268
|
+
};
|
|
269
|
+
const reportFileName = sanitizeForFilePath(params.reportFile ?? `audit-keyboard-${safeIsoTimestampForFileName()}.json`);
|
|
270
|
+
const reportPath = await tab.context.outputFile(reportFileName);
|
|
271
|
+
await fs.promises.writeFile(reportPath, JSON.stringify(report, null, 2), 'utf-8');
|
|
272
|
+
const focusVisibilityPreview = result.focusVisibilityIssues.slice(0, 10).map(stop => (`- Step ${stop.step} (${stop.key}): ${stop.role ?? 'unknown-role'} ${stop.name ?? ''}`.trim()));
|
|
273
|
+
const focusJumpPreview = result.focusJumpIssues.slice(0, 10).map(stop => (`- Step ${stop.step}: deltaY=${stop.scrollDeltaY}, inViewport=${stop.inViewport}`));
|
|
274
|
+
const skipLinkResult = result.skipLink.found
|
|
275
|
+
? `found at step ${result.skipLink.step}${result.skipLink.activated ? ', activated' : ''}`
|
|
276
|
+
: 'not found';
|
|
277
|
+
response.addCode('// Pressed Tab/Shift+Tab and audited focus behavior heuristics.');
|
|
278
|
+
response.addResult([
|
|
279
|
+
`Unique focus stops: ${result.uniqueFingerprints}`,
|
|
280
|
+
`Skip link: ${skipLinkResult}`,
|
|
281
|
+
`No visible focus indicator: ${result.focusVisibilityIssues.length}`,
|
|
282
|
+
...(focusVisibilityPreview.length ? focusVisibilityPreview : ['- None']),
|
|
283
|
+
'',
|
|
284
|
+
`Focus trap detected: ${result.focusTrap.detected ? `yes (step ${result.focusTrap.step})` : 'no'}`,
|
|
285
|
+
`Focus jumps: ${result.focusJumpIssues.length}`,
|
|
286
|
+
...(focusJumpPreview.length ? focusJumpPreview : ['- None']),
|
|
287
|
+
...(result.screenshots.length ? ['', 'Issue screenshots:', ...result.screenshots.map(path => `- ${path}`)] : []),
|
|
288
|
+
'',
|
|
289
|
+
`JSON report: ${reportPath}`,
|
|
290
|
+
].join('\n'));
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
export default [
|
|
294
|
+
auditKeyboard,
|
|
295
|
+
];
|
|
296
|
+
//# sourceMappingURL=auditKeyboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditKeyboard.js","sourceRoot":"","sources":["../../src/tools/auditKeyboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import RE2 from 're2';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { defineTabTool } from './tool.js';
|
|
6
|
+
import { sanitizeForFilePath } from '../utils/fileUtils.js';
|
|
7
|
+
import { axeTagValues, dedupeAxeNodes, runAxeScan, summarizeAxeViolations, trimAxeResults } from './axe.js';
|
|
8
|
+
const defaultIgnoreQueryParams = [
|
|
9
|
+
'utm_source',
|
|
10
|
+
'utm_medium',
|
|
11
|
+
'utm_campaign',
|
|
12
|
+
'utm_term',
|
|
13
|
+
'utm_content',
|
|
14
|
+
'gclid',
|
|
15
|
+
'fbclid',
|
|
16
|
+
];
|
|
17
|
+
const defaultExcludePathPatterns = [
|
|
18
|
+
'logout|signout',
|
|
19
|
+
];
|
|
20
|
+
const maxExcludeRegexPatternLength = 200;
|
|
21
|
+
const impactPriority = {
|
|
22
|
+
critical: 0,
|
|
23
|
+
serious: 1,
|
|
24
|
+
moderate: 2,
|
|
25
|
+
minor: 3,
|
|
26
|
+
unknown: 4,
|
|
27
|
+
};
|
|
28
|
+
const crawlStrategySchema = z.enum(['links', 'nav', 'sitemap', 'provided']);
|
|
29
|
+
const auditSiteSchema = z.object({
|
|
30
|
+
startUrl: z.string().optional().describe('URL to start the crawl from. Defaults to the current tab URL.'),
|
|
31
|
+
strategy: crawlStrategySchema.default('links').describe('How to discover pages to scan.'),
|
|
32
|
+
urls: z.array(z.string()).optional().describe('Explicit URL list when strategy is "provided".'),
|
|
33
|
+
sitemapUrl: z.string().optional().describe('URL of the sitemap to fetch when strategy is "sitemap".'),
|
|
34
|
+
maxPages: z.number().int().min(1).max(200).default(25).describe('Maximum pages to scan.'),
|
|
35
|
+
maxDepth: z.number().int().min(0).max(5).default(2).describe('Maximum crawl depth for link strategy.'),
|
|
36
|
+
sameOriginOnly: z.boolean().default(true).describe('Restrict crawl to the start origin/host.'),
|
|
37
|
+
includeSubdomains: z.boolean().default(false).describe('Only applies when sameOriginOnly=true. When enabled, also allows subdomains of the start host (e.g. blog.example.com when start host is example.com). Ignored when sameOriginOnly=false.'),
|
|
38
|
+
excludePathPatterns: z.array(z.string()).default(defaultExcludePathPatterns).describe('Regex patterns applied to pathname+query. Avoid complex nested quantifiers to prevent performance issues.'),
|
|
39
|
+
ignoreQueryParams: z.array(z.string()).default(defaultIgnoreQueryParams).describe('Query parameters dropped during URL normalization.'),
|
|
40
|
+
violationsTag: z.array(z.enum(axeTagValues)).min(1).default([...axeTagValues]).describe('Axe tags to include in scans.'),
|
|
41
|
+
maxNodesPerViolation: z.number().int().min(1).max(50).default(10).describe('Maximum nodes kept per violation in the report.'),
|
|
42
|
+
waitAfterNavigationMs: z.number().int().min(0).max(5000).default(250).describe('Extra wait after navigation before scanning.'),
|
|
43
|
+
reportFile: z.string().optional().describe('Output JSON report file name.'),
|
|
44
|
+
}).superRefine((value, context) => {
|
|
45
|
+
if (value.strategy === 'provided' && (!value.urls || !value.urls.length)) {
|
|
46
|
+
context.addIssue({
|
|
47
|
+
code: z.ZodIssueCode.custom,
|
|
48
|
+
path: ['urls'],
|
|
49
|
+
message: 'urls is required when strategy="provided"',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
function normalizeWhitespace(value) {
|
|
54
|
+
return value.replace(/\s+/g, ' ').trim();
|
|
55
|
+
}
|
|
56
|
+
function isAllowedByOrigin(candidate, startUrl, sameOriginOnly, includeSubdomains) {
|
|
57
|
+
if (!sameOriginOnly)
|
|
58
|
+
return true;
|
|
59
|
+
if (!includeSubdomains)
|
|
60
|
+
return candidate.origin === startUrl.origin;
|
|
61
|
+
const hostMatch = candidate.hostname === startUrl.hostname || candidate.hostname.endsWith(`.${startUrl.hostname}`);
|
|
62
|
+
return hostMatch && candidate.protocol === startUrl.protocol;
|
|
63
|
+
}
|
|
64
|
+
function buildExcludePathPatterns(patterns) {
|
|
65
|
+
return patterns.map((pattern, index) => {
|
|
66
|
+
if (pattern.length > maxExcludeRegexPatternLength)
|
|
67
|
+
throw new Error(`excludePathPatterns[${index}] is too long (${pattern.length}). Maximum supported length is ${maxExcludeRegexPatternLength}.`);
|
|
68
|
+
try {
|
|
69
|
+
return new RE2(pattern, 'i');
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
const errorText = error instanceof Error ? error.message : String(error);
|
|
73
|
+
throw new Error(`Invalid regex in excludePathPatterns[${index}] ("${pattern}"): ${errorText}`);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function parseStartUrl(startUrlInput, activeTabUrl) {
|
|
78
|
+
const startUrlValue = startUrlInput ?? activeTabUrl;
|
|
79
|
+
let startUrl;
|
|
80
|
+
try {
|
|
81
|
+
startUrl = new URL(startUrlValue);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw new Error(`Invalid start URL "${startUrlValue}". Provide params.startUrl with an absolute http(s) URL or navigate the active tab (currently "${activeTabUrl}") first.`);
|
|
85
|
+
}
|
|
86
|
+
if (startUrl.protocol !== 'http:' && startUrl.protocol !== 'https:')
|
|
87
|
+
throw new Error(`Start URL must use http:// or https://. Received "${startUrlValue}" (active tab: "${activeTabUrl}").`);
|
|
88
|
+
return startUrl;
|
|
89
|
+
}
|
|
90
|
+
function safeIsoTimestampForFileName() {
|
|
91
|
+
return sanitizeForFilePath(new Date().toISOString());
|
|
92
|
+
}
|
|
93
|
+
function isExcludedByPath(candidate, excludePatterns) {
|
|
94
|
+
const value = `${candidate.pathname}${candidate.search}`;
|
|
95
|
+
return excludePatterns.some(pattern => pattern.test(value));
|
|
96
|
+
}
|
|
97
|
+
function normalizeUrl(rawUrl, baseUrl, ignoredParams) {
|
|
98
|
+
let url;
|
|
99
|
+
try {
|
|
100
|
+
url = new URL(rawUrl, baseUrl);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
106
|
+
return null;
|
|
107
|
+
url.hash = '';
|
|
108
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
109
|
+
if (ignoredParams.has(key.toLowerCase()))
|
|
110
|
+
url.searchParams.delete(key);
|
|
111
|
+
}
|
|
112
|
+
const sortedParams = [...url.searchParams.entries()].sort(([first], [second]) => first.localeCompare(second));
|
|
113
|
+
url.search = '';
|
|
114
|
+
for (const [key, value] of sortedParams)
|
|
115
|
+
url.searchParams.append(key, value);
|
|
116
|
+
if (url.pathname !== '/' && url.pathname.endsWith('/'))
|
|
117
|
+
url.pathname = url.pathname.slice(0, -1);
|
|
118
|
+
return url;
|
|
119
|
+
}
|
|
120
|
+
async function extractLinks(page) {
|
|
121
|
+
return await page.evaluate(() => {
|
|
122
|
+
return Array.from(document.querySelectorAll('a[href]'))
|
|
123
|
+
.map(anchor => anchor.href)
|
|
124
|
+
.filter(Boolean);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async function extractNavLinks(page) {
|
|
128
|
+
return await page.evaluate(() => {
|
|
129
|
+
const selectors = 'nav a[href], header a[href], [role="navigation"] a[href]';
|
|
130
|
+
return Array.from(document.querySelectorAll(selectors))
|
|
131
|
+
.map(anchor => anchor.href)
|
|
132
|
+
.filter(Boolean);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async function extractSitemapUrls(page, sitemapUrl) {
|
|
136
|
+
const response = await page.request.get(sitemapUrl, { timeout: 15000 });
|
|
137
|
+
if (!response.ok())
|
|
138
|
+
throw new Error(`Failed to fetch sitemap ${sitemapUrl}: ${response.status()} ${response.statusText()}`);
|
|
139
|
+
const xmlText = await response.text();
|
|
140
|
+
const matches = [...xmlText.matchAll(/<loc>([\s\S]*?)<\/loc>/gi)];
|
|
141
|
+
return matches.map(match => match[1].replace('<![CDATA[', '').replace(']]>', '').trim()).filter(Boolean);
|
|
142
|
+
}
|
|
143
|
+
function summarizeTopViolations(violations, count) {
|
|
144
|
+
return violations
|
|
145
|
+
.slice(0, count)
|
|
146
|
+
.map(violation => `- ${violation.id} (${violation.impact ?? 'unknown'}): ${violation.pagesAffected.length} pages, ${violation.totalOccurrences} nodes`);
|
|
147
|
+
}
|
|
148
|
+
function summarizeTopPages(pages, count) {
|
|
149
|
+
return pages
|
|
150
|
+
.filter(page => page.status === 'scanned')
|
|
151
|
+
.sort((first, second) => (second.summary?.totalRules ?? 0) - (first.summary?.totalRules ?? 0))
|
|
152
|
+
.slice(0, count)
|
|
153
|
+
.map(page => `- ${page.url}: ${page.summary?.totalRules ?? 0} violations, ${page.summary?.totalNodes ?? 0} nodes`);
|
|
154
|
+
}
|
|
155
|
+
const auditSite = defineTabTool({
|
|
156
|
+
capability: 'core',
|
|
157
|
+
schema: {
|
|
158
|
+
name: 'audit_site',
|
|
159
|
+
title: 'Audit multiple pages',
|
|
160
|
+
description: 'Crawl internal pages and aggregate accessibility violations across the site.',
|
|
161
|
+
inputSchema: auditSiteSchema,
|
|
162
|
+
type: 'destructive',
|
|
163
|
+
},
|
|
164
|
+
handle: async (tab, params, response) => {
|
|
165
|
+
const context = tab.context;
|
|
166
|
+
const originalTab = tab;
|
|
167
|
+
const queue = [];
|
|
168
|
+
const queued = new Set();
|
|
169
|
+
const visited = new Set();
|
|
170
|
+
const pages = [];
|
|
171
|
+
let skippedUrls = 0;
|
|
172
|
+
let erroredPages = 0;
|
|
173
|
+
const scanStartedAt = Date.now();
|
|
174
|
+
const startedAtIso = new Date(scanStartedAt).toISOString();
|
|
175
|
+
const activeTabUrl = originalTab.page.url();
|
|
176
|
+
const startUrl = parseStartUrl(params.startUrl, activeTabUrl);
|
|
177
|
+
const ignoredParams = new Set(params.ignoreQueryParams.map(param => param.toLowerCase()));
|
|
178
|
+
const excludePatterns = buildExcludePathPatterns(params.excludePathPatterns);
|
|
179
|
+
const summaryByViolation = new Map();
|
|
180
|
+
const enqueueUrl = (rawUrl, depth, discoveredFrom) => {
|
|
181
|
+
const normalizedUrl = normalizeUrl(rawUrl, startUrl, ignoredParams);
|
|
182
|
+
if (!normalizedUrl) {
|
|
183
|
+
skippedUrls++;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!isAllowedByOrigin(normalizedUrl, startUrl, params.sameOriginOnly, params.includeSubdomains)) {
|
|
187
|
+
skippedUrls++;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (isExcludedByPath(normalizedUrl, excludePatterns)) {
|
|
191
|
+
skippedUrls++;
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const normalizedUrlString = normalizedUrl.toString();
|
|
195
|
+
if (visited.has(normalizedUrlString) || queued.has(normalizedUrlString)) {
|
|
196
|
+
skippedUrls++;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (queue.length + visited.size >= params.maxPages) {
|
|
200
|
+
skippedUrls++;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
queue.push({
|
|
204
|
+
url: normalizedUrlString,
|
|
205
|
+
depth,
|
|
206
|
+
discoveredFrom,
|
|
207
|
+
});
|
|
208
|
+
queued.add(normalizedUrlString);
|
|
209
|
+
};
|
|
210
|
+
if (params.strategy === 'provided') {
|
|
211
|
+
for (const url of params.urls ?? [])
|
|
212
|
+
enqueueUrl(url, 0, null);
|
|
213
|
+
}
|
|
214
|
+
else if (params.strategy === 'sitemap') {
|
|
215
|
+
const sitemapUrl = params.sitemapUrl ?? new URL('sitemap.xml', startUrl).toString();
|
|
216
|
+
const temporaryTab = await context.newTab();
|
|
217
|
+
try {
|
|
218
|
+
const sitemapUrls = await extractSitemapUrls(temporaryTab.page, sitemapUrl);
|
|
219
|
+
for (const url of sitemapUrls)
|
|
220
|
+
enqueueUrl(url, 0, sitemapUrl);
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
const tabIndex = context.tabs().indexOf(temporaryTab);
|
|
224
|
+
if (tabIndex !== -1)
|
|
225
|
+
await context.closeTab(tabIndex);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
enqueueUrl(startUrl.toString(), 0, null);
|
|
230
|
+
}
|
|
231
|
+
const crawlTab = await context.newTab();
|
|
232
|
+
try {
|
|
233
|
+
while (queue.length && pages.length < params.maxPages) {
|
|
234
|
+
const item = queue.shift();
|
|
235
|
+
queued.delete(item.url);
|
|
236
|
+
if (visited.has(item.url)) {
|
|
237
|
+
skippedUrls++;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
visited.add(item.url);
|
|
241
|
+
const pageReport = {
|
|
242
|
+
url: item.url,
|
|
243
|
+
title: '',
|
|
244
|
+
depth: item.depth,
|
|
245
|
+
discoveredFrom: item.discoveredFrom,
|
|
246
|
+
status: 'error',
|
|
247
|
+
error: null,
|
|
248
|
+
summary: null,
|
|
249
|
+
violations: [],
|
|
250
|
+
};
|
|
251
|
+
pages.push(pageReport);
|
|
252
|
+
try {
|
|
253
|
+
await crawlTab.navigate(item.url);
|
|
254
|
+
await crawlTab.waitForTimeout(params.waitAfterNavigationMs);
|
|
255
|
+
pageReport.title = await crawlTab.page.title();
|
|
256
|
+
const axeResult = await runAxeScan(crawlTab.page, params.violationsTag);
|
|
257
|
+
const dedupedViolations = axeResult.violations.map(violation => ({
|
|
258
|
+
...violation,
|
|
259
|
+
nodes: dedupeAxeNodes(violation.nodes),
|
|
260
|
+
}));
|
|
261
|
+
const trimmedViolations = trimAxeResults({ violations: dedupedViolations }, { maxNodesPerViolation: params.maxNodesPerViolation });
|
|
262
|
+
pageReport.status = 'scanned';
|
|
263
|
+
pageReport.violations = trimmedViolations;
|
|
264
|
+
pageReport.summary = summarizeAxeViolations(trimmedViolations);
|
|
265
|
+
for (const violation of dedupedViolations) {
|
|
266
|
+
const existingSummary = summaryByViolation.get(violation.id);
|
|
267
|
+
const summary = existingSummary ?? {
|
|
268
|
+
id: violation.id,
|
|
269
|
+
impact: violation.impact,
|
|
270
|
+
tags: [...violation.tags],
|
|
271
|
+
help: violation.help,
|
|
272
|
+
helpUrl: violation.helpUrl,
|
|
273
|
+
description: violation.description,
|
|
274
|
+
pagesAffected: new Set(),
|
|
275
|
+
totalOccurrences: 0,
|
|
276
|
+
fingerprints: new Set(),
|
|
277
|
+
sampleNodes: [],
|
|
278
|
+
};
|
|
279
|
+
summary.pagesAffected.add(item.url);
|
|
280
|
+
summary.totalOccurrences += violation.nodes.length;
|
|
281
|
+
for (const node of violation.nodes) {
|
|
282
|
+
const nodeHtml = normalizeWhitespace(node.html ?? '');
|
|
283
|
+
const fingerprint = crypto.createHash('sha256').update(`${violation.id}|${nodeHtml}`).digest('hex');
|
|
284
|
+
if (summary.fingerprints.has(fingerprint))
|
|
285
|
+
continue;
|
|
286
|
+
summary.fingerprints.add(fingerprint);
|
|
287
|
+
if (summary.sampleNodes.length < 3) {
|
|
288
|
+
summary.sampleNodes.push({
|
|
289
|
+
pageUrl: item.url,
|
|
290
|
+
target: [...(node.target ?? [])],
|
|
291
|
+
html: node.html ?? '',
|
|
292
|
+
failureSummary: node.failureSummary ?? null,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
summaryByViolation.set(violation.id, summary);
|
|
297
|
+
}
|
|
298
|
+
if (params.strategy === 'links' && item.depth < params.maxDepth) {
|
|
299
|
+
const links = await extractLinks(crawlTab.page);
|
|
300
|
+
for (const link of links)
|
|
301
|
+
enqueueUrl(link, item.depth + 1, item.url);
|
|
302
|
+
}
|
|
303
|
+
if (params.strategy === 'nav' && item.depth === 0) {
|
|
304
|
+
const links = await extractNavLinks(crawlTab.page);
|
|
305
|
+
for (const link of links)
|
|
306
|
+
enqueueUrl(link, item.depth + 1, item.url);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
erroredPages++;
|
|
311
|
+
pageReport.status = 'error';
|
|
312
|
+
pageReport.error = error instanceof Error ? error.message : String(error);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
const crawlTabIndex = context.tabs().indexOf(crawlTab);
|
|
318
|
+
if (crawlTabIndex !== -1)
|
|
319
|
+
await context.closeTab(crawlTabIndex);
|
|
320
|
+
const originalTabIndex = context.tabs().indexOf(originalTab);
|
|
321
|
+
if (originalTabIndex !== -1)
|
|
322
|
+
await context.selectTab(originalTabIndex);
|
|
323
|
+
}
|
|
324
|
+
const summaryViolations = [...summaryByViolation.values()].map(summary => ({
|
|
325
|
+
id: summary.id,
|
|
326
|
+
impact: summary.impact,
|
|
327
|
+
tags: summary.tags,
|
|
328
|
+
help: summary.help,
|
|
329
|
+
helpUrl: summary.helpUrl,
|
|
330
|
+
description: summary.description,
|
|
331
|
+
pagesAffected: [...summary.pagesAffected],
|
|
332
|
+
totalOccurrences: summary.totalOccurrences,
|
|
333
|
+
uniqueOccurrences: summary.fingerprints.size,
|
|
334
|
+
sampleNodes: summary.sampleNodes,
|
|
335
|
+
})).sort((first, second) => {
|
|
336
|
+
const firstImpact = impactPriority[first.impact ?? 'unknown'] ?? impactPriority.unknown;
|
|
337
|
+
const secondImpact = impactPriority[second.impact ?? 'unknown'] ?? impactPriority.unknown;
|
|
338
|
+
if (firstImpact !== secondImpact)
|
|
339
|
+
return firstImpact - secondImpact;
|
|
340
|
+
return second.pagesAffected.length - first.pagesAffected.length;
|
|
341
|
+
});
|
|
342
|
+
const summary = {
|
|
343
|
+
totals: {
|
|
344
|
+
scannedPages: pages.filter(page => page.status === 'scanned').length,
|
|
345
|
+
erroredPages,
|
|
346
|
+
skippedUrls,
|
|
347
|
+
queuedUrls: visited.size,
|
|
348
|
+
},
|
|
349
|
+
violations: summaryViolations,
|
|
350
|
+
};
|
|
351
|
+
const report = {
|
|
352
|
+
version: 'v1',
|
|
353
|
+
metadata: {
|
|
354
|
+
startUrl: startUrl.toString(),
|
|
355
|
+
strategy: params.strategy,
|
|
356
|
+
options: {
|
|
357
|
+
maxPages: params.maxPages,
|
|
358
|
+
maxDepth: params.maxDepth,
|
|
359
|
+
sameOriginOnly: params.sameOriginOnly,
|
|
360
|
+
includeSubdomains: params.includeSubdomains,
|
|
361
|
+
excludePathPatterns: params.excludePathPatterns,
|
|
362
|
+
ignoreQueryParams: params.ignoreQueryParams,
|
|
363
|
+
violationsTag: params.violationsTag,
|
|
364
|
+
maxNodesPerViolation: params.maxNodesPerViolation,
|
|
365
|
+
waitAfterNavigationMs: params.waitAfterNavigationMs,
|
|
366
|
+
},
|
|
367
|
+
startedAt: startedAtIso,
|
|
368
|
+
finishedAt: new Date().toISOString(),
|
|
369
|
+
durationMs: Date.now() - scanStartedAt,
|
|
370
|
+
},
|
|
371
|
+
pages,
|
|
372
|
+
summary,
|
|
373
|
+
};
|
|
374
|
+
const reportFileName = sanitizeForFilePath(params.reportFile ?? `audit-site-${safeIsoTimestampForFileName()}.json`);
|
|
375
|
+
const reportPath = await context.outputFile(reportFileName);
|
|
376
|
+
await fs.promises.writeFile(reportPath, JSON.stringify(report, null, 2), 'utf-8');
|
|
377
|
+
const topViolations = summarizeTopViolations(summaryViolations, 10);
|
|
378
|
+
const topPages = summarizeTopPages(pages, 20);
|
|
379
|
+
response.addCode('// Crawled pages in a temporary tab and aggregated Axe violations.');
|
|
380
|
+
response.addResult([
|
|
381
|
+
`Scanned pages: ${summary.totals.scannedPages}`,
|
|
382
|
+
`Errored pages: ${summary.totals.erroredPages}`,
|
|
383
|
+
`Skipped URLs: ${summary.totals.skippedUrls}`,
|
|
384
|
+
'',
|
|
385
|
+
'Top violations by pages affected:',
|
|
386
|
+
...(topViolations.length ? topViolations : ['- None']),
|
|
387
|
+
'',
|
|
388
|
+
'Per-page summary (top 20 by violation count):',
|
|
389
|
+
...(topPages.length ? topPages : ['- None']),
|
|
390
|
+
'',
|
|
391
|
+
`JSON report: ${reportPath}`,
|
|
392
|
+
].join('\n'));
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
export default [
|
|
396
|
+
auditSite,
|
|
397
|
+
];
|
|
398
|
+
//# sourceMappingURL=auditSite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditSite.js","sourceRoot":"","sources":["../../src/tools/auditSite.ts"],"names":[],"mappings":"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"}
|
package/lib/tools/axe.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import AxeBuilder from '@axe-core/playwright';
|
|
2
|
+
export const axeTagValues = [
|
|
3
|
+
'wcag2a', 'wcag2aa', 'wcag2aaa', 'wcag21a', 'wcag21aa', 'wcag21aaa',
|
|
4
|
+
'wcag22a', 'wcag22aa', 'wcag22aaa', 'section508', 'cat.aria', 'cat.color',
|
|
5
|
+
'cat.forms', 'cat.keyboard', 'cat.language', 'cat.name-role-value',
|
|
6
|
+
'cat.parsing', 'cat.semantics', 'cat.sensory-and-visual-cues',
|
|
7
|
+
'cat.structure', 'cat.tables', 'cat.text-alternatives', 'cat.time-and-media',
|
|
8
|
+
];
|
|
9
|
+
export async function runAxeScan(page, tags) {
|
|
10
|
+
return await new AxeBuilder({ page }).withTags([...tags]).analyze();
|
|
11
|
+
}
|
|
12
|
+
export function dedupeAxeNodes(nodes) {
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
return nodes.filter(node => {
|
|
15
|
+
const key = JSON.stringify({ target: node.target ?? [], html: node.html ?? '' });
|
|
16
|
+
if (seen.has(key))
|
|
17
|
+
return false;
|
|
18
|
+
seen.add(key);
|
|
19
|
+
return true;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function trimAxeResults(results, options) {
|
|
23
|
+
return results.violations.map(violation => {
|
|
24
|
+
const nodes = dedupeAxeNodes(violation.nodes).slice(0, options.maxNodesPerViolation).map(node => ({
|
|
25
|
+
target: [...(node.target ?? [])],
|
|
26
|
+
html: node.html ?? '',
|
|
27
|
+
failureSummary: node.failureSummary ?? null,
|
|
28
|
+
}));
|
|
29
|
+
return {
|
|
30
|
+
id: violation.id,
|
|
31
|
+
impact: violation.impact,
|
|
32
|
+
tags: [...violation.tags],
|
|
33
|
+
help: violation.help,
|
|
34
|
+
helpUrl: violation.helpUrl,
|
|
35
|
+
description: violation.description,
|
|
36
|
+
nodes,
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
export function summarizeAxeViolations(violations) {
|
|
41
|
+
const byImpact = {};
|
|
42
|
+
const byRuleId = {};
|
|
43
|
+
let totalNodes = 0;
|
|
44
|
+
for (const violation of violations) {
|
|
45
|
+
const impact = violation.impact ?? 'unknown';
|
|
46
|
+
const nodeCount = violation.nodes.length;
|
|
47
|
+
byImpact[impact] = (byImpact[impact] ?? 0) + nodeCount;
|
|
48
|
+
byRuleId[violation.id] = (byRuleId[violation.id] ?? 0) + nodeCount;
|
|
49
|
+
totalNodes += nodeCount;
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
totalRules: violations.length,
|
|
53
|
+
totalNodes,
|
|
54
|
+
byImpact,
|
|
55
|
+
byRuleId,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=axe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axe.js","sourceRoot":"","sources":["../../src/tools/axe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { defineTabTool } from './tool.js';
|
|
4
|
+
import { sanitizeForFilePath } from '../utils/fileUtils.js';
|
|
5
|
+
import { axeTagValues, dedupeAxeNodes, runAxeScan, summarizeAxeViolations, trimAxeResults } from './axe.js';
|
|
6
|
+
const variantSchema = z.object({
|
|
7
|
+
name: z.string().min(1).describe('Variant name.'),
|
|
8
|
+
viewport: z.object({
|
|
9
|
+
width: z.number().int().min(1),
|
|
10
|
+
height: z.number().int().min(1),
|
|
11
|
+
}).optional(),
|
|
12
|
+
media: z.object({
|
|
13
|
+
colorScheme: z.enum(['light', 'dark']).optional(),
|
|
14
|
+
forcedColors: z.enum(['active', 'none']).optional(),
|
|
15
|
+
contrast: z.enum(['more', 'no-preference']).optional(),
|
|
16
|
+
reducedMotion: z.enum(['reduce', 'no-preference']).optional(),
|
|
17
|
+
}).optional(),
|
|
18
|
+
zoomPercent: z.number().int().min(50).max(400).optional(),
|
|
19
|
+
});
|
|
20
|
+
const defaultVariants = [
|
|
21
|
+
{
|
|
22
|
+
name: 'baseline',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'mobile',
|
|
26
|
+
viewport: { width: 375, height: 812 },
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'desktop',
|
|
30
|
+
viewport: { width: 1280, height: 720 },
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'forced-colors',
|
|
34
|
+
media: { forcedColors: 'active', contrast: 'more' },
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'reduced-motion',
|
|
38
|
+
media: { reducedMotion: 'reduce' },
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'zoom-200',
|
|
42
|
+
zoomPercent: 200,
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
const scanPageMatrixSchema = z.object({
|
|
46
|
+
variants: z.array(variantSchema).min(1).optional().describe('Variant list to run. Defaults to baseline/mobile/desktop/forced-colors/reduced-motion/zoom-200.'),
|
|
47
|
+
violationsTag: z.array(z.enum(axeTagValues)).min(1).default([...axeTagValues]).describe('Axe tags to include in scans.'),
|
|
48
|
+
maxNodesPerViolation: z.number().int().min(1).max(50).default(10).describe('Maximum nodes kept per violation in the report.'),
|
|
49
|
+
waitAfterApplyMs: z.number().int().min(0).max(5000).default(250).describe('Wait after applying each variant before scanning.'),
|
|
50
|
+
reloadBetweenVariants: z.boolean().default(false).describe('Reload page between variants.'),
|
|
51
|
+
reportFile: z.string().optional().describe('Output JSON report file name.'),
|
|
52
|
+
});
|
|
53
|
+
function normalizeMedia(variantMedia) {
|
|
54
|
+
return {
|
|
55
|
+
colorScheme: variantMedia?.colorScheme ?? null,
|
|
56
|
+
forcedColors: variantMedia?.forcedColors ?? null,
|
|
57
|
+
contrast: variantMedia?.contrast ?? null,
|
|
58
|
+
reducedMotion: variantMedia?.reducedMotion ?? null,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function safeIsoTimestampForFileName() {
|
|
62
|
+
return sanitizeForFilePath(new Date().toISOString());
|
|
63
|
+
}
|
|
64
|
+
function countNodesByRule(violations) {
|
|
65
|
+
const counts = {};
|
|
66
|
+
for (const violation of violations)
|
|
67
|
+
counts[violation.id] = (counts[violation.id] ?? 0) + violation.nodes.length;
|
|
68
|
+
return counts;
|
|
69
|
+
}
|
|
70
|
+
function computeDiffFromBaseline(baselineCounts, variantCounts) {
|
|
71
|
+
const baselineIds = Object.keys(baselineCounts);
|
|
72
|
+
const variantIds = Object.keys(variantCounts);
|
|
73
|
+
const newViolationIds = variantIds.filter(id => !baselineCounts[id]).sort();
|
|
74
|
+
const resolvedViolationIds = baselineIds.filter(id => !variantCounts[id]).sort();
|
|
75
|
+
const changedCounts = {};
|
|
76
|
+
const allIds = new Set([...baselineIds, ...variantIds]);
|
|
77
|
+
for (const id of allIds) {
|
|
78
|
+
const baseline = baselineCounts[id] ?? 0;
|
|
79
|
+
const variant = variantCounts[id] ?? 0;
|
|
80
|
+
if (baseline !== variant)
|
|
81
|
+
changedCounts[id] = { baseline, variant };
|
|
82
|
+
}
|
|
83
|
+
return { newViolationIds, resolvedViolationIds, changedCounts };
|
|
84
|
+
}
|
|
85
|
+
const scanPageMatrix = defineTabTool({
|
|
86
|
+
capability: 'core',
|
|
87
|
+
schema: {
|
|
88
|
+
name: 'scan_page_matrix',
|
|
89
|
+
title: 'Scan accessibility variants',
|
|
90
|
+
description: 'Run accessibility scans across viewport/media/zoom variants and compare with baseline.',
|
|
91
|
+
inputSchema: scanPageMatrixSchema,
|
|
92
|
+
type: 'destructive',
|
|
93
|
+
},
|
|
94
|
+
handle: async (tab, params, response) => {
|
|
95
|
+
const variants = params.variants ?? defaultVariants;
|
|
96
|
+
const originalViewport = tab.page.viewportSize() ?? await tab.page.evaluate(() => ({
|
|
97
|
+
width: window.innerWidth,
|
|
98
|
+
height: window.innerHeight,
|
|
99
|
+
}));
|
|
100
|
+
const originalZoom = await tab.page.evaluate(() => document.documentElement.style.zoom || '');
|
|
101
|
+
const variantResults = [];
|
|
102
|
+
try {
|
|
103
|
+
for (const variant of variants) {
|
|
104
|
+
await tab.page.setViewportSize(originalViewport);
|
|
105
|
+
await tab.page.emulateMedia({
|
|
106
|
+
colorScheme: null,
|
|
107
|
+
forcedColors: null,
|
|
108
|
+
contrast: null,
|
|
109
|
+
reducedMotion: null,
|
|
110
|
+
});
|
|
111
|
+
await tab.page.evaluate(zoom => {
|
|
112
|
+
document.documentElement.style.zoom = zoom;
|
|
113
|
+
}, originalZoom);
|
|
114
|
+
if (variant.viewport)
|
|
115
|
+
await tab.page.setViewportSize(variant.viewport);
|
|
116
|
+
if (variant.media) {
|
|
117
|
+
await tab.page.emulateMedia({
|
|
118
|
+
colorScheme: variant.media.colorScheme ?? null,
|
|
119
|
+
forcedColors: variant.media.forcedColors ?? null,
|
|
120
|
+
contrast: variant.media.contrast ?? null,
|
|
121
|
+
reducedMotion: variant.media.reducedMotion ?? null,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (variant.zoomPercent !== undefined) {
|
|
125
|
+
await tab.page.evaluate(zoomPercent => {
|
|
126
|
+
document.documentElement.style.zoom = `${zoomPercent}%`;
|
|
127
|
+
}, variant.zoomPercent);
|
|
128
|
+
}
|
|
129
|
+
if (params.reloadBetweenVariants)
|
|
130
|
+
await tab.page.reload({ waitUntil: 'domcontentloaded' });
|
|
131
|
+
await tab.waitForTimeout(params.waitAfterApplyMs);
|
|
132
|
+
const axeResult = await runAxeScan(tab.page, params.violationsTag);
|
|
133
|
+
const dedupedViolations = axeResult.violations.map(violation => ({
|
|
134
|
+
...violation,
|
|
135
|
+
nodes: dedupeAxeNodes(violation.nodes),
|
|
136
|
+
}));
|
|
137
|
+
const trimmedViolations = trimAxeResults({ violations: dedupedViolations }, { maxNodesPerViolation: params.maxNodesPerViolation });
|
|
138
|
+
const nodeCountByRuleId = countNodesByRule(dedupedViolations);
|
|
139
|
+
variantResults.push({
|
|
140
|
+
name: variant.name,
|
|
141
|
+
applied: {
|
|
142
|
+
viewport: variant.viewport ?? null,
|
|
143
|
+
media: normalizeMedia(variant.media),
|
|
144
|
+
zoomPercent: variant.zoomPercent ?? null,
|
|
145
|
+
},
|
|
146
|
+
summary: summarizeAxeViolations(trimmedViolations),
|
|
147
|
+
violations: trimmedViolations,
|
|
148
|
+
nodeCountByRuleId,
|
|
149
|
+
diffFromBaseline: {
|
|
150
|
+
newViolationIds: [],
|
|
151
|
+
resolvedViolationIds: [],
|
|
152
|
+
changedCounts: {},
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const baselineCounts = variantResults[0]?.nodeCountByRuleId ?? {};
|
|
157
|
+
for (const result of variantResults)
|
|
158
|
+
result.diffFromBaseline = computeDiffFromBaseline(baselineCounts, result.nodeCountByRuleId);
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
await tab.page.setViewportSize(originalViewport);
|
|
162
|
+
await tab.page.emulateMedia({
|
|
163
|
+
colorScheme: null,
|
|
164
|
+
forcedColors: null,
|
|
165
|
+
contrast: null,
|
|
166
|
+
reducedMotion: null,
|
|
167
|
+
});
|
|
168
|
+
await tab.page.evaluate(zoom => {
|
|
169
|
+
document.documentElement.style.zoom = zoom;
|
|
170
|
+
}, originalZoom);
|
|
171
|
+
}
|
|
172
|
+
const report = {
|
|
173
|
+
version: 'v1',
|
|
174
|
+
metadata: {
|
|
175
|
+
url: tab.page.url(),
|
|
176
|
+
baselineVariant: variantResults[0]?.name ?? 'baseline',
|
|
177
|
+
options: {
|
|
178
|
+
violationsTag: params.violationsTag,
|
|
179
|
+
maxNodesPerViolation: params.maxNodesPerViolation,
|
|
180
|
+
waitAfterApplyMs: params.waitAfterApplyMs,
|
|
181
|
+
reloadBetweenVariants: params.reloadBetweenVariants,
|
|
182
|
+
},
|
|
183
|
+
generatedAt: new Date().toISOString(),
|
|
184
|
+
},
|
|
185
|
+
variants: variantResults,
|
|
186
|
+
};
|
|
187
|
+
const reportFileName = sanitizeForFilePath(params.reportFile ?? `scan-matrix-${safeIsoTimestampForFileName()}.json`);
|
|
188
|
+
const reportPath = await tab.context.outputFile(reportFileName);
|
|
189
|
+
await fs.promises.writeFile(reportPath, JSON.stringify(report, null, 2), 'utf-8');
|
|
190
|
+
const lines = [
|
|
191
|
+
'Variant | Violations | Nodes | Top new vs baseline',
|
|
192
|
+
'--- | --- | --- | ---',
|
|
193
|
+
...variantResults.map(result => {
|
|
194
|
+
const topNew = result.diffFromBaseline.newViolationIds.slice(0, 5).join(', ') || '-';
|
|
195
|
+
return `${result.name} | ${result.summary.totalRules} | ${result.summary.totalNodes} | ${topNew}`;
|
|
196
|
+
}),
|
|
197
|
+
'',
|
|
198
|
+
`JSON report: ${reportPath}`,
|
|
199
|
+
];
|
|
200
|
+
response.addCode('// Applied viewport/media/zoom variants and compared Axe deltas against baseline.');
|
|
201
|
+
response.addResult(lines.join('\n'));
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
export default [
|
|
205
|
+
scanPageMatrix,
|
|
206
|
+
];
|
|
207
|
+
//# sourceMappingURL=scanPageMatrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanPageMatrix.js","sourceRoot":"","sources":["../../src/tools/scanPageMatrix.ts"],"names":[],"mappings":"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"}
|
package/lib/tools/snapshot.js
CHANGED
|
@@ -17,31 +17,14 @@ import { z } from 'zod';
|
|
|
17
17
|
import { defineTabTool, defineTool } from './tool.js';
|
|
18
18
|
import * as javascript from '../utils/codegen.js';
|
|
19
19
|
import { generateLocator } from './utils.js';
|
|
20
|
-
import
|
|
21
|
-
const tagValues = [
|
|
22
|
-
'wcag2a', 'wcag2aa', 'wcag2aaa', 'wcag21a', 'wcag21aa', 'wcag21aaa',
|
|
23
|
-
'wcag22a', 'wcag22aa', 'wcag22aaa', 'section508', 'cat.aria', 'cat.color',
|
|
24
|
-
'cat.forms', 'cat.keyboard', 'cat.language', 'cat.name-role-value',
|
|
25
|
-
'cat.parsing', 'cat.semantics', 'cat.sensory-and-visual-cues',
|
|
26
|
-
'cat.structure', 'cat.tables', 'cat.text-alternatives', 'cat.time-and-media',
|
|
27
|
-
];
|
|
20
|
+
import { axeTagValues, dedupeAxeNodes, runAxeScan } from './axe.js';
|
|
28
21
|
const scanPageSchema = z.object({
|
|
29
22
|
violationsTag: z
|
|
30
|
-
.array(z.enum(
|
|
23
|
+
.array(z.enum(axeTagValues))
|
|
31
24
|
.min(1)
|
|
32
|
-
.default([...
|
|
25
|
+
.default([...axeTagValues])
|
|
33
26
|
.describe('Array of tags to filter violations by. If not specified, all violations are returned.')
|
|
34
27
|
});
|
|
35
|
-
const dedupeViolationNodes = (nodes) => {
|
|
36
|
-
const seen = new Set();
|
|
37
|
-
return nodes.filter(node => {
|
|
38
|
-
const key = JSON.stringify({ target: node.target ?? [], html: node.html ?? '' });
|
|
39
|
-
if (seen.has(key))
|
|
40
|
-
return false;
|
|
41
|
-
seen.add(key);
|
|
42
|
-
return true;
|
|
43
|
-
});
|
|
44
|
-
};
|
|
45
28
|
const scanPage = defineTool({
|
|
46
29
|
capability: 'core',
|
|
47
30
|
schema: {
|
|
@@ -53,15 +36,14 @@ const scanPage = defineTool({
|
|
|
53
36
|
},
|
|
54
37
|
handle: async (context, params, response) => {
|
|
55
38
|
const tab = context.currentTabOrDie();
|
|
56
|
-
const
|
|
57
|
-
const results = await axe.analyze();
|
|
39
|
+
const results = await runAxeScan(tab.page, params.violationsTag);
|
|
58
40
|
response.addResult([
|
|
59
41
|
`URL: ${results.url}`,
|
|
60
42
|
'',
|
|
61
43
|
`Violations: ${results.violations.length}, Incomplete: ${results.incomplete.length}, Passes: ${results.passes.length}, Inapplicable: ${results.inapplicable.length}`,
|
|
62
44
|
].join('\n'));
|
|
63
45
|
results.violations.forEach(violation => {
|
|
64
|
-
const uniqueNodes =
|
|
46
|
+
const uniqueNodes = dedupeAxeNodes(violation.nodes);
|
|
65
47
|
response.addResult([
|
|
66
48
|
'',
|
|
67
49
|
`Tags : ${violation.tags}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/tools/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/tools/snapshot.ts"],"names":[],"mappings":"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"}
|
package/lib/tools.js
CHANGED
|
@@ -30,6 +30,9 @@ import tabs from './tools/tabs.js';
|
|
|
30
30
|
import screenshot from './tools/screenshot.js';
|
|
31
31
|
import wait from './tools/wait.js';
|
|
32
32
|
import verify from './tools/verify.js';
|
|
33
|
+
import auditSite from './tools/auditSite.js';
|
|
34
|
+
import scanPageMatrix from './tools/scanPageMatrix.js';
|
|
35
|
+
import auditKeyboard from './tools/auditKeyboard.js';
|
|
33
36
|
export const allTools = [
|
|
34
37
|
...common,
|
|
35
38
|
...console,
|
|
@@ -48,6 +51,9 @@ export const allTools = [
|
|
|
48
51
|
...tabs,
|
|
49
52
|
...wait,
|
|
50
53
|
...verify,
|
|
54
|
+
...auditSite,
|
|
55
|
+
...scanPageMatrix,
|
|
56
|
+
...auditKeyboard,
|
|
51
57
|
];
|
|
52
58
|
export function filteredTools(config) {
|
|
53
59
|
return allTools.filter(tool => tool.capability.startsWith('core') || config.capabilities?.includes(tool.capability));
|
package/lib/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,KAAK,MAAM,kBAAkB,CAAC;AACrC,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,KAAK,MAAM,kBAAkB,CAAC;AACrC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,GAAG,MAAM,gBAAgB,CAAC;AACjC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,UAAU,MAAM,uBAAuB,CAAC;AAC/C,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,MAAM,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,KAAK,MAAM,kBAAkB,CAAC;AACrC,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,KAAK,MAAM,kBAAkB,CAAC;AACrC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,GAAG,MAAM,gBAAgB,CAAC;AACjC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,UAAU,MAAM,uBAAuB,CAAC;AAC/C,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,SAAS,MAAM,sBAAsB,CAAC;AAC7C,OAAO,cAAc,MAAM,2BAA2B,CAAC;AACvD,OAAO,aAAa,MAAM,0BAA0B,CAAC;AAKrD,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,GAAG,MAAM;IACT,GAAG,OAAO;IACV,GAAG,OAAO;IACV,GAAG,QAAQ;IACX,GAAG,KAAK;IACR,GAAG,IAAI;IACP,GAAG,OAAO;IACV,GAAG,QAAQ;IACX,GAAG,QAAQ;IACX,GAAG,OAAO;IACV,GAAG,KAAK;IACR,GAAG,GAAG;IACN,GAAG,UAAU;IACb,GAAG,QAAQ;IACX,GAAG,IAAI;IACP,GAAG,IAAI;IACP,GAAG,MAAM;IACT,GAAG,SAAS;IACZ,GAAG,cAAc;IACjB,GAAG,aAAa;CACjB,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,MAAkB;IAC9C,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AACvH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-accessibility-scanner",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"mcpName": "io.github.JustasMonkev/mcp-accessibility-scanner",
|
|
5
5
|
"description": "A Model Context Protocol (MCP) server for performing automated accessibility scans of web pages using Playwright and Axe-core",
|
|
6
6
|
"type": "module",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"mime": "^4.1.0",
|
|
43
43
|
"playwright": "^1.58.1",
|
|
44
44
|
"playwright-core": "^1.58.1",
|
|
45
|
+
"re2": "^1.23.2",
|
|
45
46
|
"ws": "^8.19.0",
|
|
46
47
|
"zod": "^4.3.6"
|
|
47
48
|
},
|