mcp-accessibility-scanner 2.0.4 → 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/browserServerBackend.js.map +1 -1
- package/lib/mcp/proxyBackend.js +2 -3
- package/lib/mcp/proxyBackend.js.map +1 -1
- package/lib/mcp/tool.js +2 -2
- package/lib/mcp/tool.js.map +1 -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/lib/vscode/host.js +1 -2
- package/lib/vscode/host.js.map +1 -1
- package/package.json +24 -24
|
@@ -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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"}
|