mcp-accessibility-scanner 3.0.1 → 3.2.0
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 +265 -12
- package/index.d.ts +1 -1
- package/lib/browserContextFactory.js +1161 -94
- package/lib/browserContextFactory.js.map +1 -1
- package/lib/browserServerBackend.js +199 -22
- package/lib/browserServerBackend.js.map +1 -1
- package/lib/browserSessions.js +172 -0
- package/lib/browserSessions.js.map +1 -0
- package/lib/config.js +48 -7
- package/lib/config.js.map +1 -1
- package/lib/context.js +321 -71
- package/lib/context.js.map +1 -1
- package/lib/extension/cdpRelay.js +5 -0
- package/lib/extension/cdpRelay.js.map +1 -1
- package/lib/extension/extensionContextFactory.js +12 -1
- package/lib/extension/extensionContextFactory.js.map +1 -1
- package/lib/index.js +5 -1
- package/lib/index.js.map +1 -1
- package/lib/mcp/http.js +194 -44
- package/lib/mcp/http.js.map +1 -1
- package/lib/mcp/inProcessTransport.js.map +1 -1
- package/lib/mcp/mdb.js +7 -9
- package/lib/mcp/mdb.js.map +1 -1
- package/lib/mcp/proxyBackend.js +76 -18
- package/lib/mcp/proxyBackend.js.map +1 -1
- package/lib/mcp/server.js +70 -41
- package/lib/mcp/server.js.map +1 -1
- package/lib/mcp/sharedClientSlot.js +134 -0
- package/lib/mcp/sharedClientSlot.js.map +1 -0
- package/lib/mcp/tool.js +3 -0
- package/lib/mcp/tool.js.map +1 -1
- package/lib/networkPolicy.js +73 -0
- package/lib/networkPolicy.js.map +1 -0
- package/lib/program.js +91 -12
- package/lib/program.js.map +1 -1
- package/lib/response.js +16 -3
- package/lib/response.js.map +1 -1
- package/lib/sessionLog.js +36 -6
- package/lib/sessionLog.js.map +1 -1
- package/lib/tab.js +149 -18
- package/lib/tab.js.map +1 -1
- package/lib/tools/auditKeyboard.js +204 -4
- package/lib/tools/auditKeyboard.js.map +1 -1
- package/lib/tools/auditScreenReader.js +823 -0
- package/lib/tools/auditScreenReader.js.map +1 -0
- package/lib/tools/auditSite.js +268 -90
- package/lib/tools/auditSite.js.map +1 -1
- package/lib/tools/axe.js +479 -21
- package/lib/tools/axe.js.map +1 -1
- package/lib/tools/dialogs.js +18 -4
- package/lib/tools/dialogs.js.map +1 -1
- package/lib/tools/evaluate.js +34 -5
- package/lib/tools/evaluate.js.map +1 -1
- package/lib/tools/network.js +136 -8
- package/lib/tools/network.js.map +1 -1
- package/lib/tools/pdf.js +5 -2
- package/lib/tools/pdf.js.map +1 -1
- package/lib/tools/scanPageMatrix.js +135 -47
- package/lib/tools/scanPageMatrix.js.map +1 -1
- package/lib/tools/screenshot.js +8 -4
- package/lib/tools/screenshot.js.map +1 -1
- package/lib/tools/session.js +53 -0
- package/lib/tools/session.js.map +1 -0
- package/lib/tools/snapshot.js +266 -8
- package/lib/tools/snapshot.js.map +1 -1
- package/lib/tools/tool.js.map +1 -1
- package/lib/tools/utils.js +62 -6
- package/lib/tools/utils.js.map +1 -1
- package/lib/tools.js +11 -2
- package/lib/tools.js.map +1 -1
- package/lib/utils/dataUrl.js +58 -35
- package/lib/utils/dataUrl.js.map +1 -1
- package/lib/utils/fileUtils.js +35 -0
- package/lib/utils/fileUtils.js.map +1 -1
- package/lib/utils/guid.js +8 -0
- package/lib/utils/guid.js.map +1 -1
- package/lib/utils/jsSource.js +187 -0
- package/lib/utils/jsSource.js.map +1 -0
- package/lib/vscode/browserContextFactory.js +87 -0
- package/lib/vscode/browserContextFactory.js.map +1 -0
- package/lib/vscode/host.js +189 -33
- package/lib/vscode/host.js.map +1 -1
- package/lib/vscode/main.js +3 -35
- package/lib/vscode/main.js.map +1 -1
- package/package.json +13 -9
package/lib/tab.js
CHANGED
|
@@ -18,9 +18,12 @@ import { callOnPageNoTrace, waitForCompletion } from './tools/utils.js';
|
|
|
18
18
|
import { logUnhandledError } from './utils/log.js';
|
|
19
19
|
import { ManualPromise } from './mcp/manualPromise.js';
|
|
20
20
|
import { truncateDataUrls } from './utils/dataUrl.js';
|
|
21
|
+
import { safeIsoTimestampForFileName, truncateToUtf8Bytes } from './utils/fileUtils.js';
|
|
21
22
|
export const TabEvents = {
|
|
22
23
|
modalState: 'modalState'
|
|
23
24
|
};
|
|
25
|
+
class StaleAriaSnapshotError extends Error {
|
|
26
|
+
}
|
|
24
27
|
export class Tab extends EventEmitter {
|
|
25
28
|
context;
|
|
26
29
|
page;
|
|
@@ -33,34 +36,72 @@ export class Tab extends EventEmitter {
|
|
|
33
36
|
_modalStates = [];
|
|
34
37
|
_downloads = [];
|
|
35
38
|
_defaultTimeout;
|
|
39
|
+
// The aria snapshot last handed to the caller; the refs in it are the refs the
|
|
40
|
+
// next tool call will name. Cleared whenever the page it described is gone.
|
|
41
|
+
_lastAriaSnapshot;
|
|
42
|
+
_ariaSnapshotGeneration = 0;
|
|
43
|
+
_pageGeneration = 0;
|
|
44
|
+
_pageListeners = [];
|
|
36
45
|
constructor(context, page, onPageClose) {
|
|
37
46
|
super();
|
|
38
47
|
this.context = context;
|
|
39
48
|
this.page = page;
|
|
40
49
|
this._onPageClose = onPageClose;
|
|
41
50
|
this._defaultTimeout = context.config.timeouts.defaultTimeout ?? 6000;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
// Registered through a tracked list so dispose() can take them off again:
|
|
52
|
+
// on a shared (non-isolated CDP) context the page outlives the session,
|
|
53
|
+
// and listeners left behind would pile up with session churn.
|
|
54
|
+
const listen = (event, listener) => {
|
|
55
|
+
page.on(event, listener);
|
|
56
|
+
this._pageListeners.push({ event, listener });
|
|
57
|
+
};
|
|
58
|
+
// Every document swap invalidates the cached snapshot, whoever caused it:
|
|
59
|
+
// goBack(), page.reload() from scan_page_matrix, a meta refresh, or the page
|
|
60
|
+
// assigning location itself. Tab.navigate() is only one of those routes, and
|
|
61
|
+
// a ref resolved against the page the user has left would target the wrong
|
|
62
|
+
// document.
|
|
63
|
+
listen('framenavigated', (frame) => {
|
|
64
|
+
if (!frame.parentFrame()) {
|
|
65
|
+
++this._pageGeneration;
|
|
66
|
+
this._invalidateAriaSnapshot();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
listen('console', event => this._handleConsoleMessage(messageToConsoleMessage(event)));
|
|
70
|
+
listen('pageerror', error => this._handleConsoleMessage(pageErrorToConsoleMessage(error)));
|
|
71
|
+
listen('request', request => this._requests.set(request, null));
|
|
72
|
+
listen('response', response => this._handleResponse(response));
|
|
73
|
+
listen('close', () => this._onClose());
|
|
74
|
+
listen('filechooser', chooser => {
|
|
48
75
|
this.setModalState({
|
|
49
76
|
type: 'fileChooser',
|
|
50
77
|
description: 'File chooser',
|
|
51
78
|
fileChooser: chooser,
|
|
52
79
|
});
|
|
53
80
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
81
|
+
listen('dialog', dialog => this._dialogShown(dialog));
|
|
82
|
+
// Fires on Playwright >= 1.63 when a dialog is closed out of band (e.g.
|
|
83
|
+
// dismissed manually in headed mode or via a CDP side-channel); inert on
|
|
84
|
+
// the pinned 1.62.0, which never emits it. Until then a stale dialog
|
|
85
|
+
// modal state blocks every snapshot-bearing tool until the user re-issues
|
|
86
|
+
// browser_handle_dialog, whose already-closed fallback (tools/dialogs.ts)
|
|
87
|
+
// recovers the session on the pinned version.
|
|
88
|
+
listen('dialogclosed', dialog => this._dialogClosed(dialog));
|
|
89
|
+
listen('download', download => {
|
|
90
|
+
// Tracked on the Context: the save outlives this tool call (and can
|
|
91
|
+
// outlive the tab), and context disposal must wait for it instead of
|
|
92
|
+
// closing the browser mid-stream. The context also owns the promise's
|
|
93
|
+
// rejection handling.
|
|
94
|
+
this.context.trackPendingDownload(this._downloadStarted(download));
|
|
57
95
|
});
|
|
58
96
|
page.setDefaultNavigationTimeout(context.config.timeouts.navigationTimeout ?? 30000);
|
|
59
97
|
page.setDefaultTimeout(this._defaultTimeout);
|
|
60
|
-
_pageTabMap.set(page, this);
|
|
61
98
|
}
|
|
62
|
-
|
|
63
|
-
|
|
99
|
+
// Detaches this wrapper from its page without closing the page: the page
|
|
100
|
+
// can belong to a shared context that outlives the session.
|
|
101
|
+
dispose() {
|
|
102
|
+
for (const { event, listener } of this._pageListeners)
|
|
103
|
+
this.page.off(event, listener);
|
|
104
|
+
this._pageListeners = [];
|
|
64
105
|
}
|
|
65
106
|
modalStates() {
|
|
66
107
|
return this._modalStates;
|
|
@@ -82,11 +123,41 @@ export class Tab extends EventEmitter {
|
|
|
82
123
|
dialog,
|
|
83
124
|
});
|
|
84
125
|
}
|
|
126
|
+
_dialogClosed(dialog) {
|
|
127
|
+
const state = this._modalStates.find(state => state.type === 'dialog' && state.dialog === dialog);
|
|
128
|
+
if (state)
|
|
129
|
+
this.clearModalState(state);
|
|
130
|
+
}
|
|
85
131
|
async _downloadStarted(download) {
|
|
132
|
+
// The suggested name alone is not collision-safe: sessions share one
|
|
133
|
+
// output directory, and two downloads suggesting "report.pdf" would
|
|
134
|
+
// overwrite each other. The same {timestamp}-{token} fragment the other
|
|
135
|
+
// default artifact names carry goes in before the extension, keeping the
|
|
136
|
+
// suggested name as the recognizable part; responses print the suggested
|
|
137
|
+
// name next to the saved path, so the file stays attributable.
|
|
138
|
+
const suggested = download.suggestedFilename() || 'download';
|
|
139
|
+
const separator = suggested.lastIndexOf('.');
|
|
140
|
+
let base = separator > 0 ? suggested.slice(0, separator) : suggested;
|
|
141
|
+
let extension = separator > 0 ? suggested.slice(separator) : '';
|
|
142
|
+
const uniqueSuffix = `-${safeIsoTimestampForFileName()}`;
|
|
143
|
+
// Filesystems cap a single name component at 255 bytes, and a long but
|
|
144
|
+
// valid Content-Disposition name plus the ~35-byte suffix used to fail
|
|
145
|
+
// saveAs() with ENAMETOOLONG. The recognizable part is truncated by BYTE
|
|
146
|
+
// length (UTF-8, whole code points) so extension and uniqueness suffix
|
|
147
|
+
// survive intact; a pathological "extension" too long to leave any base
|
|
148
|
+
// is just part of one long name and is truncated with it.
|
|
149
|
+
const maxNameBytes = 255;
|
|
150
|
+
let baseBudget = maxNameBytes - Buffer.byteLength(uniqueSuffix, 'utf8') - Buffer.byteLength(extension, 'utf8');
|
|
151
|
+
if (baseBudget < 1) {
|
|
152
|
+
base = suggested;
|
|
153
|
+
extension = '';
|
|
154
|
+
baseBudget = maxNameBytes - Buffer.byteLength(uniqueSuffix, 'utf8');
|
|
155
|
+
}
|
|
156
|
+
const uniqueName = `${truncateToUtf8Bytes(base, baseBudget)}${uniqueSuffix}${extension}`;
|
|
86
157
|
const entry = {
|
|
87
158
|
download,
|
|
88
159
|
finished: false,
|
|
89
|
-
outputFile: await this.context.outputFile(
|
|
160
|
+
outputFile: await this.context.outputFile(uniqueName)
|
|
90
161
|
};
|
|
91
162
|
this._downloads.push(entry);
|
|
92
163
|
await download.saveAs(entry.outputFile);
|
|
@@ -97,6 +168,12 @@ export class Tab extends EventEmitter {
|
|
|
97
168
|
this._recentConsoleMessages.length = 0;
|
|
98
169
|
this._requests.clear();
|
|
99
170
|
this._mainDocumentStatus = undefined;
|
|
171
|
+
++this._pageGeneration;
|
|
172
|
+
this._invalidateAriaSnapshot();
|
|
173
|
+
}
|
|
174
|
+
_invalidateAriaSnapshot() {
|
|
175
|
+
++this._ariaSnapshotGeneration;
|
|
176
|
+
this._lastAriaSnapshot = undefined;
|
|
100
177
|
}
|
|
101
178
|
_handleConsoleMessage(message) {
|
|
102
179
|
this._consoleMessages.push(message);
|
|
@@ -172,12 +249,28 @@ export class Tab extends EventEmitter {
|
|
|
172
249
|
requests() {
|
|
173
250
|
return this._requests;
|
|
174
251
|
}
|
|
252
|
+
// Playwright resolves `Request.allHeaders()` and `Response.body()` with no
|
|
253
|
+
// timeout of their own, so a still-streaming response would hang a tool call
|
|
254
|
+
// until the page closed. Callers outside this class need the same bound the
|
|
255
|
+
// page-state reads above use.
|
|
256
|
+
async withPageStateTimeout(promise, description) {
|
|
257
|
+
return this._withPageStateTimeout(promise, description);
|
|
258
|
+
}
|
|
175
259
|
async captureSnapshot() {
|
|
176
260
|
let tabSnapshot;
|
|
261
|
+
const capture = { valid: true };
|
|
262
|
+
const snapshotGeneration = this._ariaSnapshotGeneration;
|
|
177
263
|
const modalStates = await this._raceAgainstModalStates(async () => {
|
|
178
264
|
const [snapshot, title] = await Promise.all([
|
|
179
|
-
this._withPageStateTimeout(this.
|
|
180
|
-
|
|
265
|
+
this._withPageStateTimeout(this._captureAriaSnapshot(capture), 'capturing page accessibility snapshot').catch(error => {
|
|
266
|
+
// Nothing describes the page any more, and the refs of an older
|
|
267
|
+
// snapshot must not be trusted against it.
|
|
268
|
+
if (!(error instanceof StaleAriaSnapshotError)) {
|
|
269
|
+
capture.valid = false;
|
|
270
|
+
logUnhandledError(error);
|
|
271
|
+
if (snapshotGeneration === this._ariaSnapshotGeneration)
|
|
272
|
+
this._invalidateAriaSnapshot();
|
|
273
|
+
}
|
|
181
274
|
return `# Page snapshot unavailable: ${formatPageStateError(error)}`;
|
|
182
275
|
}),
|
|
183
276
|
this._withPageStateTimeout(this.page.title(), 'reading page title').catch(error => {
|
|
@@ -201,6 +294,10 @@ export class Tab extends EventEmitter {
|
|
|
201
294
|
tabSnapshot.consoleMessages = this._recentConsoleMessages;
|
|
202
295
|
this._recentConsoleMessages = [];
|
|
203
296
|
}
|
|
297
|
+
if (!tabSnapshot) {
|
|
298
|
+
capture.valid = false;
|
|
299
|
+
this._invalidateAriaSnapshot();
|
|
300
|
+
}
|
|
204
301
|
return tabSnapshot ?? {
|
|
205
302
|
url: this.page.url(),
|
|
206
303
|
title: '',
|
|
@@ -255,13 +352,48 @@ export class Tab extends EventEmitter {
|
|
|
255
352
|
return (await this.refLocators([params]))[0];
|
|
256
353
|
}
|
|
257
354
|
async refLocators(params) {
|
|
258
|
-
|
|
355
|
+
// The refs a caller passes come from the snapshot the last tool call
|
|
356
|
+
// returned, which is the one cached here, so the common case needs no fresh
|
|
357
|
+
// capture. Playwright keeps a ref bound to the element it was issued for,
|
|
358
|
+
// but that element can change its accessible role or name while staying
|
|
359
|
+
// connected. Re-checking only the referenced nodes is still cheaper than a
|
|
360
|
+
// full-page snapshot and prevents an old ref from targeting repurposed UI.
|
|
361
|
+
const cached = this._lastAriaSnapshot;
|
|
362
|
+
const snapshot = cached && await this._refsMatchSnapshot(params, cached)
|
|
363
|
+
? cached
|
|
364
|
+
: await this._captureAriaSnapshot();
|
|
259
365
|
return params.map(param => {
|
|
260
366
|
if (!snapshot.includes(`[ref=${param.ref}]`))
|
|
261
367
|
throw new Error(`Ref ${param.ref} not found in the current page snapshot. Try capturing new snapshot.`);
|
|
262
368
|
return this.page.locator(`aria-ref=${param.ref}`).describe(param.element);
|
|
263
369
|
});
|
|
264
370
|
}
|
|
371
|
+
async _refsMatchSnapshot(params, snapshot) {
|
|
372
|
+
const pageGeneration = this._pageGeneration;
|
|
373
|
+
const lines = snapshot.split('\n');
|
|
374
|
+
const timeout = Math.min(this._pageStateTimeoutMs(), 1000);
|
|
375
|
+
const matches = await Promise.all(params.map(async (param) => {
|
|
376
|
+
const cached = lines.find(line => line.includes(`[ref=${param.ref}]`));
|
|
377
|
+
if (!cached)
|
|
378
|
+
return false;
|
|
379
|
+
const current = await this.page.locator(`aria-ref=${param.ref}`)
|
|
380
|
+
.ariaSnapshot({ mode: 'ai', depth: 1, timeout })
|
|
381
|
+
.catch(() => '');
|
|
382
|
+
// Refs are assigned from the full role and name before long names are
|
|
383
|
+
// omitted from rendering, so a semantic change still changes this line.
|
|
384
|
+
return current.split('\n', 1)[0]?.trim() === cached.trim();
|
|
385
|
+
}));
|
|
386
|
+
return pageGeneration === this._pageGeneration && matches.every(Boolean);
|
|
387
|
+
}
|
|
388
|
+
async _captureAriaSnapshot(capture = { valid: true }) {
|
|
389
|
+
const pageGeneration = this._pageGeneration;
|
|
390
|
+
const snapshot = await this.page.ariaSnapshot({ mode: 'ai' });
|
|
391
|
+
if (!capture.valid || pageGeneration !== this._pageGeneration)
|
|
392
|
+
throw new StaleAriaSnapshotError('Page changed while capturing accessibility snapshot.');
|
|
393
|
+
++this._ariaSnapshotGeneration;
|
|
394
|
+
this._lastAriaSnapshot = snapshot;
|
|
395
|
+
return snapshot;
|
|
396
|
+
}
|
|
265
397
|
async waitForTimeout(time) {
|
|
266
398
|
if (this._javaScriptBlocked()) {
|
|
267
399
|
await new Promise(f => setTimeout(f, time));
|
|
@@ -301,10 +433,9 @@ export function renderModalStates(context, modalStates) {
|
|
|
301
433
|
if (modalStates.length === 0)
|
|
302
434
|
result.push('- There is no modal state present');
|
|
303
435
|
for (const state of modalStates) {
|
|
304
|
-
const tool = context.tools.
|
|
436
|
+
const tool = context.tools.find(tool => tool.clearsModalState === state.type);
|
|
305
437
|
result.push(`- [${truncateDataUrls(state.description)}]: can be handled by the "${tool?.schema.name}" tool`);
|
|
306
438
|
}
|
|
307
439
|
return result;
|
|
308
440
|
}
|
|
309
|
-
const _pageTabMap = new WeakMap();
|
|
310
441
|
//# sourceMappingURL=tab.js.map
|
package/lib/tab.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tab.js","sourceRoot":"","sources":["../src/tab.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tab.js","sourceRoot":"","sources":["../src/tab.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAKxF,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,UAAU,EAAE,YAAY;CACzB,CAAC;AAgBF,MAAM,sBAAuB,SAAQ,KAAK;CAAG;AAE7C,MAAM,OAAO,GAAI,SAAQ,YAAgC;IAC9C,OAAO,CAAU;IACjB,IAAI,CAAkB;IACvB,UAAU,GAAG,aAAa,CAAC;IAC3B,gBAAgB,GAAqB,EAAE,CAAC;IACxC,sBAAsB,GAAqB,EAAE,CAAC;IAC9C,SAAS,GAAwD,IAAI,GAAG,EAAE,CAAC;IAC3E,mBAAmB,CAAqD;IACxE,YAAY,CAAqB;IACjC,YAAY,GAAiB,EAAE,CAAC;IAChC,UAAU,GAA+E,EAAE,CAAC;IAC5F,eAAe,CAAS;IAChC,+EAA+E;IAC/E,4EAA4E;IACpE,iBAAiB,CAAqB;IACtC,uBAAuB,GAAG,CAAC,CAAC;IAC5B,eAAe,GAAG,CAAC,CAAC;IAEpB,cAAc,GAA4D,EAAE,CAAC;IAErF,YAAY,OAAgB,EAAE,IAAqB,EAAE,WAA+B;QAClF,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,IAAI,IAAI,CAAC;QACtE,0EAA0E;QAC1E,wEAAwE;QACxE,8DAA8D;QAC9D,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,QAAkC,EAAE,EAAE;YACnE,IAAI,CAAC,EAAE,CAAC,KAAY,EAAE,QAAQ,CAAC,CAAC;YAChC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChD,CAAC,CAAC;QACF,0EAA0E;QAC1E,6EAA6E;QAC7E,6EAA6E;QAC7E,2EAA2E;QAC3E,YAAY;QACZ,MAAM,CAAC,gBAAgB,EAAE,CAAC,KAAuB,EAAE,EAAE;YACnD,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACzB,EAAE,IAAI,CAAC,eAAe,CAAC;gBACvB,IAAI,CAAC,uBAAuB,EAAE,CAAC;YACjC,CAAC;QACH,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACvF,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3F,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACvC,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,EAAE;YAC9B,IAAI,CAAC,aAAa,CAAC;gBACjB,IAAI,EAAE,aAAa;gBACnB,WAAW,EAAE,cAAc;gBAC3B,WAAW,EAAE,OAAO;aACrB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;QACtD,wEAAwE;QACxE,yEAAyE;QACzE,qEAAqE;QACrE,0EAA0E;QAC1E,0EAA0E;QAC1E,8CAA8C;QAC9C,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7D,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE;YAC5B,oEAAoE;YACpE,qEAAqE;YACrE,sEAAsE;YACtE,sBAAsB;YACtB,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,IAAI,KAAK,CAAC,CAAC;QACrF,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC/C,CAAC;IAED,yEAAyE;IACzE,4DAA4D;IAC5D,OAAO;QACL,KAAK,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC,cAAc;YACnD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAY,EAAE,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,aAAa,CAAC,UAAsB;QAClC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAC9C,CAAC;IAED,eAAe,CAAC,UAAsB;QACpC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC;IAC9E,CAAC;IAED,mBAAmB;QACjB,OAAO,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7D,CAAC;IAEO,YAAY,CAAC,MAAyB;QAC5C,IAAI,CAAC,aAAa,CAAC;YACjB,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,IAAI,MAAM,CAAC,IAAI,EAAE,0BAA0B,MAAM,CAAC,OAAO,EAAE,GAAG;YAC3E,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,MAAyB;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QAClG,IAAI,KAAK;YACP,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,QAA6B;QAC1D,qEAAqE;QACrE,oEAAoE;QACpE,wEAAwE;QACxE,yEAAyE;QACzE,yEAAyE;QACzE,+DAA+D;QAC/D,MAAM,SAAS,GAAG,QAAQ,CAAC,iBAAiB,EAAE,IAAI,UAAU,CAAC;QAC7D,MAAM,SAAS,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,IAAI,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrE,IAAI,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,YAAY,GAAG,IAAI,2BAA2B,EAAE,EAAE,CAAC;QACzD,uEAAuE;QACvE,uEAAuE;QACvE,yEAAyE;QACzE,uEAAuE;QACvE,wEAAwE;QACxE,0DAA0D;QAC1D,MAAM,YAAY,GAAG,GAAG,CAAC;QACzB,IAAI,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC/G,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,IAAI,GAAG,SAAS,CAAC;YACjB,SAAS,GAAG,EAAE,CAAC;YACf,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,UAAU,GAAG,GAAG,mBAAmB,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,YAAY,GAAG,SAAS,EAAE,CAAC;QACzF,MAAM,KAAK,GAAG;YACZ,QAAQ;YACR,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;SACtD,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,MAAM,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACxC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACxB,CAAC;IAEO,wBAAwB;QAC9B,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,sBAAsB,CAAC,MAAM,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;QACrC,EAAE,IAAI,CAAC,eAAe,CAAC;QACvB,IAAI,CAAC,uBAAuB,EAAE,CAAC;IACjC,CAAC;IAEO,uBAAuB;QAC7B,EAAE,IAAI,CAAC,uBAAuB,CAAC;QAC/B,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;IACrC,CAAC;IAEO,qBAAqB,CAAC,OAAuB;QACnD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAEO,eAAe,CAAC,QAA6B;QACnD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACtC,IAAI,OAAO,CAAC,mBAAmB,EAAE,IAAI,QAAQ,CAAC,KAAK,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;YACxG,IAAI,CAAC,mBAAmB,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC;IAChG,CAAC;IAEO,QAAQ;QACd,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAChC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,IAAI,CAAC,uBAAuB,CAAC,KAAK,IAAI,EAAE;YAC5C,IAAI,CAAC;gBACH,IAAI,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAC9C,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAClD,oBAAoB,EACpB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,IAAI,CAAC,CAC7C,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,iBAAiB,CAAC,OAAe;QAC/B,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,YAAY;QACV,OAAO,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,KAAa,EAAE,OAA8B;QAClE,MAAM,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC7G,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAW;QACxB,IAAI,CAAC,wBAAwB,EAAE,CAAC;QAEhC,MAAM,aAAa,GAAG,IAAI,aAAa,EAAuB,CAAC;QAC/D,MAAM,gBAAgB,GAAG,CAAC,QAA6B,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5F,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;QAC7C,IAAI,CAAC;YACH,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC/D,CAAC;YAAC,OAAO,EAAW,EAAE,CAAC;gBACrB,MAAM,CAAC,GAAG,EAAW,CAAC;gBACtB,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC;oBAC7C,MAAM,CAAC,CAAC;gBACV,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBAChH,IAAI,CAAC,QAAQ;oBACX,MAAM,CAAC,CAAC;gBACV,2DAA2D;gBAC3D,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;gBACvD,OAAO;YACT,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;QAC9C,CAAC;QAED,sEAAsE;QACtE,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,CAAC,OAAkD;QACvD,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,2EAA2E;IAC3E,6EAA6E;IAC7E,4EAA4E;IAC5E,8BAA8B;IAC9B,KAAK,CAAC,oBAAoB,CAAI,OAAmB,EAAE,WAAmB;QACpE,OAAO,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,IAAI,WAAoC,CAAC;QACzC,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAChC,MAAM,kBAAkB,GAAG,IAAI,CAAC,uBAAuB,CAAC;QACxD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,KAAK,IAAI,EAAE;YAChE,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAC1C,IAAI,CAAC,qBAAqB,CACtB,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAClC,uCAAuC,CAC1C,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;oBACd,gEAAgE;oBAChE,2CAA2C;oBAC3C,IAAI,CAAC,CAAC,KAAK,YAAY,sBAAsB,CAAC,EAAE,CAAC;wBAC/C,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;wBACtB,iBAAiB,CAAC,KAAK,CAAC,CAAC;wBACzB,IAAI,kBAAkB,KAAK,IAAI,CAAC,uBAAuB;4BACrD,IAAI,CAAC,uBAAuB,EAAE,CAAC;oBACnC,CAAC;oBACD,OAAO,gCAAgC,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvE,CAAC,CAAC;gBACF,IAAI,CAAC,qBAAqB,CACtB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,EACjB,oBAAoB,CACvB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;oBACd,iBAAiB,CAAC,KAAK,CAAC,CAAC;oBACzB,OAAO,IAAI,CAAC,UAAU,CAAC;gBACzB,CAAC,CAAC;aACH,CAAC,CAAC;YACH,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;YACxB,WAAW,GAAG;gBACZ,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;gBACpB,KAAK;gBACL,kBAAkB,EAAE,IAAI,CAAC,mBAAmB;gBAC5C,YAAY,EAAE,QAAQ;gBACtB,WAAW,EAAE,EAAE;gBACf,eAAe,EAAE,EAAE;gBACnB,SAAS,EAAE,IAAI,CAAC,UAAU;aAC3B,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,IAAI,WAAW,EAAE,CAAC;YAChB,0EAA0E;YAC1E,WAAW,CAAC,eAAe,GAAG,IAAI,CAAC,sBAAsB,CAAC;YAC1D,IAAI,CAAC,sBAAsB,GAAG,EAAE,CAAC;QACnC,CAAC;QACD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;YACtB,IAAI,CAAC,uBAAuB,EAAE,CAAC;QACjC,CAAC;QACD,OAAO,WAAW,IAAI;YACpB,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;YACpB,KAAK,EAAE,EAAE;YACT,kBAAkB,EAAE,IAAI,CAAC,mBAAmB;YAC5C,YAAY,EAAE,EAAE;YAChB,WAAW;YACX,eAAe,EAAE,EAAE;YACnB,SAAS,EAAE,EAAE;SACd,CAAC;IACJ,CAAC;IAEO,kBAAkB;QACxB,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAClE,CAAC;IAEO,mBAAmB;QACzB,OAAO,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,CAAC;IAEO,KAAK,CAAC,qBAAqB,CAAI,OAAmB,EAAE,WAAmB,EAAE,SAAS,GAAG,IAAI,CAAC,mBAAmB,EAAE;QACrH,IAAI,SAAoD,CAAC;QACzD,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;gBACxB,OAAO;gBACP,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;oBAC/B,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;wBAC1B,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,SAAS,YAAY,WAAW,GAAG,CAAC,CAAC,CAAC;oBAC5E,CAAC,EAAE,SAAS,CAAC,CAAC;gBAChB,CAAC,CAAC;aACH,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,IAAI,SAAS;gBACX,YAAY,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,uBAAuB,CAAC,MAA2B;QAC/D,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM;YAC3B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;QAE5B,MAAM,OAAO,GAAG,IAAI,aAAa,EAAgB,CAAC;QAClD,MAAM,QAAQ,GAAG,CAAC,UAAsB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3E,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAE1C,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;YACxB,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;gBACjB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACzC,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YACF,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAA6B;QACnD,MAAM,IAAI,CAAC,uBAAuB,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAwC;QACvD,OAAO,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAA0C;QAC1D,qEAAqE;QACrE,4EAA4E;QAC5E,0EAA0E;QAC1E,wEAAwE;QACxE,2EAA2E;QAC3E,2EAA2E;QAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,MAAM,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC;YACtE,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YACxB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,KAAK,CAAC,GAAG,GAAG,CAAC;gBAC1C,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,GAAG,sEAAsE,CAAC,CAAC;YAC1G,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,MAAyB,EAAE,QAAgB;QAC1E,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC;QAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,IAAI,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAC,KAAK,EAAC,EAAE;YACzD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YACvE,IAAI,CAAC,MAAM;gBACT,OAAO,KAAK,CAAC;YACf,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,KAAK,CAAC,GAAG,EAAE,CAAC;iBAC3D,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;iBAC/C,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACrB,sEAAsE;YACtE,wEAAwE;YACxE,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;QAC7D,CAAC,CAAC,CAAC,CAAC;QACJ,OAAO,cAAc,KAAK,IAAI,CAAC,eAAe,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3E,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;QAC1D,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC;QAC5C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,cAAc,KAAK,IAAI,CAAC,eAAe;YAC3D,MAAM,IAAI,sBAAsB,CAAC,sDAAsD,CAAC,CAAC;QAC3F,EAAE,IAAI,CAAC,uBAAuB,CAAC;QAC/B,IAAI,CAAC,iBAAiB,GAAG,QAAQ,CAAC;QAClC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,IAAY;QAC/B,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;YAC9B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,MAAM,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IACxE,CAAC;CACF;AAQD,SAAS,uBAAuB,CAAC,OAAkC;IACjE,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;QACpB,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE;KACnI,CAAC;AACJ,CAAC;AAED,SAAS,yBAAyB,CAAC,YAAyB;IAC1D,IAAI,YAAY,YAAY,KAAK,EAAE,CAAC;QAClC,OAAO;YACL,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,YAAY,CAAC,OAAO;YAC1B,QAAQ,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,IAAI,YAAY,CAAC,OAAO;SAC3D,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC;QAC1B,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,IAAI,KAAK,YAAY,KAAK;QACxB,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAgB,EAAE,WAAyB;IAC3E,MAAM,MAAM,GAAa,CAAC,iBAAiB,CAAC,CAAC;IAC7C,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9E,MAAM,CAAC,IAAI,CAAC,MAAM,gBAAgB,CAAC,KAAK,CAAC,WAAW,CAAC,6BAA6B,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC;IAC/G,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { defineTabTool } from './tool.js';
|
|
4
|
-
import { sanitizeForFilePath } from '../utils/fileUtils.js';
|
|
4
|
+
import { safeIsoTimestampForFileName, sanitizeForFilePath } from '../utils/fileUtils.js';
|
|
5
5
|
function buildFingerprint(point) {
|
|
6
6
|
return [
|
|
7
7
|
point.role ?? '',
|
|
@@ -29,6 +29,60 @@ function isLikelySkipLink(point) {
|
|
|
29
29
|
return false;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
+
// WCAG 2.2 SC 2.5.8 Target Size (Minimum), in CSS pixels.
|
|
33
|
+
const MIN_TARGET_SIZE_PX = 24;
|
|
34
|
+
function rectCenter(rect) {
|
|
35
|
+
return { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };
|
|
36
|
+
}
|
|
37
|
+
function isUndersizedTarget(rect) {
|
|
38
|
+
return rect.width < MIN_TARGET_SIZE_PX || rect.height < MIN_TARGET_SIZE_PX;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* SC 2.5.8 spacing exception: an undersized target passes when a 24px-diameter
|
|
42
|
+
* circle centered on its bounding box intersects neither another target's box nor
|
|
43
|
+
* the equivalent circle of another undersized target.
|
|
44
|
+
*/
|
|
45
|
+
function meetsSpacingException(rect, neighbors) {
|
|
46
|
+
const center = rectCenter(rect);
|
|
47
|
+
const radius = MIN_TARGET_SIZE_PX / 2;
|
|
48
|
+
return neighbors.every(neighbor => {
|
|
49
|
+
// Every neighbor is "another target", so its box is tested first; an
|
|
50
|
+
// undersized one additionally owns a circle, and both must be cleared.
|
|
51
|
+
const nearestX = Math.min(Math.max(center.x, neighbor.x), neighbor.x + neighbor.width);
|
|
52
|
+
const nearestY = Math.min(Math.max(center.y, neighbor.y), neighbor.y + neighbor.height);
|
|
53
|
+
if (Math.hypot(center.x - nearestX, center.y - nearestY) < radius)
|
|
54
|
+
return false;
|
|
55
|
+
if (!isUndersizedTarget(neighbor))
|
|
56
|
+
return true;
|
|
57
|
+
const neighborCenter = rectCenter(neighbor);
|
|
58
|
+
return Math.hypot(center.x - neighborCenter.x, center.y - neighborCenter.y) >= MIN_TARGET_SIZE_PX;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export function meetsTargetSizeMinimum(point) {
|
|
62
|
+
const rect = point.boundingBox;
|
|
63
|
+
// Document root / non-interactive focus stops are not pointer targets at all.
|
|
64
|
+
if (!point.isPointerTarget || !rect)
|
|
65
|
+
return true;
|
|
66
|
+
if (!isUndersizedTarget(rect))
|
|
67
|
+
return true;
|
|
68
|
+
// ponytail: only the spacing and inline exceptions are evaluated. The
|
|
69
|
+
// user-agent-control, essential and equivalent-alternative exceptions need
|
|
70
|
+
// author intent that is not observable from the DOM, so undersized targets
|
|
71
|
+
// relying on them are reported and must be triaged by hand. Upgrade path:
|
|
72
|
+
// compare against a default-stylesheet baseline for user-agent control, and
|
|
73
|
+
// accept an allowlist of selectors for essential/equivalent.
|
|
74
|
+
if (point.inlineTarget)
|
|
75
|
+
return true;
|
|
76
|
+
return meetsSpacingException(rect, point.neighborTargets);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* SC 2.4.11 Focus Not Obscured (Minimum) is only violated when the focused
|
|
80
|
+
* component is *entirely* hidden, so a partially covered target passes here.
|
|
81
|
+
*/
|
|
82
|
+
export function isFocusEntirelyObscured(point) {
|
|
83
|
+
const obstruction = point.obstruction;
|
|
84
|
+
return obstruction !== null && obstruction.sampled > 0 && obstruction.blocked === obstruction.sampled;
|
|
85
|
+
}
|
|
32
86
|
function didUrlHashChange(urlBefore, urlAfter) {
|
|
33
87
|
if (!urlBefore || !urlAfter)
|
|
34
88
|
return false;
|
|
@@ -39,9 +93,6 @@ function didUrlHashChange(urlBefore, urlAfter) {
|
|
|
39
93
|
return false;
|
|
40
94
|
}
|
|
41
95
|
}
|
|
42
|
-
function safeIsoTimestampForFileName() {
|
|
43
|
-
return sanitizeForFilePath(new Date().toISOString());
|
|
44
|
-
}
|
|
45
96
|
async function maybeCaptureIssueScreenshot(options, callbacks, screenshots, issueName) {
|
|
46
97
|
if (!options.screenshotOnIssue || !callbacks.captureScreenshot)
|
|
47
98
|
return;
|
|
@@ -91,6 +142,14 @@ export async function runKeyboardFocusAudit(options, callbacks) {
|
|
|
91
142
|
await maybeCaptureIssueScreenshot(options, callbacks, screenshots, `focus-jump-${step}`);
|
|
92
143
|
}
|
|
93
144
|
}
|
|
145
|
+
if (options.checkTargetSize && !meetsTargetSizeMinimum(stop)) {
|
|
146
|
+
stop.issues.push('target-size-below-minimum');
|
|
147
|
+
await maybeCaptureIssueScreenshot(options, callbacks, screenshots, `target-size-${step}`);
|
|
148
|
+
}
|
|
149
|
+
if (options.checkFocusObscured && isFocusEntirelyObscured(stop)) {
|
|
150
|
+
stop.issues.push('focus-entirely-obscured');
|
|
151
|
+
await maybeCaptureIssueScreenshot(options, callbacks, screenshots, `focus-obscured-${step}`);
|
|
152
|
+
}
|
|
94
153
|
if (options.checkSkipLink && step <= options.skipLinkMaxTabs && isLikelySkipLink(stop) && skipLinkStep === null) {
|
|
95
154
|
skipLinkStep = step;
|
|
96
155
|
if (options.activateSkipLink && !skipLinkActivated) {
|
|
@@ -151,6 +210,8 @@ export async function runKeyboardFocusAudit(options, callbacks) {
|
|
|
151
210
|
},
|
|
152
211
|
focusVisibilityIssues: stops.filter(stop => stop.issues.includes('no-visible-focus-indicator')),
|
|
153
212
|
focusJumpIssues: stops.filter(stop => stop.issues.includes('focus-jump-or-not-visible')),
|
|
213
|
+
targetSizeIssues: stops.filter(stop => stop.issues.includes('target-size-below-minimum')),
|
|
214
|
+
focusObscuredIssues: stops.filter(stop => stop.issues.includes('focus-entirely-obscured')),
|
|
154
215
|
focusTrap: {
|
|
155
216
|
detected: focusTrapDetectedAt !== null,
|
|
156
217
|
step: focusTrapDetectedAt,
|
|
@@ -171,6 +232,8 @@ const auditKeyboardSchema = z.object({
|
|
|
171
232
|
checkFocusTrap: z.boolean().default(true).describe('Detect likely focus trap/cycle.'),
|
|
172
233
|
checkFocusVisibility: z.boolean().default(true).describe('Check focus ring visibility heuristic.'),
|
|
173
234
|
checkFocusJumps: z.boolean().default(true).describe('Detect large scroll jumps and invisible focus.'),
|
|
235
|
+
checkTargetSize: z.boolean().default(true).describe('Check target size against WCAG 2.2 SC 2.5.8 (24x24 CSS px, spacing/inline exceptions applied).'),
|
|
236
|
+
checkFocusObscured: z.boolean().default(true).describe('Check that the focused element is not entirely hidden behind other content (WCAG 2.2 SC 2.4.11).'),
|
|
174
237
|
jumpScrollThresholdPx: z.number().int().min(1).default(800).describe('Scroll delta threshold for jump detection.'),
|
|
175
238
|
screenshotOnIssue: z.boolean().default(false).describe('Capture screenshots for detected issues.'),
|
|
176
239
|
maxIssueScreenshots: z.number().int().min(1).max(20).default(3).describe('Maximum screenshots saved when screenshotOnIssue=true.'),
|
|
@@ -202,6 +265,10 @@ const auditKeyboard = defineTabTool({
|
|
|
202
265
|
boundingBox: null,
|
|
203
266
|
inViewport: false,
|
|
204
267
|
hasVisibleIndicator: false,
|
|
268
|
+
isPointerTarget: false,
|
|
269
|
+
inlineTarget: false,
|
|
270
|
+
neighborTargets: [],
|
|
271
|
+
obstruction: null,
|
|
205
272
|
scrollX,
|
|
206
273
|
scrollY,
|
|
207
274
|
};
|
|
@@ -225,6 +292,125 @@ const auditKeyboard = defineTabTool({
|
|
|
225
292
|
&& rect.right >= 0
|
|
226
293
|
&& rect.top <= window.innerHeight
|
|
227
294
|
&& rect.left <= window.innerWidth;
|
|
295
|
+
// Kept in sync with MIN_TARGET_SIZE_PX; page.evaluate cannot close over it.
|
|
296
|
+
const minTargetSize = 24;
|
|
297
|
+
// ponytail: target size comes from the layout box, so a target whose visible
|
|
298
|
+
// area is cut down by an overflow or clip-path ancestor is under-reported.
|
|
299
|
+
// Intersecting with clipping ancestors was measured against ordinary markup and
|
|
300
|
+
// cost four false positives (carousel slides parked off-track, rows of a plain
|
|
301
|
+
// overflow: auto list) per true positive, and clip-path shapes are not derivable
|
|
302
|
+
// from a rect at all. Upgrade path: clip only against ancestors that cannot be
|
|
303
|
+
// scrolled or animated to reveal the rest of the target.
|
|
304
|
+
const targetSelector = 'a[href], button, input:not([type="hidden"]), select, textarea, summary, [contenteditable]:not([contenteditable="false"]), [tabindex]:not([tabindex^="-"]), [role="button"], [role="link"], [role="checkbox"], [role="radio"], [role="switch"], [role="tab"], [role="menuitem"], [role="option"]';
|
|
305
|
+
// Shared by the focused element and its spacing neighbors so a disabled or
|
|
306
|
+
// unrendered control is never counted as a pointer target on either side.
|
|
307
|
+
const isPointerTargetElement = (element, box) => box.width > 0
|
|
308
|
+
&& box.height > 0
|
|
309
|
+
&& element.matches(targetSelector)
|
|
310
|
+
&& !element.matches(':disabled');
|
|
311
|
+
const isPointerTarget = isPointerTargetElement(current, rect);
|
|
312
|
+
// "Target is in a sentence": approximated as an inline-level target that sits
|
|
313
|
+
// directly next to running text.
|
|
314
|
+
// ponytail: ceiling is that targets merely constrained by the line-height of
|
|
315
|
+
// nearby non-target text are missed. Upgrade path: compare the target height
|
|
316
|
+
// against the parent's computed line-height.
|
|
317
|
+
// The target may sit inside inline formatting (<strong>, <span>, ...), so walk
|
|
318
|
+
// up through inline-level wrappers to the containing block before concluding
|
|
319
|
+
// there is no running text beside it.
|
|
320
|
+
let hasSentenceText = false;
|
|
321
|
+
for (let scope = current; scope.parentElement && !hasSentenceText; scope = scope.parentElement) {
|
|
322
|
+
hasSentenceText = Array.from(scope.parentElement.childNodes).some(node => (node.nodeType === Node.TEXT_NODE && (node.textContent ?? '').trim().length > 0));
|
|
323
|
+
if (!window.getComputedStyle(scope.parentElement).display.startsWith('inline'))
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
// Any inline-level display (inline, inline-block, inline-flex, ...) can sit in a
|
|
327
|
+
// sentence; SC 2.5.8's exception is about the sentence, not the display keyword.
|
|
328
|
+
const inlineTarget = isPointerTarget && style.display.startsWith('inline') && hasSentenceText;
|
|
329
|
+
const neighborTargets = [];
|
|
330
|
+
if (isPointerTarget && (rect.width < minTargetSize || rect.height < minTargetSize)) {
|
|
331
|
+
for (const candidate of document.querySelectorAll(targetSelector)) {
|
|
332
|
+
if (candidate === current)
|
|
333
|
+
continue;
|
|
334
|
+
const other = candidate.getBoundingClientRect();
|
|
335
|
+
if (!isPointerTargetElement(candidate, other))
|
|
336
|
+
continue;
|
|
337
|
+
// Only targets close enough for either 24px circle to reach can matter;
|
|
338
|
+
// the margin overshoots deliberately so the spacing test never misses one.
|
|
339
|
+
const outOfRange = other.right < rect.left - 2 * minTargetSize
|
|
340
|
+
|| other.left > rect.right + 2 * minTargetSize
|
|
341
|
+
|| other.bottom < rect.top - 2 * minTargetSize
|
|
342
|
+
|| other.top > rect.bottom + 2 * minTargetSize;
|
|
343
|
+
if (outOfRange)
|
|
344
|
+
continue;
|
|
345
|
+
neighborTargets.push({ x: other.x, y: other.y, width: other.width, height: other.height });
|
|
346
|
+
// ponytail: payload cap. A cluster denser than 32 neighbors within 48px
|
|
347
|
+
// would under-report rather than over-report; raise the cap if that appears.
|
|
348
|
+
if (neighborTargets.length >= 32)
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
let obstruction = null;
|
|
353
|
+
const clipLeft = Math.max(rect.left, 0);
|
|
354
|
+
const clipTop = Math.max(rect.top, 0);
|
|
355
|
+
const clipRight = Math.min(rect.right, window.innerWidth - 1);
|
|
356
|
+
const clipBottom = Math.min(rect.bottom, window.innerHeight - 1);
|
|
357
|
+
// SC 2.4.11 applies to anything that receives focus, so this is deliberately not
|
|
358
|
+
// gated on isPointerTarget: contenteditable, iframes and tabindex-only widgets
|
|
359
|
+
// are sampled too.
|
|
360
|
+
if (rect.width > 0 && rect.height > 0 && clipRight >= clipLeft && clipBottom >= clipTop) {
|
|
361
|
+
const inset = (low, high, value) => Math.min(Math.max(value, low), high);
|
|
362
|
+
const samples = [
|
|
363
|
+
[inset(clipLeft, clipRight, clipLeft + 1), inset(clipTop, clipBottom, clipTop + 1)],
|
|
364
|
+
[inset(clipLeft, clipRight, clipRight - 1), inset(clipTop, clipBottom, clipTop + 1)],
|
|
365
|
+
[inset(clipLeft, clipRight, clipLeft + 1), inset(clipTop, clipBottom, clipBottom - 1)],
|
|
366
|
+
[inset(clipLeft, clipRight, clipRight - 1), inset(clipTop, clipBottom, clipBottom - 1)],
|
|
367
|
+
[(clipLeft + clipRight) / 2, (clipTop + clipBottom) / 2],
|
|
368
|
+
];
|
|
369
|
+
const labels = current instanceof HTMLInputElement || current instanceof HTMLTextAreaElement || current instanceof HTMLSelectElement
|
|
370
|
+
? Array.from(current.labels ?? [])
|
|
371
|
+
: [];
|
|
372
|
+
// SC 2.4.11 is about visual coverage, not hit-test order, so a hit only counts
|
|
373
|
+
// when it (or a wrapper of it that is not also around the target) actually
|
|
374
|
+
// paints: visible, non-zero opacity and a non-transparent background.
|
|
375
|
+
// ponytail: the remaining ceiling is that a covering layer with
|
|
376
|
+
// `pointer-events: none` is never returned by hit testing, so it is missed
|
|
377
|
+
// (under-report, never a false alarm). Upgrade path: intersect the focused box
|
|
378
|
+
// against the boxes of positioned/stacking-context layers painted above it.
|
|
379
|
+
const paintsOver = (element) => {
|
|
380
|
+
let paints = false;
|
|
381
|
+
// Painted evidence never short-circuits the walk: an ancestor that renders
|
|
382
|
+
// nothing (opacity: 0, visibility: hidden) hides its painted children too.
|
|
383
|
+
for (let node = element; node && !node.contains(current); node = node.parentElement) {
|
|
384
|
+
const nodeStyle = window.getComputedStyle(node);
|
|
385
|
+
if (nodeStyle.visibility === 'hidden' || Number.parseFloat(nodeStyle.opacity || '1') === 0)
|
|
386
|
+
return false;
|
|
387
|
+
if (paints)
|
|
388
|
+
continue;
|
|
389
|
+
const alpha = /^rgba\(.*,\s*([\d.]+)\)$/.exec(nodeStyle.backgroundColor);
|
|
390
|
+
paints = nodeStyle.backgroundImage !== 'none'
|
|
391
|
+
|| (alpha ? Number.parseFloat(alpha[1]) > 0 : nodeStyle.backgroundColor !== 'transparent');
|
|
392
|
+
}
|
|
393
|
+
return paints;
|
|
394
|
+
};
|
|
395
|
+
let blocked = 0;
|
|
396
|
+
let blockedBy = null;
|
|
397
|
+
for (const [x, y] of samples) {
|
|
398
|
+
const hit = document.elementFromPoint(x, y);
|
|
399
|
+
// Descendants paint the target itself; ancestors and associated labels
|
|
400
|
+
// wrap it (the common visually-hidden custom control pattern).
|
|
401
|
+
const covers = hit !== null
|
|
402
|
+
&& !current.contains(hit)
|
|
403
|
+
&& !hit.contains(current)
|
|
404
|
+
&& !labels.some(label => label.contains(hit))
|
|
405
|
+
&& paintsOver(hit);
|
|
406
|
+
if (!covers)
|
|
407
|
+
continue;
|
|
408
|
+
blocked++;
|
|
409
|
+
const className = typeof hit.className === 'string' ? hit.className.trim().split(/\s+/)[0] : '';
|
|
410
|
+
blockedBy = blockedBy ?? `${hit.tagName.toLowerCase()}${hit.id ? `#${hit.id}` : ''}${className ? `.${className}` : ''}`;
|
|
411
|
+
}
|
|
412
|
+
obstruction = { sampled: samples.length, blocked, blockedBy };
|
|
413
|
+
}
|
|
228
414
|
return {
|
|
229
415
|
role,
|
|
230
416
|
name: name ? name.slice(0, 200) : null,
|
|
@@ -240,6 +426,10 @@ const auditKeyboard = defineTabTool({
|
|
|
240
426
|
} : null,
|
|
241
427
|
inViewport,
|
|
242
428
|
hasVisibleIndicator: hasOutline || hasBoxShadow,
|
|
429
|
+
isPointerTarget,
|
|
430
|
+
inlineTarget,
|
|
431
|
+
neighborTargets,
|
|
432
|
+
obstruction,
|
|
243
433
|
scrollX,
|
|
244
434
|
scrollY,
|
|
245
435
|
};
|
|
@@ -323,6 +513,8 @@ const auditKeyboard = defineTabTool({
|
|
|
323
513
|
skipLinkActivated: result.skipLink.activated,
|
|
324
514
|
focusVisibilityIssueCount: result.focusVisibilityIssues.length,
|
|
325
515
|
focusJumpIssueCount: result.focusJumpIssues.length,
|
|
516
|
+
targetSizeIssueCount: result.targetSizeIssues.length,
|
|
517
|
+
focusObscuredIssueCount: result.focusObscuredIssues.length,
|
|
326
518
|
focusTrapDetected: result.focusTrap.detected,
|
|
327
519
|
focusTrapStep: result.focusTrap.step,
|
|
328
520
|
screenshotCount: result.screenshots.length,
|
|
@@ -332,6 +524,8 @@ const auditKeyboard = defineTabTool({
|
|
|
332
524
|
});
|
|
333
525
|
const focusVisibilityPreview = result.focusVisibilityIssues.slice(0, 10).map(stop => (`- Step ${stop.step} (${stop.key}): ${stop.role ?? 'unknown-role'} ${stop.name ?? ''}`.trim()));
|
|
334
526
|
const focusJumpPreview = result.focusJumpIssues.slice(0, 10).map(stop => (`- Step ${stop.step}: deltaY=${stop.scrollDeltaY}, inViewport=${stop.inViewport}`));
|
|
527
|
+
const targetSizePreview = result.targetSizeIssues.slice(0, 10).map(stop => (`- Step ${stop.step}: ${stop.role ?? 'unknown-role'} ${stop.name ?? ''} is ${Math.round(stop.boundingBox?.width ?? 0)}x${Math.round(stop.boundingBox?.height ?? 0)} CSS px`.replace(/\s+/g, ' ')));
|
|
528
|
+
const focusObscuredPreview = result.focusObscuredIssues.slice(0, 10).map(stop => (`- Step ${stop.step}: ${stop.role ?? 'unknown-role'} ${stop.name ?? ''} hidden behind ${stop.obstruction?.blockedBy ?? 'other content'}`.replace(/\s+/g, ' ')));
|
|
335
529
|
const skipLinkResult = result.skipLink.found
|
|
336
530
|
? `found at step ${result.skipLink.step}${result.skipLink.activated ? ', activated' : ''}`
|
|
337
531
|
: 'not found';
|
|
@@ -345,6 +539,12 @@ const auditKeyboard = defineTabTool({
|
|
|
345
539
|
`Focus trap detected: ${result.focusTrap.detected ? `yes (step ${result.focusTrap.step})` : 'no'}`,
|
|
346
540
|
`Focus jumps: ${result.focusJumpIssues.length}`,
|
|
347
541
|
...(focusJumpPreview.length ? focusJumpPreview : ['- None']),
|
|
542
|
+
'',
|
|
543
|
+
`Target size below 24x24 CSS px (WCAG 2.2 SC 2.5.8, spacing and inline exceptions applied): ${result.targetSizeIssues.length}`,
|
|
544
|
+
...(targetSizePreview.length ? targetSizePreview : ['- None']),
|
|
545
|
+
'',
|
|
546
|
+
`Focus entirely obscured (WCAG 2.2 SC 2.4.11): ${result.focusObscuredIssues.length}`,
|
|
547
|
+
...(focusObscuredPreview.length ? focusObscuredPreview : ['- None']),
|
|
348
548
|
...(result.screenshots.length ? ['', 'Issue screenshots:', ...result.screenshots.map(path => `- ${path}`)] : []),
|
|
349
549
|
'',
|
|
350
550
|
`JSON report: ${reportPath}`,
|