@accesslint/core 0.1.3 → 0.2.2
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 +8 -11
- package/dist/index.cjs +5 -5
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.iife.js +5 -5
- package/dist/index.js +1170 -1034
- package/dist/rules/aria/aria-attr-audit.d.ts.map +1 -1
- package/dist/rules/aria/aria-hidden-rules.d.ts.map +1 -1
- package/dist/rules/color/color-contrast.d.ts +3 -0
- package/dist/rules/color/color-contrast.d.ts.map +1 -0
- package/dist/rules/images/server-side-image-map.d.ts +1 -2
- package/dist/rules/images/server-side-image-map.d.ts.map +1 -1
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/keyboard/interactive-rules.d.ts.map +1 -1
- package/dist/rules/keyboard/tabindex.d.ts +1 -2
- package/dist/rules/keyboard/tabindex.d.ts.map +1 -1
- package/dist/rules/structure/deprecated-elements.d.ts +2 -3
- package/dist/rules/structure/deprecated-elements.d.ts.map +1 -1
- package/dist/rules/structure/list-rules.d.ts.map +1 -1
- package/dist/rules/types.d.ts +0 -14
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/utils/aria.d.ts +1 -0
- package/dist/rules/utils/aria.d.ts.map +1 -1
- package/dist/rules/utils/color.d.ts +8 -0
- package/dist/rules/utils/color.d.ts.map +1 -0
- package/dist/rules/utils/selector.d.ts +1 -0
- package/dist/rules/utils/selector.d.ts.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
let
|
|
2
|
-
function
|
|
3
|
-
|
|
1
|
+
let M = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
function Q() {
|
|
3
|
+
M = /* @__PURE__ */ new WeakMap();
|
|
4
4
|
}
|
|
5
|
-
function
|
|
5
|
+
function J(t) {
|
|
6
6
|
var i;
|
|
7
7
|
const a = t.tagName.toLowerCase(), e = (i = t.getAttribute("type")) == null ? void 0 : i.toLowerCase();
|
|
8
8
|
switch (a) {
|
|
@@ -117,28 +117,38 @@ function U(t) {
|
|
|
117
117
|
return null;
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
-
function
|
|
121
|
-
var
|
|
122
|
-
const a =
|
|
120
|
+
function E(t) {
|
|
121
|
+
var n;
|
|
122
|
+
const a = M.get(t);
|
|
123
|
+
if (a !== void 0) return a;
|
|
124
|
+
const i = ((n = t.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase()) || null || J(t);
|
|
125
|
+
return M.set(t, i), i;
|
|
126
|
+
}
|
|
127
|
+
let $ = /* @__PURE__ */ new WeakMap();
|
|
128
|
+
function Z() {
|
|
129
|
+
$ = /* @__PURE__ */ new WeakMap();
|
|
130
|
+
}
|
|
131
|
+
function b(t) {
|
|
132
|
+
const a = $.get(t);
|
|
123
133
|
if (a !== void 0) return a;
|
|
124
|
-
const
|
|
125
|
-
return
|
|
134
|
+
const e = de(t);
|
|
135
|
+
return $.set(t, e), e;
|
|
126
136
|
}
|
|
127
|
-
function
|
|
128
|
-
var
|
|
137
|
+
function de(t) {
|
|
138
|
+
var r, o, s, u, h;
|
|
129
139
|
const a = t.getAttribute("aria-labelledby");
|
|
130
140
|
if (a) {
|
|
131
141
|
const d = a.split(/\s+/).map((p) => {
|
|
132
|
-
const
|
|
133
|
-
return
|
|
142
|
+
const g = t.ownerDocument.getElementById(p);
|
|
143
|
+
return g ? w(g).trim() : "";
|
|
134
144
|
}).filter(Boolean);
|
|
135
145
|
if (d.length) return d.join(" ");
|
|
136
146
|
}
|
|
137
|
-
const e = (
|
|
147
|
+
const e = (r = t.getAttribute("aria-label")) == null ? void 0 : r.trim();
|
|
138
148
|
if (e) return e;
|
|
139
149
|
if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) {
|
|
140
150
|
if (t.id) {
|
|
141
|
-
const
|
|
151
|
+
const g = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`), f = g ? w(g).trim() : "";
|
|
142
152
|
if (f) return f;
|
|
143
153
|
}
|
|
144
154
|
const d = t.closest("label"), p = d ? w(d).trim() : "";
|
|
@@ -150,15 +160,15 @@ function g(t) {
|
|
|
150
160
|
const d = (s = t.getAttribute("placeholder")) == null ? void 0 : s.trim();
|
|
151
161
|
if (d) return d;
|
|
152
162
|
}
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
163
|
+
const n = t.tagName.toLowerCase();
|
|
164
|
+
if (n === "fieldset") {
|
|
155
165
|
const d = t.querySelector(":scope > legend");
|
|
156
166
|
if (d) {
|
|
157
167
|
const p = w(d).trim();
|
|
158
168
|
if (p) return p;
|
|
159
169
|
}
|
|
160
170
|
}
|
|
161
|
-
if (
|
|
171
|
+
if (n === "table") {
|
|
162
172
|
const d = t.querySelector(":scope > caption");
|
|
163
173
|
if (d) {
|
|
164
174
|
const p = w(d).trim();
|
|
@@ -169,9 +179,9 @@ function g(t) {
|
|
|
169
179
|
const d = w(t).trim();
|
|
170
180
|
if (d) return d;
|
|
171
181
|
}
|
|
172
|
-
return t instanceof HTMLImageElement || t instanceof HTMLAreaElement ? ((
|
|
182
|
+
return t instanceof HTMLImageElement || t instanceof HTMLAreaElement ? ((u = t.alt) == null ? void 0 : u.trim()) ?? "" : t instanceof HTMLInputElement && t.type === "image" ? ((h = t.alt) == null ? void 0 : h.trim()) ?? "" : "";
|
|
173
183
|
}
|
|
174
|
-
const
|
|
184
|
+
const ue = /* @__PURE__ */ new Set([
|
|
175
185
|
"alert",
|
|
176
186
|
"alertdialog",
|
|
177
187
|
"application",
|
|
@@ -255,52 +265,56 @@ const J = /* @__PURE__ */ new Set([
|
|
|
255
265
|
"treegrid",
|
|
256
266
|
"treeitem"
|
|
257
267
|
]);
|
|
258
|
-
function
|
|
268
|
+
function me(t) {
|
|
259
269
|
const a = t.trim().toLowerCase().replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "");
|
|
260
|
-
return
|
|
270
|
+
return ue.has(a);
|
|
261
271
|
}
|
|
262
|
-
let
|
|
263
|
-
function
|
|
264
|
-
|
|
272
|
+
let H = /* @__PURE__ */ new WeakMap();
|
|
273
|
+
function ee() {
|
|
274
|
+
H = /* @__PURE__ */ new WeakMap();
|
|
265
275
|
}
|
|
266
|
-
function
|
|
267
|
-
const a =
|
|
276
|
+
function m(t) {
|
|
277
|
+
const a = H.get(t);
|
|
268
278
|
if (a !== void 0) return a;
|
|
269
279
|
let e;
|
|
270
|
-
return t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && (t.hidden || t.style.display === "none") ? e = !0 : t.parentElement ? e =
|
|
280
|
+
return t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && (t.hidden || t.style.display === "none") ? e = !0 : t.parentElement ? e = m(t.parentElement) : e = !1, H.set(t, e), e;
|
|
271
281
|
}
|
|
272
|
-
function
|
|
282
|
+
function pe(t) {
|
|
273
283
|
return !!(t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && (t.hidden || t.style.display === "none"));
|
|
274
284
|
}
|
|
275
285
|
function w(t) {
|
|
276
|
-
var e, i,
|
|
286
|
+
var e, i, n, r;
|
|
277
287
|
let a = "";
|
|
278
288
|
for (const o of t.childNodes)
|
|
279
289
|
if (o.nodeType === 3)
|
|
280
290
|
a += o.textContent ?? "";
|
|
281
291
|
else if (o.nodeType === 1) {
|
|
282
292
|
const s = o;
|
|
283
|
-
if (!
|
|
284
|
-
const
|
|
285
|
-
if (
|
|
293
|
+
if (!pe(s)) {
|
|
294
|
+
const u = (e = s.tagName) == null ? void 0 : e.toLowerCase();
|
|
295
|
+
if (u === "img" || u === "area")
|
|
286
296
|
a += ((i = s.getAttribute("aria-label")) == null ? void 0 : i.trim()) ?? s.getAttribute("alt") ?? "";
|
|
287
|
-
else if (
|
|
288
|
-
const h = (
|
|
297
|
+
else if (u === "svg") {
|
|
298
|
+
const h = (n = s.getAttribute("aria-label")) == null ? void 0 : n.trim();
|
|
289
299
|
if (h)
|
|
290
300
|
a += h;
|
|
291
301
|
else {
|
|
292
302
|
const d = s.querySelector("title");
|
|
293
303
|
d && (a += d.textContent ?? "");
|
|
294
304
|
}
|
|
295
|
-
} else (
|
|
305
|
+
} else (r = s.getAttribute("aria-label")) != null && r.trim() ? a += s.getAttribute("aria-label").trim() : a += w(s);
|
|
296
306
|
}
|
|
297
307
|
}
|
|
298
308
|
return a;
|
|
299
309
|
}
|
|
300
|
-
|
|
310
|
+
let D = /* @__PURE__ */ new WeakMap();
|
|
311
|
+
function te() {
|
|
312
|
+
D = /* @__PURE__ */ new WeakMap();
|
|
313
|
+
}
|
|
314
|
+
function he(t) {
|
|
301
315
|
return t.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
302
316
|
}
|
|
303
|
-
const
|
|
317
|
+
const ge = [
|
|
304
318
|
"data-testid",
|
|
305
319
|
"data-test-id",
|
|
306
320
|
"data-cy",
|
|
@@ -310,69 +324,105 @@ const ae = [
|
|
|
310
324
|
"for",
|
|
311
325
|
"aria-label"
|
|
312
326
|
];
|
|
313
|
-
function
|
|
327
|
+
function be(t) {
|
|
314
328
|
const a = t.tagName.toLowerCase();
|
|
315
|
-
for (const i of
|
|
316
|
-
const
|
|
317
|
-
if (
|
|
318
|
-
return `${a}[${i}="${
|
|
329
|
+
for (const i of ge) {
|
|
330
|
+
const n = t.getAttribute(i);
|
|
331
|
+
if (n != null && n.length > 0 && n.length < 100)
|
|
332
|
+
return `${a}[${i}="${he(n)}"]`;
|
|
319
333
|
}
|
|
320
334
|
const e = t.parentElement;
|
|
321
335
|
if (e) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (i
|
|
326
|
-
return `${a}:nth-of-type(${
|
|
336
|
+
let i = 0, n = 0;
|
|
337
|
+
for (let r = 0; r < e.children.length; r++)
|
|
338
|
+
e.children[r].tagName === t.tagName && (i++, e.children[r] === t && (n = i));
|
|
339
|
+
if (i > 1)
|
|
340
|
+
return `${a}:nth-of-type(${n})`;
|
|
327
341
|
}
|
|
328
342
|
return a;
|
|
329
343
|
}
|
|
330
|
-
function
|
|
344
|
+
function R(t) {
|
|
331
345
|
if (t.id) return `#${CSS.escape(t.id)}`;
|
|
332
346
|
const a = t.getRootNode(), e = a instanceof ShadowRoot ? null : a.documentElement, i = [];
|
|
333
|
-
let
|
|
334
|
-
for (;
|
|
335
|
-
if (
|
|
336
|
-
i.unshift(`#${CSS.escape(
|
|
347
|
+
let n = t;
|
|
348
|
+
for (; n && n !== e; ) {
|
|
349
|
+
if (n !== t && n.id) {
|
|
350
|
+
i.unshift(`#${CSS.escape(n.id)}`);
|
|
337
351
|
break;
|
|
338
352
|
}
|
|
339
|
-
if (i.unshift(
|
|
340
|
-
const
|
|
353
|
+
if (i.unshift(be(n)), i.length >= 2) {
|
|
354
|
+
const r = i.join(" > ");
|
|
341
355
|
try {
|
|
342
|
-
const o = a.querySelectorAll(
|
|
343
|
-
if (o.length === 1 && o[0] === t) return
|
|
356
|
+
const o = a.querySelectorAll(r);
|
|
357
|
+
if (o.length === 1 && o[0] === t) return r;
|
|
344
358
|
} catch {
|
|
345
359
|
}
|
|
346
360
|
}
|
|
347
|
-
|
|
361
|
+
n = n.parentElement;
|
|
348
362
|
}
|
|
349
363
|
return i.join(" > ");
|
|
350
364
|
}
|
|
351
365
|
function c(t) {
|
|
352
|
-
var
|
|
353
|
-
const a =
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
366
|
+
var r;
|
|
367
|
+
const a = D.get(t);
|
|
368
|
+
if (a !== void 0) return a;
|
|
369
|
+
const e = [];
|
|
370
|
+
let i = t;
|
|
371
|
+
for (; i; ) {
|
|
372
|
+
const o = i.getRootNode();
|
|
373
|
+
if (o instanceof ShadowRoot)
|
|
374
|
+
e.unshift({ selector: R(i), delimiter: " >>> " }), i = o.host;
|
|
359
375
|
else {
|
|
360
|
-
const
|
|
361
|
-
if (
|
|
362
|
-
|
|
376
|
+
const s = (r = o.defaultView) == null ? void 0 : r.frameElement;
|
|
377
|
+
if (s)
|
|
378
|
+
e.unshift({ selector: R(i), delimiter: " >>>iframe> " }), i = s;
|
|
363
379
|
else {
|
|
364
|
-
|
|
380
|
+
e.unshift({ selector: R(i), delimiter: "" });
|
|
365
381
|
break;
|
|
366
382
|
}
|
|
367
383
|
}
|
|
368
384
|
}
|
|
369
|
-
|
|
385
|
+
const n = e.map((o, s) => (s === 0 ? "" : o.delimiter) + o.selector).join("");
|
|
386
|
+
return D.set(t, n), n;
|
|
387
|
+
}
|
|
388
|
+
function Wa(t) {
|
|
389
|
+
const a = [], e = [];
|
|
390
|
+
let i = t;
|
|
391
|
+
for (; i; ) {
|
|
392
|
+
const r = i.indexOf(" >>>iframe> "), o = i.indexOf(" >>> ");
|
|
393
|
+
if (r !== -1 && (o === -1 || r <= o))
|
|
394
|
+
a.push(i.slice(0, r).trim()), e.push("iframe"), i = i.slice(r + 12);
|
|
395
|
+
else if (o !== -1)
|
|
396
|
+
a.push(i.slice(0, o).trim()), e.push("shadow"), i = i.slice(o + 5);
|
|
397
|
+
else {
|
|
398
|
+
a.push(i.trim());
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
let n = document;
|
|
403
|
+
for (let r = 0; r < a.length; r++) {
|
|
404
|
+
const o = n.querySelector(a[r]);
|
|
405
|
+
if (!o) return null;
|
|
406
|
+
if (r < a.length - 1)
|
|
407
|
+
if (e[r] === "iframe") {
|
|
408
|
+
const s = o.contentDocument;
|
|
409
|
+
if (!s) return null;
|
|
410
|
+
n = s;
|
|
411
|
+
} else {
|
|
412
|
+
const s = o.shadowRoot;
|
|
413
|
+
if (!s) return null;
|
|
414
|
+
n = s;
|
|
415
|
+
}
|
|
416
|
+
else
|
|
417
|
+
return o;
|
|
418
|
+
}
|
|
419
|
+
return null;
|
|
370
420
|
}
|
|
371
421
|
function l(t) {
|
|
372
422
|
const a = t.outerHTML;
|
|
373
423
|
return a.length > 200 ? a.slice(0, 200) + "..." : a;
|
|
374
424
|
}
|
|
375
|
-
const
|
|
425
|
+
const fe = /* @__PURE__ */ new Set([
|
|
376
426
|
"aria-activedescendant",
|
|
377
427
|
"aria-atomic",
|
|
378
428
|
"aria-autocomplete",
|
|
@@ -426,7 +476,7 @@ const re = /* @__PURE__ */ new Set([
|
|
|
426
476
|
"aria-valuemin",
|
|
427
477
|
"aria-valuenow",
|
|
428
478
|
"aria-valuetext"
|
|
429
|
-
]),
|
|
479
|
+
]), ve = /* @__PURE__ */ new Set([
|
|
430
480
|
"aria-atomic",
|
|
431
481
|
"aria-busy",
|
|
432
482
|
"aria-disabled",
|
|
@@ -437,7 +487,7 @@ const re = /* @__PURE__ */ new Set([
|
|
|
437
487
|
"aria-multiselectable",
|
|
438
488
|
"aria-readonly",
|
|
439
489
|
"aria-required"
|
|
440
|
-
]),
|
|
490
|
+
]), ye = /* @__PURE__ */ new Set(["aria-checked", "aria-pressed"]), we = /* @__PURE__ */ new Set([
|
|
441
491
|
"aria-colcount",
|
|
442
492
|
"aria-colindex",
|
|
443
493
|
"aria-colspan",
|
|
@@ -447,11 +497,11 @@ const re = /* @__PURE__ */ new Set([
|
|
|
447
497
|
"aria-rowindex",
|
|
448
498
|
"aria-rowspan",
|
|
449
499
|
"aria-setsize"
|
|
450
|
-
]),
|
|
500
|
+
]), Ae = /* @__PURE__ */ new Set([
|
|
451
501
|
"aria-valuemax",
|
|
452
502
|
"aria-valuemin",
|
|
453
503
|
"aria-valuenow"
|
|
454
|
-
]),
|
|
504
|
+
]), P = {
|
|
455
505
|
"aria-autocomplete": /* @__PURE__ */ new Set(["inline", "list", "both", "none"]),
|
|
456
506
|
"aria-current": /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"]),
|
|
457
507
|
"aria-dropeffect": /* @__PURE__ */ new Set(["copy", "execute", "link", "move", "none", "popup"]),
|
|
@@ -461,7 +511,7 @@ const re = /* @__PURE__ */ new Set([
|
|
|
461
511
|
"aria-orientation": /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]),
|
|
462
512
|
"aria-relevant": /* @__PURE__ */ new Set(["additions", "all", "removals", "text"]),
|
|
463
513
|
"aria-sort": /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"])
|
|
464
|
-
},
|
|
514
|
+
}, V = /* @__PURE__ */ new Set([
|
|
465
515
|
"caption",
|
|
466
516
|
"code",
|
|
467
517
|
"deletion",
|
|
@@ -478,7 +528,7 @@ const re = /* @__PURE__ */ new Set([
|
|
|
478
528
|
"suggestion",
|
|
479
529
|
"term",
|
|
480
530
|
"time"
|
|
481
|
-
]),
|
|
531
|
+
]), Se = {
|
|
482
532
|
abbr: !0,
|
|
483
533
|
bdi: !0,
|
|
484
534
|
bdo: !0,
|
|
@@ -506,7 +556,7 @@ const re = /* @__PURE__ */ new Set([
|
|
|
506
556
|
u: !0,
|
|
507
557
|
var: !0,
|
|
508
558
|
wbr: !0
|
|
509
|
-
},
|
|
559
|
+
}, xe = {
|
|
510
560
|
alert: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
|
|
511
561
|
article: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
|
|
512
562
|
banner: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
|
|
@@ -539,77 +589,92 @@ const re = /* @__PURE__ */ new Set([
|
|
|
539
589
|
time: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
|
|
540
590
|
tooltip: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"])
|
|
541
591
|
};
|
|
542
|
-
let
|
|
543
|
-
function
|
|
544
|
-
|
|
592
|
+
let I = null, q = null;
|
|
593
|
+
function ae() {
|
|
594
|
+
I = null, q = null;
|
|
545
595
|
}
|
|
546
|
-
function
|
|
547
|
-
var
|
|
548
|
-
if (
|
|
596
|
+
function _(t) {
|
|
597
|
+
var n;
|
|
598
|
+
if (q && (I == null ? void 0 : I.deref()) === t) return q;
|
|
549
599
|
const a = [], e = [], i = [];
|
|
550
|
-
for (const
|
|
600
|
+
for (const r of t.querySelectorAll("*")) {
|
|
551
601
|
let o = !1;
|
|
552
|
-
for (const d of
|
|
602
|
+
for (const d of r.attributes)
|
|
553
603
|
if (d.name.startsWith("aria-")) {
|
|
554
604
|
o = !0;
|
|
555
605
|
break;
|
|
556
606
|
}
|
|
557
607
|
if (!o) continue;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
608
|
+
let s, u;
|
|
609
|
+
const h = () => (s === void 0 && (s = c(r), u = l(r)), { selector: s, html: u });
|
|
610
|
+
for (const d of r.attributes)
|
|
611
|
+
if (d.name.startsWith("aria-") && !fe.has(d.name)) {
|
|
612
|
+
const p = h();
|
|
561
613
|
a.push({
|
|
562
614
|
ruleId: "aria-valid-attr",
|
|
563
|
-
selector:
|
|
564
|
-
html:
|
|
615
|
+
selector: p.selector,
|
|
616
|
+
html: p.html,
|
|
565
617
|
impact: "critical",
|
|
566
618
|
message: `Invalid ARIA attribute "${d.name}".`
|
|
567
619
|
});
|
|
568
620
|
break;
|
|
569
621
|
}
|
|
570
|
-
for (const d of
|
|
622
|
+
for (const d of r.attributes) {
|
|
571
623
|
if (!d.name.startsWith("aria-")) continue;
|
|
572
624
|
const p = d.value.trim();
|
|
573
|
-
if (
|
|
574
|
-
p !== "true" && p !== "false"
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
625
|
+
if (ve.has(d.name)) {
|
|
626
|
+
if (p !== "true" && p !== "false") {
|
|
627
|
+
const g = h();
|
|
628
|
+
e.push({
|
|
629
|
+
ruleId: "aria-valid-attr-value",
|
|
630
|
+
selector: g.selector,
|
|
631
|
+
html: g.html,
|
|
632
|
+
impact: "critical",
|
|
633
|
+
message: `${d.name} must be "true" or "false", got "${p}".`
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
} else if (ye.has(d.name)) {
|
|
637
|
+
if (p !== "true" && p !== "false" && p !== "mixed") {
|
|
638
|
+
const g = h();
|
|
639
|
+
e.push({
|
|
640
|
+
ruleId: "aria-valid-attr-value",
|
|
641
|
+
selector: g.selector,
|
|
642
|
+
html: g.html,
|
|
643
|
+
impact: "critical",
|
|
644
|
+
message: `${d.name} must be "true", "false", or "mixed", got "${p}".`
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
} else if (we.has(d.name)) {
|
|
648
|
+
if (p === "" || !/^-?\d+$/.test(p)) {
|
|
649
|
+
const g = h();
|
|
650
|
+
e.push({
|
|
651
|
+
ruleId: "aria-valid-attr-value",
|
|
652
|
+
selector: g.selector,
|
|
653
|
+
html: g.html,
|
|
654
|
+
impact: "critical",
|
|
655
|
+
message: `${d.name} must be an integer, got "${p}".`
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
} else if (Ae.has(d.name)) {
|
|
659
|
+
if (p === "" || isNaN(Number(p))) {
|
|
660
|
+
const g = h();
|
|
661
|
+
e.push({
|
|
662
|
+
ruleId: "aria-valid-attr-value",
|
|
663
|
+
selector: g.selector,
|
|
664
|
+
html: g.html,
|
|
665
|
+
impact: "critical",
|
|
666
|
+
message: `${d.name} must be a number, got "${p}".`
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
} else if (P[d.name]) {
|
|
670
|
+
const g = p.split(/\s+/);
|
|
671
|
+
for (const f of g)
|
|
672
|
+
if (!P[d.name].has(f)) {
|
|
673
|
+
const v = h();
|
|
609
674
|
e.push({
|
|
610
675
|
ruleId: "aria-valid-attr-value",
|
|
611
|
-
selector:
|
|
612
|
-
html:
|
|
676
|
+
selector: v.selector,
|
|
677
|
+
html: v.html,
|
|
613
678
|
impact: "critical",
|
|
614
679
|
message: `Invalid value "${p}" for ${d.name}.`
|
|
615
680
|
});
|
|
@@ -617,38 +682,45 @@ function $(t) {
|
|
|
617
682
|
}
|
|
618
683
|
}
|
|
619
684
|
}
|
|
620
|
-
if (!
|
|
621
|
-
const d = (
|
|
622
|
-
if (!d &&
|
|
623
|
-
const
|
|
624
|
-
(
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
html: m,
|
|
628
|
-
impact: "serious",
|
|
629
|
-
message: `aria-label and aria-labelledby are prohibited on <${p}> elements.`
|
|
630
|
-
});
|
|
631
|
-
} else if (d) {
|
|
632
|
-
if (B.has(d)) {
|
|
633
|
-
const f = n.hasAttribute("aria-label"), v = n.hasAttribute("aria-labelledby");
|
|
634
|
-
(f || v) && i.push({
|
|
685
|
+
if (!m(r)) {
|
|
686
|
+
const d = (n = r.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase(), p = r.tagName.toLowerCase();
|
|
687
|
+
if (!d && Se[p]) {
|
|
688
|
+
const g = r.hasAttribute("aria-label"), f = r.hasAttribute("aria-labelledby");
|
|
689
|
+
if (g || f) {
|
|
690
|
+
const v = h();
|
|
691
|
+
i.push({
|
|
635
692
|
ruleId: "aria-prohibited-attr",
|
|
636
|
-
selector:
|
|
637
|
-
html:
|
|
693
|
+
selector: v.selector,
|
|
694
|
+
html: v.html,
|
|
638
695
|
impact: "serious",
|
|
639
|
-
message: `aria-label and aria-labelledby are prohibited on
|
|
696
|
+
message: `aria-label and aria-labelledby are prohibited on <${p}> elements.`
|
|
640
697
|
});
|
|
641
698
|
}
|
|
642
|
-
|
|
643
|
-
if (
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
699
|
+
} else if (d) {
|
|
700
|
+
if (V.has(d)) {
|
|
701
|
+
const f = r.hasAttribute("aria-label"), v = r.hasAttribute("aria-labelledby");
|
|
702
|
+
if (f || v) {
|
|
703
|
+
const y = h();
|
|
704
|
+
i.push({
|
|
705
|
+
ruleId: "aria-prohibited-attr",
|
|
706
|
+
selector: y.selector,
|
|
707
|
+
html: y.html,
|
|
708
|
+
impact: "serious",
|
|
709
|
+
message: `aria-label and aria-labelledby are prohibited on role "${d}".`
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
const g = xe[d];
|
|
714
|
+
if (g) {
|
|
715
|
+
for (const f of r.attributes)
|
|
716
|
+
if (f.name.startsWith("aria-") && g.has(f.name)) {
|
|
717
|
+
if ((f.name === "aria-label" || f.name === "aria-labelledby") && V.has(d))
|
|
647
718
|
continue;
|
|
719
|
+
const v = h();
|
|
648
720
|
i.push({
|
|
649
721
|
ruleId: "aria-prohibited-attr",
|
|
650
|
-
selector:
|
|
651
|
-
html:
|
|
722
|
+
selector: v.selector,
|
|
723
|
+
html: v.html,
|
|
652
724
|
impact: "serious",
|
|
653
725
|
message: `Attribute "${f.name}" is prohibited on role "${d}".`
|
|
654
726
|
});
|
|
@@ -657,10 +729,62 @@ function $(t) {
|
|
|
657
729
|
}
|
|
658
730
|
}
|
|
659
731
|
}
|
|
660
|
-
return
|
|
732
|
+
return I = new WeakRef(t), q = { validAttr: a, validAttrValue: e, prohibitedAttr: i }, q;
|
|
733
|
+
}
|
|
734
|
+
let B = /* @__PURE__ */ new WeakMap(), O = /* @__PURE__ */ new WeakMap();
|
|
735
|
+
function ie() {
|
|
736
|
+
B = /* @__PURE__ */ new WeakMap(), O = /* @__PURE__ */ new WeakMap();
|
|
737
|
+
}
|
|
738
|
+
function C(t) {
|
|
739
|
+
let a = B.get(t);
|
|
740
|
+
return a || (a = getComputedStyle(t), B.set(t, a), a);
|
|
741
|
+
}
|
|
742
|
+
function U(t, a, e) {
|
|
743
|
+
const [i, n, r] = [t, a, e].map((o) => {
|
|
744
|
+
const s = o / 255;
|
|
745
|
+
return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
746
|
+
});
|
|
747
|
+
return 0.2126 * i + 0.7152 * n + 0.0722 * r;
|
|
748
|
+
}
|
|
749
|
+
function ke(t, a) {
|
|
750
|
+
const e = Math.max(t, a), i = Math.min(t, a);
|
|
751
|
+
return (e + 0.05) / (i + 0.05);
|
|
752
|
+
}
|
|
753
|
+
function ne(t) {
|
|
754
|
+
const a = t.match(
|
|
755
|
+
/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*[\d.]+)?\s*\)/
|
|
756
|
+
);
|
|
757
|
+
return a ? [parseInt(a[1]), parseInt(a[2]), parseInt(a[3])] : null;
|
|
758
|
+
}
|
|
759
|
+
function Ie(t) {
|
|
760
|
+
const a = O.get(t);
|
|
761
|
+
if (a !== void 0) return a;
|
|
762
|
+
const e = qe(t);
|
|
763
|
+
return O.set(t, e), e;
|
|
764
|
+
}
|
|
765
|
+
function qe(t) {
|
|
766
|
+
let a = t;
|
|
767
|
+
for (; a; ) {
|
|
768
|
+
const e = C(a), i = e.backgroundColor;
|
|
769
|
+
if (i === "transparent" || i === "rgba(0, 0, 0, 0)") {
|
|
770
|
+
a = a.parentElement;
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
const n = i.match(/rgba\(.+?,\s*([\d.]+)\s*\)/);
|
|
774
|
+
if (n && parseFloat(n[1]) < 0.1) {
|
|
775
|
+
a = a.parentElement;
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
return e.backgroundImage && e.backgroundImage !== "none" ? null : ne(i);
|
|
779
|
+
}
|
|
780
|
+
return [255, 255, 255];
|
|
661
781
|
}
|
|
662
|
-
function
|
|
663
|
-
|
|
782
|
+
function Ce(t) {
|
|
783
|
+
const a = C(t), e = parseFloat(a.fontSize), i = parseInt(a.fontWeight) || (a.fontWeight === "bold" ? 700 : 400);
|
|
784
|
+
return e >= 24 || e >= 18.66 && i >= 700;
|
|
785
|
+
}
|
|
786
|
+
function Te(t) {
|
|
787
|
+
var r, o;
|
|
664
788
|
const a = [], e = t.closest("a");
|
|
665
789
|
if (e) {
|
|
666
790
|
const s = e.getAttribute("href");
|
|
@@ -669,17 +793,17 @@ function ue(t) {
|
|
|
669
793
|
const i = t.closest("figure");
|
|
670
794
|
if (i) {
|
|
671
795
|
const s = i.querySelector("figcaption");
|
|
672
|
-
(
|
|
796
|
+
(r = s == null ? void 0 : s.textContent) != null && r.trim() && a.push(`Figcaption: ${s.textContent.trim().slice(0, 100)}`);
|
|
673
797
|
}
|
|
674
|
-
const
|
|
675
|
-
if (
|
|
676
|
-
const s = (o =
|
|
798
|
+
const n = t.parentElement;
|
|
799
|
+
if (n && n !== e) {
|
|
800
|
+
const s = (o = n.textContent) == null ? void 0 : o.replace(t.alt || "", "").trim().slice(0, 100);
|
|
677
801
|
s && a.push(`Adjacent text: ${s}`);
|
|
678
802
|
}
|
|
679
803
|
return a.length > 0 ? a.join(`
|
|
680
804
|
`) : void 0;
|
|
681
805
|
}
|
|
682
|
-
const
|
|
806
|
+
const Ee = {
|
|
683
807
|
id: "img-alt",
|
|
684
808
|
wcag: ["1.1.1"],
|
|
685
809
|
level: "A",
|
|
@@ -689,17 +813,17 @@ const me = {
|
|
|
689
813
|
run(t) {
|
|
690
814
|
const a = [];
|
|
691
815
|
for (const e of t.querySelectorAll("img"))
|
|
692
|
-
|
|
816
|
+
m(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none" || !e.hasAttribute("alt") && !b(e) && a.push({
|
|
693
817
|
ruleId: "img-alt",
|
|
694
818
|
selector: c(e),
|
|
695
819
|
html: l(e),
|
|
696
820
|
impact: "critical",
|
|
697
821
|
message: "Image element missing alt attribute.",
|
|
698
|
-
context:
|
|
822
|
+
context: Te(e)
|
|
699
823
|
});
|
|
700
824
|
return a;
|
|
701
825
|
}
|
|
702
|
-
},
|
|
826
|
+
}, Le = {
|
|
703
827
|
id: "svg-img-alt",
|
|
704
828
|
wcag: ["1.1.1"],
|
|
705
829
|
level: "A",
|
|
@@ -709,8 +833,8 @@ const me = {
|
|
|
709
833
|
run(t) {
|
|
710
834
|
const a = [];
|
|
711
835
|
for (const e of t.querySelectorAll('svg[role="img"]')) {
|
|
712
|
-
if (
|
|
713
|
-
|
|
836
|
+
if (m(e)) continue;
|
|
837
|
+
b(e) || a.push({
|
|
714
838
|
ruleId: "svg-img-alt",
|
|
715
839
|
selector: c(e),
|
|
716
840
|
html: l(e),
|
|
@@ -720,7 +844,7 @@ const me = {
|
|
|
720
844
|
}
|
|
721
845
|
return a;
|
|
722
846
|
}
|
|
723
|
-
},
|
|
847
|
+
}, Re = {
|
|
724
848
|
id: "input-image-alt",
|
|
725
849
|
wcag: ["1.1.1", "4.1.2"],
|
|
726
850
|
level: "A",
|
|
@@ -730,7 +854,7 @@ const me = {
|
|
|
730
854
|
run(t) {
|
|
731
855
|
const a = [];
|
|
732
856
|
for (const e of t.querySelectorAll('input[type="image"]'))
|
|
733
|
-
|
|
857
|
+
m(e) || b(e) || a.push({
|
|
734
858
|
ruleId: "input-image-alt",
|
|
735
859
|
selector: c(e),
|
|
736
860
|
html: l(e),
|
|
@@ -739,7 +863,7 @@ const me = {
|
|
|
739
863
|
});
|
|
740
864
|
return a;
|
|
741
865
|
}
|
|
742
|
-
},
|
|
866
|
+
}, Ne = {
|
|
743
867
|
id: "image-redundant-alt",
|
|
744
868
|
wcag: [],
|
|
745
869
|
level: "A",
|
|
@@ -751,23 +875,23 @@ const me = {
|
|
|
751
875
|
var e;
|
|
752
876
|
const a = [];
|
|
753
877
|
for (const i of t.querySelectorAll("img[alt]")) {
|
|
754
|
-
const
|
|
755
|
-
if (!
|
|
756
|
-
const
|
|
757
|
-
if (
|
|
758
|
-
const o = ((e =
|
|
759
|
-
o && o ===
|
|
878
|
+
const n = i.getAttribute("alt").trim().toLowerCase();
|
|
879
|
+
if (!n) continue;
|
|
880
|
+
const r = i.closest("a, button");
|
|
881
|
+
if (r) {
|
|
882
|
+
const o = ((e = r.textContent) == null ? void 0 : e.trim().toLowerCase()) || "";
|
|
883
|
+
o && o === n && a.push({
|
|
760
884
|
ruleId: "image-redundant-alt",
|
|
761
885
|
selector: c(i),
|
|
762
886
|
html: l(i),
|
|
763
887
|
impact: "minor",
|
|
764
|
-
message: `Alt text "${i.getAttribute("alt")}" duplicates surrounding ${
|
|
888
|
+
message: `Alt text "${i.getAttribute("alt")}" duplicates surrounding ${r.tagName.toLowerCase()} text.`
|
|
765
889
|
});
|
|
766
890
|
}
|
|
767
891
|
}
|
|
768
892
|
return a;
|
|
769
893
|
}
|
|
770
|
-
},
|
|
894
|
+
}, Me = ["image", "picture", "photo", "graphic", "icon", "img"], $e = {
|
|
771
895
|
id: "image-alt-redundant-words",
|
|
772
896
|
wcag: [],
|
|
773
897
|
level: "A",
|
|
@@ -779,7 +903,7 @@ const me = {
|
|
|
779
903
|
const a = [];
|
|
780
904
|
for (const e of t.querySelectorAll("img[alt]")) {
|
|
781
905
|
const i = e.getAttribute("alt").toLowerCase();
|
|
782
|
-
i &&
|
|
906
|
+
i && Me.some((n) => i.split(/\s+/).includes(n)) && a.push({
|
|
783
907
|
ruleId: "image-alt-redundant-words",
|
|
784
908
|
selector: c(e),
|
|
785
909
|
html: l(e),
|
|
@@ -789,7 +913,7 @@ const me = {
|
|
|
789
913
|
}
|
|
790
914
|
return a;
|
|
791
915
|
}
|
|
792
|
-
},
|
|
916
|
+
}, He = {
|
|
793
917
|
id: "area-alt",
|
|
794
918
|
wcag: ["1.1.1", "4.1.2"],
|
|
795
919
|
level: "A",
|
|
@@ -799,8 +923,8 @@ const me = {
|
|
|
799
923
|
run(t) {
|
|
800
924
|
const a = [];
|
|
801
925
|
for (const e of t.querySelectorAll("area[href]")) {
|
|
802
|
-
if (
|
|
803
|
-
|
|
926
|
+
if (m(e)) continue;
|
|
927
|
+
b(e) || a.push({
|
|
804
928
|
ruleId: "area-alt",
|
|
805
929
|
selector: c(e),
|
|
806
930
|
html: l(e),
|
|
@@ -810,7 +934,7 @@ const me = {
|
|
|
810
934
|
}
|
|
811
935
|
return a;
|
|
812
936
|
}
|
|
813
|
-
},
|
|
937
|
+
}, De = {
|
|
814
938
|
id: "object-alt",
|
|
815
939
|
wcag: ["1.1.1"],
|
|
816
940
|
level: "A",
|
|
@@ -820,7 +944,7 @@ const me = {
|
|
|
820
944
|
run(t) {
|
|
821
945
|
const a = [];
|
|
822
946
|
for (const e of t.querySelectorAll("object"))
|
|
823
|
-
|
|
947
|
+
m(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none" || b(e) || a.push({
|
|
824
948
|
ruleId: "object-alt",
|
|
825
949
|
selector: c(e),
|
|
826
950
|
html: l(e),
|
|
@@ -829,7 +953,7 @@ const me = {
|
|
|
829
953
|
});
|
|
830
954
|
return a;
|
|
831
955
|
}
|
|
832
|
-
},
|
|
956
|
+
}, Be = {
|
|
833
957
|
id: "role-img-alt",
|
|
834
958
|
wcag: ["1.1.1"],
|
|
835
959
|
level: "A",
|
|
@@ -839,8 +963,8 @@ const me = {
|
|
|
839
963
|
run(t) {
|
|
840
964
|
const a = [];
|
|
841
965
|
for (const e of t.querySelectorAll('[role="img"]')) {
|
|
842
|
-
if (
|
|
843
|
-
|
|
966
|
+
if (m(e) || e.tagName.toLowerCase() === "svg" || e.tagName.toLowerCase() === "img") continue;
|
|
967
|
+
b(e) || a.push({
|
|
844
968
|
ruleId: "role-img-alt",
|
|
845
969
|
selector: c(e),
|
|
846
970
|
html: l(e),
|
|
@@ -850,26 +974,220 @@ const me = {
|
|
|
850
974
|
}
|
|
851
975
|
return a;
|
|
852
976
|
}
|
|
853
|
-
}
|
|
977
|
+
};
|
|
978
|
+
function _a(t) {
|
|
979
|
+
if (typeof t != "object" || t === null)
|
|
980
|
+
return "Rule spec must be an object";
|
|
981
|
+
const a = t;
|
|
982
|
+
if (typeof a.id != "string" || a.id.length === 0)
|
|
983
|
+
return "Rule must have a non-empty string id";
|
|
984
|
+
if (typeof a.selector != "string" || a.selector.length === 0)
|
|
985
|
+
return "Rule must have a non-empty string selector";
|
|
986
|
+
if (typeof a.check != "object" || a.check === null)
|
|
987
|
+
return "Rule must have a check object";
|
|
988
|
+
const e = a.check;
|
|
989
|
+
if (![
|
|
990
|
+
"selector-exists",
|
|
991
|
+
"attribute-value",
|
|
992
|
+
"attribute-missing",
|
|
993
|
+
"attribute-regex",
|
|
994
|
+
"child-required",
|
|
995
|
+
"child-invalid"
|
|
996
|
+
].includes(e.type))
|
|
997
|
+
return `Invalid check type: ${String(e.type)}`;
|
|
998
|
+
if (typeof a.impact != "string" || !["critical", "serious", "moderate", "minor"].includes(a.impact))
|
|
999
|
+
return "Rule must have a valid impact (critical|serious|moderate|minor)";
|
|
1000
|
+
if (typeof a.message != "string" || a.message.length === 0)
|
|
1001
|
+
return "Rule must have a non-empty message";
|
|
1002
|
+
if (typeof a.description != "string")
|
|
1003
|
+
return "Rule must have a description string";
|
|
1004
|
+
if (!Array.isArray(a.wcag))
|
|
1005
|
+
return "Rule must have a wcag array";
|
|
1006
|
+
if (typeof a.level != "string" || !["A", "AA"].includes(a.level))
|
|
1007
|
+
return "Rule must have level A or AA";
|
|
1008
|
+
const n = Oe(e);
|
|
1009
|
+
return n || null;
|
|
1010
|
+
}
|
|
1011
|
+
function Oe(t) {
|
|
1012
|
+
switch (t.type) {
|
|
1013
|
+
case "selector-exists":
|
|
1014
|
+
return null;
|
|
1015
|
+
case "attribute-value":
|
|
1016
|
+
return typeof t.attribute != "string" ? "attribute-value check requires attribute string" : [">", "<", "=", "!=", "in", "not-in"].includes(t.operator) ? t.value === void 0 ? "attribute-value check requires value" : null : "attribute-value check requires valid operator";
|
|
1017
|
+
case "attribute-missing":
|
|
1018
|
+
return typeof t.attribute != "string" ? "attribute-missing check requires attribute string" : null;
|
|
1019
|
+
case "attribute-regex":
|
|
1020
|
+
return typeof t.attribute != "string" ? "attribute-regex check requires attribute string" : typeof t.pattern != "string" ? "attribute-regex check requires pattern string" : typeof t.shouldMatch != "boolean" ? "attribute-regex check requires shouldMatch boolean" : null;
|
|
1021
|
+
case "child-required":
|
|
1022
|
+
return typeof t.childSelector != "string" ? "child-required check requires childSelector string" : null;
|
|
1023
|
+
case "child-invalid":
|
|
1024
|
+
return Array.isArray(t.allowedChildren) ? null : "child-invalid check requires allowedChildren array";
|
|
1025
|
+
default:
|
|
1026
|
+
return `Unknown check type: ${String(t.type)}`;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
function S(t, a, e) {
|
|
1030
|
+
let i = t;
|
|
1031
|
+
if (i.includes("{{tag}}") && (i = i.replace(/\{\{tag\}\}/g, a.tagName.toLowerCase())), i.includes("{{value}}")) {
|
|
1032
|
+
let n = "";
|
|
1033
|
+
"attribute" in e && e.attribute && (n = a.getAttribute(e.attribute) ?? ""), i = i.replace(/\{\{value\}\}/g, n);
|
|
1034
|
+
}
|
|
1035
|
+
return i;
|
|
1036
|
+
}
|
|
1037
|
+
function x(t) {
|
|
1038
|
+
const a = t.skipAriaHidden !== !1;
|
|
1039
|
+
return {
|
|
1040
|
+
id: t.id,
|
|
1041
|
+
wcag: t.wcag,
|
|
1042
|
+
level: t.level,
|
|
1043
|
+
tags: t.tags,
|
|
1044
|
+
description: t.description,
|
|
1045
|
+
guidance: t.guidance,
|
|
1046
|
+
prompt: t.prompt,
|
|
1047
|
+
run(e) {
|
|
1048
|
+
const i = [];
|
|
1049
|
+
switch (t.check.type) {
|
|
1050
|
+
case "selector-exists": {
|
|
1051
|
+
for (const n of e.querySelectorAll(t.selector))
|
|
1052
|
+
a && m(n) || i.push({
|
|
1053
|
+
ruleId: t.id,
|
|
1054
|
+
selector: c(n),
|
|
1055
|
+
html: l(n),
|
|
1056
|
+
impact: t.impact,
|
|
1057
|
+
message: S(t.message, n, t.check),
|
|
1058
|
+
element: n
|
|
1059
|
+
});
|
|
1060
|
+
break;
|
|
1061
|
+
}
|
|
1062
|
+
case "attribute-value": {
|
|
1063
|
+
const { attribute: n, operator: r, value: o } = t.check;
|
|
1064
|
+
for (const s of e.querySelectorAll(t.selector)) {
|
|
1065
|
+
if (a && m(s)) continue;
|
|
1066
|
+
const u = s.getAttribute(n);
|
|
1067
|
+
u !== null && We(u, r, o) && i.push({
|
|
1068
|
+
ruleId: t.id,
|
|
1069
|
+
selector: c(s),
|
|
1070
|
+
html: l(s),
|
|
1071
|
+
impact: t.impact,
|
|
1072
|
+
message: S(t.message, s, t.check),
|
|
1073
|
+
element: s
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
break;
|
|
1077
|
+
}
|
|
1078
|
+
case "attribute-missing": {
|
|
1079
|
+
const { attribute: n } = t.check;
|
|
1080
|
+
for (const r of e.querySelectorAll(t.selector))
|
|
1081
|
+
a && m(r) || r.hasAttribute(n) || i.push({
|
|
1082
|
+
ruleId: t.id,
|
|
1083
|
+
selector: c(r),
|
|
1084
|
+
html: l(r),
|
|
1085
|
+
impact: t.impact,
|
|
1086
|
+
message: S(t.message, r, t.check),
|
|
1087
|
+
element: r
|
|
1088
|
+
});
|
|
1089
|
+
break;
|
|
1090
|
+
}
|
|
1091
|
+
case "attribute-regex": {
|
|
1092
|
+
const { attribute: n, pattern: r, flags: o, shouldMatch: s } = t.check;
|
|
1093
|
+
let u;
|
|
1094
|
+
try {
|
|
1095
|
+
u = new RegExp(r, o);
|
|
1096
|
+
} catch {
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
for (const h of e.querySelectorAll(t.selector)) {
|
|
1100
|
+
if (a && m(h)) continue;
|
|
1101
|
+
const d = h.getAttribute(n);
|
|
1102
|
+
if (d === null) continue;
|
|
1103
|
+
const p = u.test(d);
|
|
1104
|
+
s && !p ? i.push({
|
|
1105
|
+
ruleId: t.id,
|
|
1106
|
+
selector: c(h),
|
|
1107
|
+
html: l(h),
|
|
1108
|
+
impact: t.impact,
|
|
1109
|
+
message: S(t.message, h, t.check),
|
|
1110
|
+
element: h
|
|
1111
|
+
}) : !s && p && i.push({
|
|
1112
|
+
ruleId: t.id,
|
|
1113
|
+
selector: c(h),
|
|
1114
|
+
html: l(h),
|
|
1115
|
+
impact: t.impact,
|
|
1116
|
+
message: S(t.message, h, t.check),
|
|
1117
|
+
element: h
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
break;
|
|
1121
|
+
}
|
|
1122
|
+
case "child-required": {
|
|
1123
|
+
const { childSelector: n } = t.check;
|
|
1124
|
+
for (const r of e.querySelectorAll(t.selector))
|
|
1125
|
+
a && m(r) || r.querySelector(n) || i.push({
|
|
1126
|
+
ruleId: t.id,
|
|
1127
|
+
selector: c(r),
|
|
1128
|
+
html: l(r),
|
|
1129
|
+
impact: t.impact,
|
|
1130
|
+
message: S(t.message, r, t.check),
|
|
1131
|
+
element: r
|
|
1132
|
+
});
|
|
1133
|
+
break;
|
|
1134
|
+
}
|
|
1135
|
+
case "child-invalid": {
|
|
1136
|
+
const n = new Set(
|
|
1137
|
+
t.check.allowedChildren.map((r) => r.toLowerCase())
|
|
1138
|
+
);
|
|
1139
|
+
for (const r of e.querySelectorAll(t.selector))
|
|
1140
|
+
if (!(a && m(r))) {
|
|
1141
|
+
for (const o of r.children)
|
|
1142
|
+
if (!n.has(o.tagName.toLowerCase())) {
|
|
1143
|
+
i.push({
|
|
1144
|
+
ruleId: t.id,
|
|
1145
|
+
selector: c(o),
|
|
1146
|
+
html: l(o),
|
|
1147
|
+
impact: t.impact,
|
|
1148
|
+
message: S(t.message, o, t.check),
|
|
1149
|
+
element: o
|
|
1150
|
+
});
|
|
1151
|
+
break;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
break;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
return i;
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
function We(t, a, e) {
|
|
1162
|
+
switch (a) {
|
|
1163
|
+
case ">":
|
|
1164
|
+
return parseFloat(t) > e;
|
|
1165
|
+
case "<":
|
|
1166
|
+
return parseFloat(t) < e;
|
|
1167
|
+
case "=":
|
|
1168
|
+
return t === String(e);
|
|
1169
|
+
case "!=":
|
|
1170
|
+
return t !== String(e);
|
|
1171
|
+
case "in":
|
|
1172
|
+
return Array.isArray(e) && e.includes(t);
|
|
1173
|
+
case "not-in":
|
|
1174
|
+
return Array.isArray(e) && !e.includes(t);
|
|
1175
|
+
default:
|
|
1176
|
+
return !1;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
const _e = {
|
|
854
1180
|
id: "server-side-image-map",
|
|
1181
|
+
selector: "img[ismap], input[type='image'][ismap]",
|
|
1182
|
+
check: { type: "selector-exists" },
|
|
1183
|
+
impact: "minor",
|
|
1184
|
+
message: "Server-side image map detected. Use client-side image map with <map> and <area> elements instead.",
|
|
1185
|
+
description: "Server-side image maps must not be used.",
|
|
855
1186
|
wcag: ["2.1.1"],
|
|
856
1187
|
level: "A",
|
|
857
|
-
description: "Server-side image maps must not be used.",
|
|
858
1188
|
guidance: "Server-side image maps (using ismap attribute) send click coordinates to the server, which is inaccessible to keyboard users and screen readers who can't precisely click specific regions. Replace with client-side image maps (<map> with <area> elements) that provide keyboard access and accessible names, or use linked images/buttons instead.",
|
|
859
|
-
prompt: "Explain that the ismap attribute should be removed and the functionality replaced with a client-side <map> element with <area> children, or separate linked images/buttons."
|
|
860
|
-
|
|
861
|
-
const a = [];
|
|
862
|
-
for (const e of t.querySelectorAll("img[ismap], input[type='image'][ismap]"))
|
|
863
|
-
u(e) || a.push({
|
|
864
|
-
ruleId: "server-side-image-map",
|
|
865
|
-
selector: c(e),
|
|
866
|
-
html: l(e),
|
|
867
|
-
impact: "minor",
|
|
868
|
-
message: "Server-side image map detected. Use client-side image map with <map> and <area> elements instead."
|
|
869
|
-
});
|
|
870
|
-
return a;
|
|
871
|
-
}
|
|
872
|
-
}, Se = {
|
|
1189
|
+
prompt: "Explain that the ismap attribute should be removed and the functionality replaced with a client-side <map> element with <area> children, or separate linked images/buttons."
|
|
1190
|
+
}, Fe = x(_e), Pe = {
|
|
873
1191
|
id: "label",
|
|
874
1192
|
wcag: ["4.1.2"],
|
|
875
1193
|
level: "A",
|
|
@@ -881,8 +1199,8 @@ const me = {
|
|
|
881
1199
|
'input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select'
|
|
882
1200
|
);
|
|
883
1201
|
for (const i of e) {
|
|
884
|
-
if (
|
|
885
|
-
|
|
1202
|
+
if (m(i)) continue;
|
|
1203
|
+
b(i) || a.push({
|
|
886
1204
|
ruleId: "label",
|
|
887
1205
|
selector: c(i),
|
|
888
1206
|
html: l(i),
|
|
@@ -892,7 +1210,7 @@ const me = {
|
|
|
892
1210
|
}
|
|
893
1211
|
return a;
|
|
894
1212
|
}
|
|
895
|
-
},
|
|
1213
|
+
}, Ve = {
|
|
896
1214
|
id: "form-field-multiple-labels",
|
|
897
1215
|
wcag: [],
|
|
898
1216
|
level: "A",
|
|
@@ -903,17 +1221,17 @@ const me = {
|
|
|
903
1221
|
run(t) {
|
|
904
1222
|
const a = [], e = t.querySelectorAll('input:not([type="hidden"]), textarea, select');
|
|
905
1223
|
for (const i of e) {
|
|
906
|
-
if (
|
|
907
|
-
const
|
|
908
|
-
let
|
|
1224
|
+
if (m(i) || !i.id) continue;
|
|
1225
|
+
const n = t.querySelectorAll(`label[for="${CSS.escape(i.id)}"]`);
|
|
1226
|
+
let r = 0, o = i.parentElement;
|
|
909
1227
|
for (; o; ) {
|
|
910
1228
|
if (o.tagName.toLowerCase() === "label" && !o.hasAttribute("for")) {
|
|
911
|
-
|
|
1229
|
+
r++;
|
|
912
1230
|
break;
|
|
913
1231
|
}
|
|
914
1232
|
o = o.parentElement;
|
|
915
1233
|
}
|
|
916
|
-
const s =
|
|
1234
|
+
const s = n.length + r;
|
|
917
1235
|
s > 1 && a.push({
|
|
918
1236
|
ruleId: "form-field-multiple-labels",
|
|
919
1237
|
selector: c(i),
|
|
@@ -924,7 +1242,7 @@ const me = {
|
|
|
924
1242
|
}
|
|
925
1243
|
return a;
|
|
926
1244
|
}
|
|
927
|
-
},
|
|
1245
|
+
}, Ue = {
|
|
928
1246
|
id: "select-name",
|
|
929
1247
|
wcag: ["4.1.2"],
|
|
930
1248
|
level: "A",
|
|
@@ -934,7 +1252,7 @@ const me = {
|
|
|
934
1252
|
run(t) {
|
|
935
1253
|
const a = [];
|
|
936
1254
|
for (const e of t.querySelectorAll("select"))
|
|
937
|
-
|
|
1255
|
+
m(e) || b(e) || a.push({
|
|
938
1256
|
ruleId: "select-name",
|
|
939
1257
|
selector: c(e),
|
|
940
1258
|
html: l(e),
|
|
@@ -943,7 +1261,7 @@ const me = {
|
|
|
943
1261
|
});
|
|
944
1262
|
return a;
|
|
945
1263
|
}
|
|
946
|
-
},
|
|
1264
|
+
}, je = {
|
|
947
1265
|
id: "input-button-name",
|
|
948
1266
|
wcag: ["4.1.2"],
|
|
949
1267
|
level: "A",
|
|
@@ -953,22 +1271,22 @@ const me = {
|
|
|
953
1271
|
run(t) {
|
|
954
1272
|
var e, i;
|
|
955
1273
|
const a = [];
|
|
956
|
-
for (const
|
|
1274
|
+
for (const n of t.querySelectorAll(
|
|
957
1275
|
'input[type="submit"], input[type="button"], input[type="reset"]'
|
|
958
1276
|
)) {
|
|
959
|
-
if (
|
|
960
|
-
const
|
|
961
|
-
!
|
|
1277
|
+
if (m(n)) continue;
|
|
1278
|
+
const r = (e = n.getAttribute("value")) == null ? void 0 : e.trim(), o = (i = n.getAttribute("type")) == null ? void 0 : i.toLowerCase(), s = (o === "submit" || o === "reset") && !n.hasAttribute("value");
|
|
1279
|
+
!r && !s && !b(n) && a.push({
|
|
962
1280
|
ruleId: "input-button-name",
|
|
963
|
-
selector: c(
|
|
964
|
-
html: l(
|
|
1281
|
+
selector: c(n),
|
|
1282
|
+
html: l(n),
|
|
965
1283
|
impact: "critical",
|
|
966
1284
|
message: "Input button has no discernible text."
|
|
967
1285
|
});
|
|
968
1286
|
}
|
|
969
1287
|
return a;
|
|
970
1288
|
}
|
|
971
|
-
},
|
|
1289
|
+
}, ze = /* @__PURE__ */ new Set([
|
|
972
1290
|
"off",
|
|
973
1291
|
"on",
|
|
974
1292
|
"name",
|
|
@@ -1023,7 +1341,7 @@ const me = {
|
|
|
1023
1341
|
"impp",
|
|
1024
1342
|
"url",
|
|
1025
1343
|
"photo"
|
|
1026
|
-
]),
|
|
1344
|
+
]), Ge = {
|
|
1027
1345
|
id: "autocomplete-valid",
|
|
1028
1346
|
wcag: ["1.3.5"],
|
|
1029
1347
|
level: "AA",
|
|
@@ -1035,8 +1353,8 @@ const me = {
|
|
|
1035
1353
|
for (const e of t.querySelectorAll("[autocomplete]")) {
|
|
1036
1354
|
const i = e.getAttribute("autocomplete").trim();
|
|
1037
1355
|
if (!i) continue;
|
|
1038
|
-
const
|
|
1039
|
-
|
|
1356
|
+
const n = i.split(/\s+/), r = n[n.length - 1];
|
|
1357
|
+
ze.has(r) || a.push({
|
|
1040
1358
|
ruleId: "autocomplete-valid",
|
|
1041
1359
|
selector: c(e),
|
|
1042
1360
|
html: l(e),
|
|
@@ -1047,30 +1365,30 @@ const me = {
|
|
|
1047
1365
|
return a;
|
|
1048
1366
|
}
|
|
1049
1367
|
};
|
|
1050
|
-
function
|
|
1368
|
+
function j(t) {
|
|
1051
1369
|
return t.toLowerCase().replace(/\s+/g, " ").trim();
|
|
1052
1370
|
}
|
|
1053
|
-
function
|
|
1054
|
-
const e =
|
|
1371
|
+
function z(t, a) {
|
|
1372
|
+
const e = j(t), i = j(a);
|
|
1055
1373
|
if (!e || !i || e.includes(i) || i.includes(e)) return !0;
|
|
1056
|
-
const
|
|
1057
|
-
return
|
|
1374
|
+
const n = i.split(/\s+/).map((r) => r.replace(/[.,;:!?\u2026]+$/g, "")).filter((r) => r.length > 2);
|
|
1375
|
+
return n.length >= 2 && n.filter((o) => e.includes(o)).length / n.length > 0.5;
|
|
1058
1376
|
}
|
|
1059
|
-
function
|
|
1377
|
+
function W(t) {
|
|
1060
1378
|
let a = "";
|
|
1061
1379
|
for (const e of t.childNodes)
|
|
1062
1380
|
if (e.nodeType === 3)
|
|
1063
1381
|
a += e.textContent ?? "";
|
|
1064
1382
|
else if (e.nodeType === 1) {
|
|
1065
|
-
const i = e;
|
|
1066
|
-
if (
|
|
1067
|
-
const
|
|
1068
|
-
if (
|
|
1069
|
-
a +=
|
|
1383
|
+
const i = e, n = i.tagName.toLowerCase();
|
|
1384
|
+
if (n === "style" || n === "script" || n === "svg" || i.getAttribute("aria-hidden") === "true" || i instanceof HTMLElement && i.style.display === "none") continue;
|
|
1385
|
+
const r = i.getAttribute("role");
|
|
1386
|
+
if (r === "img" || r === "presentation" || r === "none") continue;
|
|
1387
|
+
a += W(i);
|
|
1070
1388
|
}
|
|
1071
1389
|
return a;
|
|
1072
1390
|
}
|
|
1073
|
-
const
|
|
1391
|
+
const Xe = {
|
|
1074
1392
|
id: "label-content-name-mismatch",
|
|
1075
1393
|
wcag: ["2.5.3"],
|
|
1076
1394
|
level: "A",
|
|
@@ -1080,33 +1398,33 @@ const Te = {
|
|
|
1080
1398
|
run(t) {
|
|
1081
1399
|
const a = [];
|
|
1082
1400
|
for (const e of t.querySelectorAll('button, [role="button"], a[href], input[type="submit"], input[type="button"]')) {
|
|
1083
|
-
if (
|
|
1084
|
-
const i =
|
|
1401
|
+
if (m(e)) continue;
|
|
1402
|
+
const i = b(e);
|
|
1085
1403
|
if (!i) continue;
|
|
1086
|
-
let
|
|
1087
|
-
e instanceof HTMLInputElement ?
|
|
1088
|
-
const
|
|
1089
|
-
if (!
|
|
1404
|
+
let n = "";
|
|
1405
|
+
e instanceof HTMLInputElement ? n = e.value || "" : n = W(e);
|
|
1406
|
+
const r = n.trim();
|
|
1407
|
+
if (!r || r.length <= 2) continue;
|
|
1090
1408
|
const o = e.hasAttribute("aria-label"), s = e.hasAttribute("aria-labelledby");
|
|
1091
|
-
!o && !s ||
|
|
1409
|
+
!o && !s || z(i, n) || a.push({
|
|
1092
1410
|
ruleId: "label-content-name-mismatch",
|
|
1093
1411
|
selector: c(e),
|
|
1094
1412
|
html: l(e),
|
|
1095
1413
|
impact: "serious",
|
|
1096
|
-
message: `Accessible name "${i}" does not contain visible text "${
|
|
1414
|
+
message: `Accessible name "${i}" does not contain visible text "${n.trim()}".`
|
|
1097
1415
|
});
|
|
1098
1416
|
}
|
|
1099
1417
|
for (const e of t.querySelectorAll("input, select, textarea")) {
|
|
1100
|
-
if (
|
|
1101
|
-
const i =
|
|
1418
|
+
if (m(e) || e instanceof HTMLInputElement && ["hidden", "submit", "button", "image"].includes(e.type)) continue;
|
|
1419
|
+
const i = b(e);
|
|
1102
1420
|
if (!i || !e.hasAttribute("aria-label")) continue;
|
|
1103
|
-
const
|
|
1421
|
+
const r = e.id;
|
|
1104
1422
|
let o = "";
|
|
1105
|
-
if (
|
|
1106
|
-
const s = t.querySelector(`label[for="${CSS.escape(
|
|
1107
|
-
s && (o =
|
|
1423
|
+
if (r) {
|
|
1424
|
+
const s = t.querySelector(`label[for="${CSS.escape(r)}"]`);
|
|
1425
|
+
s && (o = W(s));
|
|
1108
1426
|
}
|
|
1109
|
-
o.trim() && (
|
|
1427
|
+
o.trim() && (z(i, o) || a.push({
|
|
1110
1428
|
ruleId: "label-content-name-mismatch",
|
|
1111
1429
|
selector: c(e),
|
|
1112
1430
|
html: l(e),
|
|
@@ -1116,7 +1434,7 @@ const Te = {
|
|
|
1116
1434
|
}
|
|
1117
1435
|
return a;
|
|
1118
1436
|
}
|
|
1119
|
-
},
|
|
1437
|
+
}, Ke = {
|
|
1120
1438
|
id: "label-title-only",
|
|
1121
1439
|
wcag: [],
|
|
1122
1440
|
level: "A",
|
|
@@ -1125,21 +1443,21 @@ const Te = {
|
|
|
1125
1443
|
guidance: "The title attribute is unreliable as a label because it only appears on hover/focus (not visible to touch users) and is often ignored by assistive technologies. Use a visible <label> element, aria-label, or aria-labelledby instead. Title can supplement a label but should not replace it.",
|
|
1126
1444
|
prompt: "The title attribute text should be moved to a visible <label> element or aria-label. Show what text to use based on the current title.",
|
|
1127
1445
|
run(t) {
|
|
1128
|
-
var i,
|
|
1446
|
+
var i, n, r, o;
|
|
1129
1447
|
const a = [], e = t.querySelectorAll(
|
|
1130
1448
|
'input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select'
|
|
1131
1449
|
);
|
|
1132
1450
|
for (const s of e) {
|
|
1133
|
-
if (
|
|
1134
|
-
const
|
|
1451
|
+
if (m(s)) continue;
|
|
1452
|
+
const u = s.hasAttribute("title") && ((i = s.getAttribute("title")) == null ? void 0 : i.trim()), h = s.hasAttribute("aria-label") && ((n = s.getAttribute("aria-label")) == null ? void 0 : n.trim()), d = s.hasAttribute("aria-labelledby");
|
|
1135
1453
|
let p = !1;
|
|
1136
|
-
const
|
|
1137
|
-
if (
|
|
1138
|
-
const v = s.ownerDocument.querySelector(`label[for="${CSS.escape(
|
|
1139
|
-
(
|
|
1454
|
+
const g = s.id;
|
|
1455
|
+
if (g) {
|
|
1456
|
+
const v = s.ownerDocument.querySelector(`label[for="${CSS.escape(g)}"]`);
|
|
1457
|
+
(r = v == null ? void 0 : v.textContent) != null && r.trim() && (p = !0);
|
|
1140
1458
|
}
|
|
1141
1459
|
const f = s.closest("label");
|
|
1142
|
-
(o = f == null ? void 0 : f.textContent) != null && o.trim() && (p = !0),
|
|
1460
|
+
(o = f == null ? void 0 : f.textContent) != null && o.trim() && (p = !0), u && !h && !d && !p && a.push({
|
|
1143
1461
|
ruleId: "label-title-only",
|
|
1144
1462
|
selector: c(s),
|
|
1145
1463
|
html: l(s),
|
|
@@ -1149,29 +1467,19 @@ const Te = {
|
|
|
1149
1467
|
}
|
|
1150
1468
|
return a;
|
|
1151
1469
|
}
|
|
1152
|
-
},
|
|
1470
|
+
}, Ye = {
|
|
1153
1471
|
id: "tabindex",
|
|
1472
|
+
selector: "[tabindex]",
|
|
1473
|
+
check: { type: "attribute-value", attribute: "tabindex", operator: ">", value: 0 },
|
|
1474
|
+
impact: "serious",
|
|
1475
|
+
message: 'Element has tabindex="{{value}}" which disrupts tab order.',
|
|
1476
|
+
description: "Elements should not have tabindex greater than 0, which disrupts natural tab order.",
|
|
1154
1477
|
wcag: [],
|
|
1155
|
-
tags: ["best-practice"],
|
|
1156
1478
|
level: "A",
|
|
1157
|
-
|
|
1479
|
+
tags: ["best-practice"],
|
|
1158
1480
|
guidance: "Positive tabindex values force elements to the front of the tab order regardless of DOM position, creating unpredictable navigation for keyboard users. Use tabindex='0' to add elements to the natural tab order, or tabindex='-1' to make elements programmatically focusable but not in tab order. Rely on DOM order for tab sequence.",
|
|
1159
|
-
prompt: "Change the positive tabindex value to tabindex='0' and rely on DOM order for tab sequence instead."
|
|
1160
|
-
|
|
1161
|
-
const a = [];
|
|
1162
|
-
for (const e of t.querySelectorAll("[tabindex]")) {
|
|
1163
|
-
const i = parseInt(e.getAttribute("tabindex"), 10);
|
|
1164
|
-
i > 0 && a.push({
|
|
1165
|
-
ruleId: "tabindex",
|
|
1166
|
-
selector: c(e),
|
|
1167
|
-
html: l(e),
|
|
1168
|
-
impact: "serious",
|
|
1169
|
-
message: `Element has tabindex="${i}" which disrupts tab order.`
|
|
1170
|
-
});
|
|
1171
|
-
}
|
|
1172
|
-
return a;
|
|
1173
|
-
}
|
|
1174
|
-
}, Re = /* @__PURE__ */ new Set([
|
|
1481
|
+
prompt: "Change the positive tabindex value to tabindex='0' and rely on DOM order for tab sequence instead."
|
|
1482
|
+
}, Qe = x(Ye), Je = /* @__PURE__ */ new Set([
|
|
1175
1483
|
"div",
|
|
1176
1484
|
"span",
|
|
1177
1485
|
"p",
|
|
@@ -1198,7 +1506,7 @@ const Te = {
|
|
|
1198
1506
|
"tr",
|
|
1199
1507
|
"td",
|
|
1200
1508
|
"th"
|
|
1201
|
-
]),
|
|
1509
|
+
]), Ze = {
|
|
1202
1510
|
id: "focus-order-semantics",
|
|
1203
1511
|
wcag: [],
|
|
1204
1512
|
tags: ["best-practice"],
|
|
@@ -1210,7 +1518,7 @@ const Te = {
|
|
|
1210
1518
|
const a = [];
|
|
1211
1519
|
for (const e of t.querySelectorAll('[tabindex="0"]')) {
|
|
1212
1520
|
const i = e.tagName.toLowerCase();
|
|
1213
|
-
if (!
|
|
1521
|
+
if (!Je.has(i)) continue;
|
|
1214
1522
|
e.getAttribute("role") || a.push({
|
|
1215
1523
|
ruleId: "focus-order-semantics",
|
|
1216
1524
|
selector: c(e),
|
|
@@ -1221,7 +1529,7 @@ const Te = {
|
|
|
1221
1529
|
}
|
|
1222
1530
|
return a;
|
|
1223
1531
|
}
|
|
1224
|
-
},
|
|
1532
|
+
}, et = /* @__PURE__ */ new Set([
|
|
1225
1533
|
"a",
|
|
1226
1534
|
"audio",
|
|
1227
1535
|
"button",
|
|
@@ -1230,7 +1538,7 @@ const Te = {
|
|
|
1230
1538
|
"select",
|
|
1231
1539
|
"textarea",
|
|
1232
1540
|
"video"
|
|
1233
|
-
]),
|
|
1541
|
+
]), tt = /* @__PURE__ */ new Set([
|
|
1234
1542
|
"button",
|
|
1235
1543
|
"checkbox",
|
|
1236
1544
|
"combobox",
|
|
@@ -1254,7 +1562,7 @@ const Te = {
|
|
|
1254
1562
|
"tabpanel",
|
|
1255
1563
|
"textbox",
|
|
1256
1564
|
"treeitem"
|
|
1257
|
-
]),
|
|
1565
|
+
]), at = {
|
|
1258
1566
|
grid: /* @__PURE__ */ new Set(["gridcell", "row", "columnheader", "rowheader"]),
|
|
1259
1567
|
listbox: /* @__PURE__ */ new Set(["option"]),
|
|
1260
1568
|
menu: /* @__PURE__ */ new Set(["menuitem", "menuitemcheckbox", "menuitemradio"]),
|
|
@@ -1264,26 +1572,26 @@ const Te = {
|
|
|
1264
1572
|
tree: /* @__PURE__ */ new Set(["treeitem"]),
|
|
1265
1573
|
treegrid: /* @__PURE__ */ new Set(["gridcell", "row", "columnheader", "rowheader", "treeitem"])
|
|
1266
1574
|
};
|
|
1267
|
-
function
|
|
1268
|
-
var
|
|
1269
|
-
const e = (
|
|
1270
|
-
return !e || !i ? !1 : ((o =
|
|
1575
|
+
function it(t, a) {
|
|
1576
|
+
var n, r, o;
|
|
1577
|
+
const e = (n = t.getAttribute("role")) == null ? void 0 : n.toLowerCase(), i = (r = a.getAttribute("role")) == null ? void 0 : r.toLowerCase();
|
|
1578
|
+
return !e || !i ? !1 : ((o = at[e]) == null ? void 0 : o.has(i)) ?? !1;
|
|
1271
1579
|
}
|
|
1272
|
-
function
|
|
1273
|
-
var
|
|
1580
|
+
function nt(t) {
|
|
1581
|
+
var n;
|
|
1274
1582
|
const a = t.tagName.toLowerCase();
|
|
1275
|
-
if (
|
|
1583
|
+
if (et.has(a))
|
|
1276
1584
|
return a === "a" && !t.hasAttribute("href") ? !1 : a === "audio" || a === "video" ? t.hasAttribute("controls") : !(a === "img" && !t.hasAttribute("usemap") || a === "input" && t.type === "hidden" || t.disabled);
|
|
1277
|
-
const e = (
|
|
1278
|
-
if (e &&
|
|
1585
|
+
const e = (n = t.getAttribute("role")) == null ? void 0 : n.toLowerCase();
|
|
1586
|
+
if (e && tt.has(e)) return !0;
|
|
1279
1587
|
const i = t.getAttribute("tabindex");
|
|
1280
1588
|
return i !== null && i !== "-1" || t.getAttribute("contenteditable") === "true";
|
|
1281
1589
|
}
|
|
1282
|
-
function
|
|
1590
|
+
function rt(t) {
|
|
1283
1591
|
const a = t.tagName.toLowerCase();
|
|
1284
1592
|
return !!(a === "a" && t.hasAttribute("href") || a === "button" && !t.disabled);
|
|
1285
1593
|
}
|
|
1286
|
-
const
|
|
1594
|
+
const ot = {
|
|
1287
1595
|
id: "nested-interactive",
|
|
1288
1596
|
wcag: ["4.1.2"],
|
|
1289
1597
|
level: "A",
|
|
@@ -1293,15 +1601,15 @@ const We = {
|
|
|
1293
1601
|
run(t) {
|
|
1294
1602
|
const a = [], e = t.body ?? t;
|
|
1295
1603
|
if (!e) return a;
|
|
1296
|
-
const
|
|
1297
|
-
let o =
|
|
1604
|
+
const n = (t.body ? t : t.ownerDocument).createTreeWalker(e, NodeFilter.SHOW_ELEMENT), r = [];
|
|
1605
|
+
let o = n.currentNode;
|
|
1298
1606
|
for (; o; ) {
|
|
1299
|
-
for (;
|
|
1300
|
-
|
|
1301
|
-
if (!
|
|
1302
|
-
if (
|
|
1303
|
-
const s =
|
|
1304
|
-
|
|
1607
|
+
for (; r.length > 0 && !r[r.length - 1].contains(o); )
|
|
1608
|
+
r.pop();
|
|
1609
|
+
if (!m(o) && nt(o)) {
|
|
1610
|
+
if (r.length > 0) {
|
|
1611
|
+
const s = r[r.length - 1];
|
|
1612
|
+
it(s, o) || a.push({
|
|
1305
1613
|
ruleId: "nested-interactive",
|
|
1306
1614
|
selector: c(o),
|
|
1307
1615
|
html: l(o),
|
|
@@ -1309,13 +1617,13 @@ const We = {
|
|
|
1309
1617
|
message: `Interactive element <${o.tagName.toLowerCase()}> is nested inside <${s.tagName.toLowerCase()}>.`
|
|
1310
1618
|
});
|
|
1311
1619
|
}
|
|
1312
|
-
|
|
1620
|
+
rt(o) && r.push(o);
|
|
1313
1621
|
}
|
|
1314
|
-
o =
|
|
1622
|
+
o = n.nextNode();
|
|
1315
1623
|
}
|
|
1316
1624
|
return a;
|
|
1317
1625
|
}
|
|
1318
|
-
},
|
|
1626
|
+
}, st = {
|
|
1319
1627
|
id: "scrollable-region-focusable",
|
|
1320
1628
|
wcag: ["2.1.1"],
|
|
1321
1629
|
level: "A",
|
|
@@ -1325,13 +1633,11 @@ const We = {
|
|
|
1325
1633
|
run(t) {
|
|
1326
1634
|
const a = [];
|
|
1327
1635
|
for (const e of t.querySelectorAll("*")) {
|
|
1328
|
-
if (
|
|
1329
|
-
const i =
|
|
1330
|
-
if (!r) continue;
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
const h = e.getAttribute("tabindex");
|
|
1334
|
-
h !== null && h !== "-1" || e.querySelector(
|
|
1636
|
+
if (m(e) || !(e instanceof HTMLElement)) continue;
|
|
1637
|
+
const i = C(e), n = i.overflowX, r = i.overflowY;
|
|
1638
|
+
if (!(n === "scroll" || n === "auto" || r === "scroll" || r === "auto") || !(e.scrollHeight > e.clientHeight || e.scrollWidth > e.clientWidth)) continue;
|
|
1639
|
+
const u = e.getAttribute("tabindex");
|
|
1640
|
+
u !== null && u !== "-1" || e.querySelector(
|
|
1335
1641
|
'a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
1336
1642
|
) || a.push({
|
|
1337
1643
|
ruleId: "scrollable-region-focusable",
|
|
@@ -1343,7 +1649,7 @@ const We = {
|
|
|
1343
1649
|
}
|
|
1344
1650
|
return a;
|
|
1345
1651
|
}
|
|
1346
|
-
},
|
|
1652
|
+
}, lt = {
|
|
1347
1653
|
id: "accesskeys",
|
|
1348
1654
|
wcag: [],
|
|
1349
1655
|
level: "A",
|
|
@@ -1354,26 +1660,26 @@ const We = {
|
|
|
1354
1660
|
run(t) {
|
|
1355
1661
|
var i;
|
|
1356
1662
|
const a = [], e = /* @__PURE__ */ new Map();
|
|
1357
|
-
for (const
|
|
1358
|
-
if (
|
|
1359
|
-
const
|
|
1360
|
-
if (!
|
|
1361
|
-
const o = e.get(
|
|
1362
|
-
o.push(
|
|
1663
|
+
for (const n of t.querySelectorAll("[accesskey]")) {
|
|
1664
|
+
if (m(n)) continue;
|
|
1665
|
+
const r = (i = n.getAttribute("accesskey")) == null ? void 0 : i.trim().toLowerCase();
|
|
1666
|
+
if (!r) continue;
|
|
1667
|
+
const o = e.get(r) || [];
|
|
1668
|
+
o.push(n), e.set(r, o);
|
|
1363
1669
|
}
|
|
1364
|
-
for (const [
|
|
1365
|
-
if (
|
|
1366
|
-
for (const o of
|
|
1670
|
+
for (const [n, r] of e)
|
|
1671
|
+
if (r.length > 1)
|
|
1672
|
+
for (const o of r.slice(1))
|
|
1367
1673
|
a.push({
|
|
1368
1674
|
ruleId: "accesskeys",
|
|
1369
1675
|
selector: c(o),
|
|
1370
1676
|
html: l(o),
|
|
1371
1677
|
impact: "serious",
|
|
1372
|
-
message: `Duplicate accesskey "${
|
|
1678
|
+
message: `Duplicate accesskey "${n}". Each accesskey must be unique.`
|
|
1373
1679
|
});
|
|
1374
1680
|
return a;
|
|
1375
1681
|
}
|
|
1376
|
-
},
|
|
1682
|
+
}, ct = {
|
|
1377
1683
|
id: "heading-order",
|
|
1378
1684
|
wcag: [],
|
|
1379
1685
|
level: "A",
|
|
@@ -1383,22 +1689,22 @@ const We = {
|
|
|
1383
1689
|
prompt: "State which heading level was expected and suggest changing this heading to the appropriate level.",
|
|
1384
1690
|
run(t) {
|
|
1385
1691
|
const a = [], e = t.querySelectorAll("h1, h2, h3, h4, h5, h6, [role='heading']");
|
|
1386
|
-
let i = 0,
|
|
1387
|
-
for (const
|
|
1388
|
-
if (
|
|
1692
|
+
let i = 0, n = null;
|
|
1693
|
+
for (const r of e) {
|
|
1694
|
+
if (m(r)) continue;
|
|
1389
1695
|
let o;
|
|
1390
|
-
|
|
1696
|
+
r.hasAttribute("aria-level") ? o = parseInt(r.getAttribute("aria-level"), 10) : o = parseInt(r.tagName[1], 10), i > 0 && o > i + 1 && a.push({
|
|
1391
1697
|
ruleId: "heading-order",
|
|
1392
|
-
selector: c(
|
|
1393
|
-
html: l(
|
|
1698
|
+
selector: c(r),
|
|
1699
|
+
html: l(r),
|
|
1394
1700
|
impact: "moderate",
|
|
1395
1701
|
message: `Heading level ${o} skipped from level ${i}.`,
|
|
1396
|
-
context:
|
|
1397
|
-
}), i = o,
|
|
1702
|
+
context: n ? `Previous heading: ${l(n)}` : void 0
|
|
1703
|
+
}), i = o, n = r;
|
|
1398
1704
|
}
|
|
1399
1705
|
return a;
|
|
1400
1706
|
}
|
|
1401
|
-
},
|
|
1707
|
+
}, L = 'article, aside, main, nav, section, [role="article"], [role="complementary"], [role="main"], [role="navigation"], [role="region"]', G = 'main, [role="main"], header, [role="banner"], footer, [role="contentinfo"], nav, [role="navigation"], aside, [role="complementary"], section[aria-label], section[aria-labelledby], [role="region"][aria-label], [role="region"][aria-labelledby], form[aria-label], form[aria-labelledby], [role="form"][aria-label], [role="form"][aria-labelledby], [role="search"]', dt = {
|
|
1402
1708
|
id: "landmark-one-main",
|
|
1403
1709
|
wcag: [],
|
|
1404
1710
|
level: "A",
|
|
@@ -1422,7 +1728,7 @@ const We = {
|
|
|
1422
1728
|
message: "Page has multiple main landmarks."
|
|
1423
1729
|
})) : [];
|
|
1424
1730
|
}
|
|
1425
|
-
},
|
|
1731
|
+
}, ut = {
|
|
1426
1732
|
id: "landmark-no-duplicate-banner",
|
|
1427
1733
|
wcag: [],
|
|
1428
1734
|
level: "A",
|
|
@@ -1431,18 +1737,18 @@ const We = {
|
|
|
1431
1737
|
guidance: "The banner landmark (typically <header>) identifies site-oriented content like logos and search. Only one top-level banner is allowed per page. If you need multiple headers, nest them inside sectioning elements (article, section, aside) where they become scoped headers rather than page-level banners.",
|
|
1432
1738
|
prompt: "Explain whether to remove this duplicate banner or nest it inside a sectioning element.",
|
|
1433
1739
|
run(t) {
|
|
1434
|
-
const a = [], e = t.querySelectorAll('header, [role="banner"]'), i = Array.from(e).filter((
|
|
1740
|
+
const a = [], e = t.querySelectorAll('header, [role="banner"]'), i = Array.from(e).filter((n) => !n.closest(L));
|
|
1435
1741
|
return i.length > 1 && i.slice(1).forEach(
|
|
1436
|
-
(
|
|
1742
|
+
(n) => a.push({
|
|
1437
1743
|
ruleId: "landmark-no-duplicate-banner",
|
|
1438
|
-
selector: c(
|
|
1439
|
-
html: l(
|
|
1744
|
+
selector: c(n),
|
|
1745
|
+
html: l(n),
|
|
1440
1746
|
impact: "moderate",
|
|
1441
1747
|
message: "Page has multiple banner landmarks."
|
|
1442
1748
|
})
|
|
1443
1749
|
), a;
|
|
1444
1750
|
}
|
|
1445
|
-
},
|
|
1751
|
+
}, mt = {
|
|
1446
1752
|
id: "landmark-no-duplicate-contentinfo",
|
|
1447
1753
|
wcag: [],
|
|
1448
1754
|
level: "A",
|
|
@@ -1451,18 +1757,18 @@ const We = {
|
|
|
1451
1757
|
guidance: "The contentinfo landmark (typically <footer>) contains information about the page like copyright and contact info. Only one top-level contentinfo is allowed per page. Nest additional footers inside sectioning elements to scope them.",
|
|
1452
1758
|
prompt: "Explain whether to remove this duplicate footer or nest it inside a sectioning element.",
|
|
1453
1759
|
run(t) {
|
|
1454
|
-
const a = [], e = t.querySelectorAll('footer, [role="contentinfo"]'), i = Array.from(e).filter((
|
|
1760
|
+
const a = [], e = t.querySelectorAll('footer, [role="contentinfo"]'), i = Array.from(e).filter((n) => !n.closest(L));
|
|
1455
1761
|
return i.length > 1 && i.slice(1).forEach(
|
|
1456
|
-
(
|
|
1762
|
+
(n) => a.push({
|
|
1457
1763
|
ruleId: "landmark-no-duplicate-contentinfo",
|
|
1458
|
-
selector: c(
|
|
1459
|
-
html: l(
|
|
1764
|
+
selector: c(n),
|
|
1765
|
+
html: l(n),
|
|
1460
1766
|
impact: "moderate",
|
|
1461
1767
|
message: "Page has multiple contentinfo landmarks."
|
|
1462
1768
|
})
|
|
1463
1769
|
), a;
|
|
1464
1770
|
}
|
|
1465
|
-
},
|
|
1771
|
+
}, pt = {
|
|
1466
1772
|
id: "landmark-no-duplicate-main",
|
|
1467
1773
|
wcag: [],
|
|
1468
1774
|
level: "A",
|
|
@@ -1482,7 +1788,7 @@ const We = {
|
|
|
1482
1788
|
})
|
|
1483
1789
|
), a;
|
|
1484
1790
|
}
|
|
1485
|
-
},
|
|
1791
|
+
}, ht = {
|
|
1486
1792
|
id: "landmark-banner-is-top-level",
|
|
1487
1793
|
wcag: [],
|
|
1488
1794
|
level: "A",
|
|
@@ -1493,7 +1799,7 @@ const We = {
|
|
|
1493
1799
|
run(t) {
|
|
1494
1800
|
const a = [], e = t.querySelectorAll('[role="banner"]');
|
|
1495
1801
|
for (const i of e)
|
|
1496
|
-
i.closest(
|
|
1802
|
+
i.closest(L) && a.push({
|
|
1497
1803
|
ruleId: "landmark-banner-is-top-level",
|
|
1498
1804
|
selector: c(i),
|
|
1499
1805
|
html: l(i),
|
|
@@ -1502,7 +1808,7 @@ const We = {
|
|
|
1502
1808
|
});
|
|
1503
1809
|
return a;
|
|
1504
1810
|
}
|
|
1505
|
-
},
|
|
1811
|
+
}, gt = {
|
|
1506
1812
|
id: "landmark-contentinfo-is-top-level",
|
|
1507
1813
|
wcag: [],
|
|
1508
1814
|
level: "A",
|
|
@@ -1513,7 +1819,7 @@ const We = {
|
|
|
1513
1819
|
run(t) {
|
|
1514
1820
|
const a = [], e = t.querySelectorAll('[role="contentinfo"]');
|
|
1515
1821
|
for (const i of e)
|
|
1516
|
-
i.closest(
|
|
1822
|
+
i.closest(L) && a.push({
|
|
1517
1823
|
ruleId: "landmark-contentinfo-is-top-level",
|
|
1518
1824
|
selector: c(i),
|
|
1519
1825
|
html: l(i),
|
|
@@ -1522,7 +1828,7 @@ const We = {
|
|
|
1522
1828
|
});
|
|
1523
1829
|
return a;
|
|
1524
1830
|
}
|
|
1525
|
-
},
|
|
1831
|
+
}, bt = {
|
|
1526
1832
|
id: "landmark-main-is-top-level",
|
|
1527
1833
|
wcag: [],
|
|
1528
1834
|
level: "A",
|
|
@@ -1533,8 +1839,8 @@ const We = {
|
|
|
1533
1839
|
run(t) {
|
|
1534
1840
|
const a = [], e = t.querySelectorAll('main, [role="main"]');
|
|
1535
1841
|
for (const i of e) {
|
|
1536
|
-
const
|
|
1537
|
-
|
|
1842
|
+
const n = i.parentElement;
|
|
1843
|
+
n != null && n.closest('article, aside, nav, section, [role="article"], [role="complementary"], [role="navigation"], [role="region"]') && a.push({
|
|
1538
1844
|
ruleId: "landmark-main-is-top-level",
|
|
1539
1845
|
selector: c(i),
|
|
1540
1846
|
html: l(i),
|
|
@@ -1544,7 +1850,7 @@ const We = {
|
|
|
1544
1850
|
}
|
|
1545
1851
|
return a;
|
|
1546
1852
|
}
|
|
1547
|
-
},
|
|
1853
|
+
}, ft = {
|
|
1548
1854
|
id: "landmark-complementary-is-top-level",
|
|
1549
1855
|
wcag: [],
|
|
1550
1856
|
level: "A",
|
|
@@ -1555,8 +1861,8 @@ const We = {
|
|
|
1555
1861
|
run(t) {
|
|
1556
1862
|
const a = [], e = t.querySelectorAll('aside, [role="complementary"]');
|
|
1557
1863
|
for (const i of e) {
|
|
1558
|
-
const
|
|
1559
|
-
|
|
1864
|
+
const n = i.parentElement;
|
|
1865
|
+
n && !n.matches('body, main, [role="main"]') && i.closest('article, nav, section, [role="article"], [role="navigation"], [role="region"]') && a.push({
|
|
1560
1866
|
ruleId: "landmark-complementary-is-top-level",
|
|
1561
1867
|
selector: c(i),
|
|
1562
1868
|
html: l(i),
|
|
@@ -1566,7 +1872,7 @@ const We = {
|
|
|
1566
1872
|
}
|
|
1567
1873
|
return a;
|
|
1568
1874
|
}
|
|
1569
|
-
},
|
|
1875
|
+
}, vt = {
|
|
1570
1876
|
id: "landmark-unique",
|
|
1571
1877
|
wcag: [],
|
|
1572
1878
|
level: "A",
|
|
@@ -1581,28 +1887,28 @@ const We = {
|
|
|
1581
1887
|
{ selector: 'section[aria-label], section[aria-labelledby], [role="region"]', type: "region" },
|
|
1582
1888
|
{ selector: 'form[aria-label], form[aria-labelledby], [role="form"], [role="search"]', type: "form" }
|
|
1583
1889
|
];
|
|
1584
|
-
for (const { selector: i, type:
|
|
1585
|
-
const
|
|
1586
|
-
if (
|
|
1890
|
+
for (const { selector: i, type: n } of e) {
|
|
1891
|
+
const r = Array.from(t.querySelectorAll(i)).filter((s) => !m(s));
|
|
1892
|
+
if (r.length <= 1) continue;
|
|
1587
1893
|
const o = /* @__PURE__ */ new Map();
|
|
1588
|
-
for (const s of
|
|
1589
|
-
const
|
|
1590
|
-
h.push(s), o.set(
|
|
1894
|
+
for (const s of r) {
|
|
1895
|
+
const u = b(s).toLowerCase() || "", h = o.get(u) || [];
|
|
1896
|
+
h.push(s), o.set(u, h);
|
|
1591
1897
|
}
|
|
1592
|
-
for (const [s,
|
|
1593
|
-
if (
|
|
1594
|
-
for (const h of
|
|
1898
|
+
for (const [s, u] of o)
|
|
1899
|
+
if (u.length > 1)
|
|
1900
|
+
for (const h of u.slice(1))
|
|
1595
1901
|
a.push({
|
|
1596
1902
|
ruleId: "landmark-unique",
|
|
1597
1903
|
selector: c(h),
|
|
1598
1904
|
html: l(h),
|
|
1599
1905
|
impact: "moderate",
|
|
1600
|
-
message: s ? `Multiple ${
|
|
1906
|
+
message: s ? `Multiple ${n} landmarks have the same label "${s}".` : `Multiple ${n} landmarks have no label. Add unique aria-label attributes.`
|
|
1601
1907
|
});
|
|
1602
1908
|
}
|
|
1603
1909
|
return a;
|
|
1604
1910
|
}
|
|
1605
|
-
},
|
|
1911
|
+
}, yt = {
|
|
1606
1912
|
id: "region",
|
|
1607
1913
|
wcag: [],
|
|
1608
1914
|
level: "A",
|
|
@@ -1614,45 +1920,31 @@ const We = {
|
|
|
1614
1920
|
var i;
|
|
1615
1921
|
const a = [], e = t.body;
|
|
1616
1922
|
if (!e) return [];
|
|
1617
|
-
for (const
|
|
1618
|
-
if (
|
|
1619
|
-
const
|
|
1620
|
-
!
|
|
1923
|
+
for (const n of e.children) {
|
|
1924
|
+
if (m(n) || n instanceof HTMLScriptElement || n instanceof HTMLStyleElement || n.tagName === "NOSCRIPT" || n instanceof HTMLElement && n.hidden || n.matches('a[href^="#"]')) continue;
|
|
1925
|
+
const r = n.matches(G), o = (i = n.textContent) == null ? void 0 : i.trim();
|
|
1926
|
+
!r && o && (n.querySelector(G) || a.push({
|
|
1621
1927
|
ruleId: "region",
|
|
1622
|
-
selector: c(
|
|
1623
|
-
html: l(
|
|
1928
|
+
selector: c(n),
|
|
1929
|
+
html: l(n),
|
|
1624
1930
|
impact: "moderate",
|
|
1625
1931
|
message: "Content is not contained within a landmark region."
|
|
1626
1932
|
}));
|
|
1627
1933
|
}
|
|
1628
1934
|
return a;
|
|
1629
1935
|
}
|
|
1630
|
-
},
|
|
1936
|
+
}, wt = {
|
|
1631
1937
|
id: "list",
|
|
1938
|
+
selector: "ul, ol",
|
|
1939
|
+
check: { type: "child-invalid", allowedChildren: ["li", "script", "template"] },
|
|
1940
|
+
impact: "serious",
|
|
1941
|
+
message: "List contains non-<li> child <{{tag}}>.",
|
|
1942
|
+
description: "<ul> and <ol> must only contain <li>, <script>, or <template> as direct children.",
|
|
1632
1943
|
wcag: ["1.3.1"],
|
|
1633
1944
|
level: "A",
|
|
1634
|
-
description: "<ul> and <ol> must only contain <li>, <script>, or <template> as direct children.",
|
|
1635
1945
|
guidance: "Screen readers announce list structure ('list with 5 items') based on proper markup. Placing non-<li> elements directly inside <ul> or <ol> breaks this structure. Wrap content in <li> elements, or if you need wrapper divs for styling, restructure your CSS to style the <li> elements directly.",
|
|
1636
|
-
prompt: "Explain how to restructure this element within the list properly."
|
|
1637
|
-
|
|
1638
|
-
const a = [];
|
|
1639
|
-
for (const e of t.querySelectorAll("ul, ol"))
|
|
1640
|
-
for (const i of e.children) {
|
|
1641
|
-
const r = i.tagName.toLowerCase();
|
|
1642
|
-
if (r !== "li" && r !== "script" && r !== "template") {
|
|
1643
|
-
a.push({
|
|
1644
|
-
ruleId: "list",
|
|
1645
|
-
selector: c(i),
|
|
1646
|
-
html: l(i),
|
|
1647
|
-
impact: "serious",
|
|
1648
|
-
message: `<${e.tagName.toLowerCase()}> contains non-<li> child <${r}>.`
|
|
1649
|
-
});
|
|
1650
|
-
break;
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
return a;
|
|
1654
|
-
}
|
|
1655
|
-
}, et = {
|
|
1946
|
+
prompt: "Explain how to restructure this element within the list properly."
|
|
1947
|
+
}, At = x(wt), St = {
|
|
1656
1948
|
id: "dlitem",
|
|
1657
1949
|
wcag: ["1.3.1"],
|
|
1658
1950
|
level: "A",
|
|
@@ -1671,30 +1963,18 @@ const We = {
|
|
|
1671
1963
|
});
|
|
1672
1964
|
return a;
|
|
1673
1965
|
}
|
|
1674
|
-
},
|
|
1966
|
+
}, xt = {
|
|
1675
1967
|
id: "definition-list",
|
|
1968
|
+
selector: "dl",
|
|
1969
|
+
check: { type: "child-invalid", allowedChildren: ["dt", "dd", "div", "script", "template"] },
|
|
1970
|
+
impact: "serious",
|
|
1971
|
+
message: "<dl> contains invalid child <{{tag}}>.",
|
|
1972
|
+
description: "<dl> elements must only contain <dt>, <dd>, <div>, <script>, or <template>.",
|
|
1676
1973
|
wcag: ["1.3.1"],
|
|
1677
1974
|
level: "A",
|
|
1678
|
-
description: "<dl> elements must only contain <dt>, <dd>, <div>, <script>, or <template>.",
|
|
1679
1975
|
guidance: "Definition lists have strict content requirements. Only <dt> (terms), <dd> (definitions), and <div> (for grouping dt/dd pairs) are valid children. Other elements break the list structure for screen readers. Move invalid elements outside the <dl>, or restructure using proper definition list markup.",
|
|
1680
|
-
prompt: "Explain whether to move this element outside the <dl> or convert it to dt/dd."
|
|
1681
|
-
|
|
1682
|
-
const a = [], e = /* @__PURE__ */ new Set(["dt", "dd", "div", "script", "template"]);
|
|
1683
|
-
for (const i of t.querySelectorAll("dl"))
|
|
1684
|
-
for (const r of i.children)
|
|
1685
|
-
if (!e.has(r.tagName.toLowerCase())) {
|
|
1686
|
-
a.push({
|
|
1687
|
-
ruleId: "definition-list",
|
|
1688
|
-
selector: c(r),
|
|
1689
|
-
html: l(r),
|
|
1690
|
-
impact: "serious",
|
|
1691
|
-
message: `<dl> contains invalid child <${r.tagName.toLowerCase()}>.`
|
|
1692
|
-
});
|
|
1693
|
-
break;
|
|
1694
|
-
}
|
|
1695
|
-
return a;
|
|
1696
|
-
}
|
|
1697
|
-
}, at = {
|
|
1976
|
+
prompt: "Explain whether to move this element outside the <dl> or convert it to dt/dd."
|
|
1977
|
+
}, kt = x(xt), It = {
|
|
1698
1978
|
id: "document-title",
|
|
1699
1979
|
wcag: ["2.4.2"],
|
|
1700
1980
|
level: "A",
|
|
@@ -1712,7 +1992,7 @@ const We = {
|
|
|
1712
1992
|
message: a ? "Document <title> element is empty." : "Document is missing a <title> element."
|
|
1713
1993
|
}] : [];
|
|
1714
1994
|
}
|
|
1715
|
-
},
|
|
1995
|
+
}, qt = {
|
|
1716
1996
|
id: "bypass",
|
|
1717
1997
|
wcag: ["2.4.1"],
|
|
1718
1998
|
level: "A",
|
|
@@ -1725,10 +2005,10 @@ const We = {
|
|
|
1725
2005
|
)) return [];
|
|
1726
2006
|
const e = t.querySelector('a[href^="#"]');
|
|
1727
2007
|
if (e) {
|
|
1728
|
-
const
|
|
1729
|
-
if (
|
|
1730
|
-
const
|
|
1731
|
-
if (t.getElementById(
|
|
2008
|
+
const n = e.getAttribute("href");
|
|
2009
|
+
if (n && n.length > 1) {
|
|
2010
|
+
const r = n.slice(1);
|
|
2011
|
+
if (t.getElementById(r)) return [];
|
|
1732
2012
|
}
|
|
1733
2013
|
}
|
|
1734
2014
|
return t.querySelector("h1, h2, h3, [role='heading']") ? [] : [{
|
|
@@ -1739,7 +2019,7 @@ const We = {
|
|
|
1739
2019
|
message: "Page has no mechanism to bypass repeated content. Add a <main> landmark or skip link."
|
|
1740
2020
|
}];
|
|
1741
2021
|
}
|
|
1742
|
-
},
|
|
2022
|
+
}, Ct = {
|
|
1743
2023
|
id: "page-has-heading-one",
|
|
1744
2024
|
wcag: [],
|
|
1745
2025
|
level: "A",
|
|
@@ -1749,10 +2029,10 @@ const We = {
|
|
|
1749
2029
|
prompt: "Suggest appropriate h1 text based on the page's visible content.",
|
|
1750
2030
|
run(t) {
|
|
1751
2031
|
const a = t.querySelector("h1");
|
|
1752
|
-
if (a &&
|
|
2032
|
+
if (a && b(a)) return [];
|
|
1753
2033
|
const e = t.querySelectorAll('[role="heading"][aria-level="1"]');
|
|
1754
2034
|
for (const i of e)
|
|
1755
|
-
if (
|
|
2035
|
+
if (b(i)) return [];
|
|
1756
2036
|
return [{
|
|
1757
2037
|
ruleId: "page-has-heading-one",
|
|
1758
2038
|
selector: "html",
|
|
@@ -1761,7 +2041,7 @@ const We = {
|
|
|
1761
2041
|
message: "Page does not contain a level-one heading."
|
|
1762
2042
|
}];
|
|
1763
2043
|
}
|
|
1764
|
-
},
|
|
2044
|
+
}, Tt = {
|
|
1765
2045
|
id: "frame-title",
|
|
1766
2046
|
wcag: ["4.1.2"],
|
|
1767
2047
|
level: "A",
|
|
@@ -1771,8 +2051,8 @@ const We = {
|
|
|
1771
2051
|
run(t) {
|
|
1772
2052
|
const a = [];
|
|
1773
2053
|
for (const e of t.querySelectorAll("iframe, frame")) {
|
|
1774
|
-
if (
|
|
1775
|
-
|
|
2054
|
+
if (m(e)) continue;
|
|
2055
|
+
b(e) || a.push({
|
|
1776
2056
|
ruleId: "frame-title",
|
|
1777
2057
|
selector: c(e),
|
|
1778
2058
|
html: l(e),
|
|
@@ -1782,7 +2062,7 @@ const We = {
|
|
|
1782
2062
|
}
|
|
1783
2063
|
return a;
|
|
1784
2064
|
}
|
|
1785
|
-
},
|
|
2065
|
+
}, Et = {
|
|
1786
2066
|
id: "frame-title-unique",
|
|
1787
2067
|
wcag: ["4.1.2"],
|
|
1788
2068
|
level: "A",
|
|
@@ -1791,21 +2071,21 @@ const We = {
|
|
|
1791
2071
|
guidance: "When multiple frames have identical titles, screen reader users cannot distinguish between them. Give each frame a unique, descriptive title that explains its specific purpose or content.",
|
|
1792
2072
|
prompt: "Suggest a more specific title to distinguish this frame from others.",
|
|
1793
2073
|
run(t) {
|
|
1794
|
-
var
|
|
2074
|
+
var n;
|
|
1795
2075
|
const a = [], e = Array.from(t.querySelectorAll("iframe[title], frame[title]")), i = /* @__PURE__ */ new Map();
|
|
1796
|
-
for (const
|
|
1797
|
-
if (
|
|
1798
|
-
const o =
|
|
1799
|
-
if (o === "0" || s === "0" ||
|
|
1800
|
-
const
|
|
1801
|
-
if (
|
|
1802
|
-
const h = i.get(
|
|
1803
|
-
h.push(
|
|
2076
|
+
for (const r of e) {
|
|
2077
|
+
if (m(r)) continue;
|
|
2078
|
+
const o = r.getAttribute("width"), s = r.getAttribute("height");
|
|
2079
|
+
if (o === "0" || s === "0" || r instanceof HTMLElement && r.style.display === "none" || r instanceof HTMLElement && r.style.visibility === "hidden") continue;
|
|
2080
|
+
const u = (n = r.getAttribute("title")) == null ? void 0 : n.trim().toLowerCase();
|
|
2081
|
+
if (u) {
|
|
2082
|
+
const h = i.get(u) || [];
|
|
2083
|
+
h.push(r), i.set(u, h);
|
|
1804
2084
|
}
|
|
1805
2085
|
}
|
|
1806
|
-
for (const [,
|
|
1807
|
-
if (
|
|
1808
|
-
for (const o of
|
|
2086
|
+
for (const [, r] of i)
|
|
2087
|
+
if (r.length > 1)
|
|
2088
|
+
for (const o of r.slice(1))
|
|
1809
2089
|
a.push({
|
|
1810
2090
|
ruleId: "frame-title-unique",
|
|
1811
2091
|
selector: c(o),
|
|
@@ -1815,7 +2095,7 @@ const We = {
|
|
|
1815
2095
|
});
|
|
1816
2096
|
return a;
|
|
1817
2097
|
}
|
|
1818
|
-
},
|
|
2098
|
+
}, Lt = {
|
|
1819
2099
|
id: "empty-heading",
|
|
1820
2100
|
wcag: [],
|
|
1821
2101
|
level: "A",
|
|
@@ -1826,7 +2106,7 @@ const We = {
|
|
|
1826
2106
|
run(t) {
|
|
1827
2107
|
const a = [], e = t.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"]');
|
|
1828
2108
|
for (const i of e)
|
|
1829
|
-
|
|
2109
|
+
m(i) || b(i) || a.push({
|
|
1830
2110
|
ruleId: "empty-heading",
|
|
1831
2111
|
selector: c(i),
|
|
1832
2112
|
html: l(i),
|
|
@@ -1835,7 +2115,7 @@ const We = {
|
|
|
1835
2115
|
});
|
|
1836
2116
|
return a;
|
|
1837
2117
|
}
|
|
1838
|
-
},
|
|
2118
|
+
}, Rt = {
|
|
1839
2119
|
id: "meta-viewport",
|
|
1840
2120
|
wcag: ["1.4.4"],
|
|
1841
2121
|
level: "AA",
|
|
@@ -1843,10 +2123,10 @@ const We = {
|
|
|
1843
2123
|
guidance: "Users with low vision need to zoom content up to 200% or more. Setting user-scalable=no or maximum-scale=1 prevents zooming and fails WCAG. Remove these restrictions. If your layout breaks at high zoom, fix the responsive design rather than preventing zoom.",
|
|
1844
2124
|
prompt: "Explain which viewport restrictions to remove and show the corrected meta tag.",
|
|
1845
2125
|
run(t) {
|
|
1846
|
-
var
|
|
2126
|
+
var r;
|
|
1847
2127
|
const a = [], e = t.querySelector('meta[name="viewport"]');
|
|
1848
2128
|
if (!e) return [];
|
|
1849
|
-
const i = ((
|
|
2129
|
+
const i = ((r = e.getAttribute("content")) == null ? void 0 : r.toLowerCase()) || "";
|
|
1850
2130
|
(/user-scalable\s*=\s*no/i.test(i) || /user-scalable\s*=\s*0/i.test(i)) && a.push({
|
|
1851
2131
|
ruleId: "meta-viewport",
|
|
1852
2132
|
selector: c(e),
|
|
@@ -1854,9 +2134,9 @@ const We = {
|
|
|
1854
2134
|
impact: "critical",
|
|
1855
2135
|
message: "Viewport disables user scaling. Remove user-scalable=no."
|
|
1856
2136
|
});
|
|
1857
|
-
const
|
|
1858
|
-
if (
|
|
1859
|
-
const o = parseFloat(
|
|
2137
|
+
const n = i.match(/maximum-scale\s*=\s*([\d.]+)/i);
|
|
2138
|
+
if (n) {
|
|
2139
|
+
const o = parseFloat(n[1]);
|
|
1860
2140
|
o < 2 && a.push({
|
|
1861
2141
|
ruleId: "meta-viewport",
|
|
1862
2142
|
selector: c(e),
|
|
@@ -1867,7 +2147,7 @@ const We = {
|
|
|
1867
2147
|
}
|
|
1868
2148
|
return a;
|
|
1869
2149
|
}
|
|
1870
|
-
},
|
|
2150
|
+
}, Nt = {
|
|
1871
2151
|
id: "meta-refresh",
|
|
1872
2152
|
wcag: ["2.2.1", "2.2.4", "3.2.5"],
|
|
1873
2153
|
level: "A",
|
|
@@ -1877,10 +2157,10 @@ const We = {
|
|
|
1877
2157
|
run(t) {
|
|
1878
2158
|
const a = [], e = t.querySelector('meta[http-equiv="refresh"]');
|
|
1879
2159
|
if (!e) return [];
|
|
1880
|
-
const i = e.getAttribute("content") || "",
|
|
1881
|
-
if (
|
|
1882
|
-
const
|
|
1883
|
-
i.includes("url=") ?
|
|
2160
|
+
const i = e.getAttribute("content") || "", n = i.match(/^(\d+)/);
|
|
2161
|
+
if (n) {
|
|
2162
|
+
const r = parseInt(n[1], 10);
|
|
2163
|
+
i.includes("url=") ? r <= 0 ? a.push({
|
|
1884
2164
|
ruleId: "meta-refresh",
|
|
1885
2165
|
selector: c(e),
|
|
1886
2166
|
html: l(e),
|
|
@@ -1891,56 +2171,40 @@ const We = {
|
|
|
1891
2171
|
selector: c(e),
|
|
1892
2172
|
html: l(e),
|
|
1893
2173
|
impact: "critical",
|
|
1894
|
-
message: `Page redirects after ${
|
|
1895
|
-
}) :
|
|
2174
|
+
message: `Page redirects after ${r} seconds without warning. Use server-side redirect.`
|
|
2175
|
+
}) : r > 0 && r <= 72e3 && a.push({
|
|
1896
2176
|
ruleId: "meta-refresh",
|
|
1897
2177
|
selector: c(e),
|
|
1898
2178
|
html: l(e),
|
|
1899
2179
|
impact: "critical",
|
|
1900
|
-
message: `Page auto-refreshes after ${
|
|
2180
|
+
message: `Page auto-refreshes after ${r} seconds. Provide user control over refresh.`
|
|
1901
2181
|
});
|
|
1902
2182
|
}
|
|
1903
2183
|
return a;
|
|
1904
2184
|
}
|
|
1905
|
-
},
|
|
2185
|
+
}, Mt = {
|
|
1906
2186
|
id: "blink",
|
|
2187
|
+
selector: "blink",
|
|
2188
|
+
check: { type: "selector-exists" },
|
|
2189
|
+
impact: "serious",
|
|
2190
|
+
message: "The <blink> element causes accessibility issues. Remove it entirely.",
|
|
2191
|
+
description: "The <blink> element must not be used.",
|
|
1907
2192
|
wcag: ["2.2.2"],
|
|
1908
2193
|
level: "A",
|
|
1909
|
-
description: "The <blink> element must not be used.",
|
|
1910
2194
|
guidance: "Blinking content can cause seizures in users with photosensitive epilepsy and is distracting for users with attention disorders. The <blink> element is deprecated and should never be used. If you need to draw attention to content, use less intrusive methods like color, borders, or icons.",
|
|
1911
|
-
prompt: "Suggest static alternatives to the blinking effect."
|
|
1912
|
-
|
|
1913
|
-
const a = [];
|
|
1914
|
-
for (const e of t.querySelectorAll("blink"))
|
|
1915
|
-
u(e) || a.push({
|
|
1916
|
-
ruleId: "blink",
|
|
1917
|
-
selector: c(e),
|
|
1918
|
-
html: l(e),
|
|
1919
|
-
impact: "serious",
|
|
1920
|
-
message: "The <blink> element causes accessibility issues. Remove it entirely."
|
|
1921
|
-
});
|
|
1922
|
-
return a;
|
|
1923
|
-
}
|
|
1924
|
-
}, ut = {
|
|
2195
|
+
prompt: "Suggest static alternatives to the blinking effect."
|
|
2196
|
+
}, $t = x(Mt), Ht = {
|
|
1925
2197
|
id: "marquee",
|
|
2198
|
+
selector: "marquee",
|
|
2199
|
+
check: { type: "selector-exists" },
|
|
2200
|
+
impact: "serious",
|
|
2201
|
+
message: "The <marquee> element causes accessibility issues. Replace with static content.",
|
|
2202
|
+
description: "The <marquee> element must not be used.",
|
|
1926
2203
|
wcag: ["2.2.2"],
|
|
1927
2204
|
level: "A",
|
|
1928
|
-
description: "The <marquee> element must not be used.",
|
|
1929
2205
|
guidance: "Scrolling or moving content is difficult for many users to read, especially those with cognitive or visual disabilities. The <marquee> element is deprecated. Replace scrolling text with static content. If content must scroll, provide pause/stop controls and ensure it stops after 5 seconds.",
|
|
1930
|
-
prompt: "Suggest static alternatives or accessible carousel patterns."
|
|
1931
|
-
|
|
1932
|
-
const a = [];
|
|
1933
|
-
for (const e of t.querySelectorAll("marquee"))
|
|
1934
|
-
u(e) || a.push({
|
|
1935
|
-
ruleId: "marquee",
|
|
1936
|
-
selector: c(e),
|
|
1937
|
-
html: l(e),
|
|
1938
|
-
impact: "serious",
|
|
1939
|
-
message: "The <marquee> element causes accessibility issues. Replace with static content."
|
|
1940
|
-
});
|
|
1941
|
-
return a;
|
|
1942
|
-
}
|
|
1943
|
-
}, mt = {
|
|
2206
|
+
prompt: "Suggest static alternatives or accessible carousel patterns."
|
|
2207
|
+
}, Dt = x(Ht), Bt = {
|
|
1944
2208
|
id: "p-as-heading",
|
|
1945
2209
|
wcag: [],
|
|
1946
2210
|
level: "A",
|
|
@@ -1951,15 +2215,15 @@ const We = {
|
|
|
1951
2215
|
run(t) {
|
|
1952
2216
|
var e, i;
|
|
1953
2217
|
const a = [];
|
|
1954
|
-
for (const
|
|
1955
|
-
if (
|
|
1956
|
-
const
|
|
1957
|
-
if ((o && s || o && h) && p &&
|
|
1958
|
-
const y =
|
|
2218
|
+
for (const n of t.querySelectorAll("p")) {
|
|
2219
|
+
if (m(n)) continue;
|
|
2220
|
+
const r = n.getAttribute("style") || "", o = /font-weight\s*:\s*(bold|[6-9]00)/i.test(r), s = /font-size\s*:\s*(\d+)\s*(px|em|rem)/i.test(r), u = ((e = n.className) == null ? void 0 : e.toLowerCase()) || "", h = /\bh[1-6]\b|\bheading\b/.test(u), d = ((i = n.textContent) == null ? void 0 : i.trim()) || "", p = d.length > 0 && d.length < 50, g = !d.match(/[.!?,;:]$/);
|
|
2221
|
+
if ((o && s || o && h) && p && g) {
|
|
2222
|
+
const y = n.nextElementSibling;
|
|
1959
2223
|
y && (y.tagName === "P" || y.tagName === "DIV" || y.tagName === "UL") && a.push({
|
|
1960
2224
|
ruleId: "p-as-heading",
|
|
1961
|
-
selector: c(
|
|
1962
|
-
html: l(
|
|
2225
|
+
selector: c(n),
|
|
2226
|
+
html: l(n),
|
|
1963
2227
|
impact: "serious",
|
|
1964
2228
|
message: "Paragraph appears to be styled as a heading. Use an h1-h6 element instead."
|
|
1965
2229
|
});
|
|
@@ -1967,7 +2231,7 @@ const We = {
|
|
|
1967
2231
|
}
|
|
1968
2232
|
return a;
|
|
1969
2233
|
}
|
|
1970
|
-
},
|
|
2234
|
+
}, Ot = {
|
|
1971
2235
|
id: "aria-roles",
|
|
1972
2236
|
wcag: ["4.1.2"],
|
|
1973
2237
|
level: "A",
|
|
@@ -1977,9 +2241,9 @@ const We = {
|
|
|
1977
2241
|
run(t) {
|
|
1978
2242
|
const a = [];
|
|
1979
2243
|
for (const e of t.querySelectorAll("[role]")) {
|
|
1980
|
-
const
|
|
1981
|
-
for (const o of
|
|
1982
|
-
if (o && !
|
|
2244
|
+
const r = e.getAttribute("role").replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "").split(/\s+/);
|
|
2245
|
+
for (const o of r)
|
|
2246
|
+
if (o && !me(o)) {
|
|
1983
2247
|
a.push({
|
|
1984
2248
|
ruleId: "aria-roles",
|
|
1985
2249
|
selector: c(e),
|
|
@@ -1992,7 +2256,7 @@ const We = {
|
|
|
1992
2256
|
}
|
|
1993
2257
|
return a;
|
|
1994
2258
|
}
|
|
1995
|
-
},
|
|
2259
|
+
}, Wt = {
|
|
1996
2260
|
id: "aria-valid-attr",
|
|
1997
2261
|
wcag: ["4.1.2"],
|
|
1998
2262
|
level: "A",
|
|
@@ -2000,9 +2264,9 @@ const We = {
|
|
|
2000
2264
|
guidance: "Misspelled ARIA attributes are ignored by assistive technologies. Check the spelling against the WAI-ARIA specification. Common mistakes: aria-labeledby (should be aria-labelledby), aria-role (should be role), aria-description (valid in ARIA 1.3+).",
|
|
2001
2265
|
prompt: "Identify the misspelled attribute and provide the correct spelling.",
|
|
2002
2266
|
run(t) {
|
|
2003
|
-
return
|
|
2267
|
+
return _(t).validAttr;
|
|
2004
2268
|
}
|
|
2005
|
-
},
|
|
2269
|
+
}, _t = {
|
|
2006
2270
|
id: "aria-valid-attr-value",
|
|
2007
2271
|
wcag: ["4.1.2"],
|
|
2008
2272
|
level: "A",
|
|
@@ -2010,9 +2274,9 @@ const We = {
|
|
|
2010
2274
|
guidance: "Each ARIA attribute accepts specific value types. Boolean attributes (aria-hidden, aria-disabled) accept only 'true' or 'false'. Tristate attributes (aria-checked, aria-pressed) also accept 'mixed'. Token attributes (aria-live, aria-autocomplete) accept predefined values. ID reference attributes (aria-labelledby, aria-describedby) must reference existing element IDs.",
|
|
2011
2275
|
prompt: "Show the invalid value and list the valid values for this specific attribute.",
|
|
2012
2276
|
run(t) {
|
|
2013
|
-
return
|
|
2277
|
+
return _(t).validAttrValue;
|
|
2014
2278
|
}
|
|
2015
|
-
},
|
|
2279
|
+
}, Ft = {
|
|
2016
2280
|
checkbox: ["aria-checked"],
|
|
2017
2281
|
combobox: ["aria-expanded"],
|
|
2018
2282
|
heading: ["aria-level"],
|
|
@@ -2027,7 +2291,7 @@ const We = {
|
|
|
2027
2291
|
slider: ["aria-valuenow"],
|
|
2028
2292
|
spinbutton: ["aria-valuenow"],
|
|
2029
2293
|
switch: ["aria-checked"]
|
|
2030
|
-
},
|
|
2294
|
+
}, Pt = {
|
|
2031
2295
|
id: "aria-required-attr",
|
|
2032
2296
|
wcag: ["4.1.2"],
|
|
2033
2297
|
level: "A",
|
|
@@ -2037,21 +2301,21 @@ const We = {
|
|
|
2037
2301
|
run(t) {
|
|
2038
2302
|
const a = [];
|
|
2039
2303
|
for (const e of t.querySelectorAll("[role]")) {
|
|
2040
|
-
const i = e.getAttribute("role").trim().toLowerCase(),
|
|
2041
|
-
if (
|
|
2304
|
+
const i = e.getAttribute("role").trim().toLowerCase(), n = Ft[i];
|
|
2305
|
+
if (n && !(i === "checkbox" && e instanceof HTMLInputElement && e.type === "checkbox") && !(i === "radio" && e instanceof HTMLInputElement && e.type === "radio") && !(i === "option" && e instanceof HTMLOptionElement) && !(i === "heading" && /^h[1-6]$/i.test(e.tagName))) {
|
|
2042
2306
|
if (i === "separator") {
|
|
2043
|
-
const
|
|
2044
|
-
if (!
|
|
2307
|
+
const r = e.getAttribute("tabindex");
|
|
2308
|
+
if (!r || r === "-1") continue;
|
|
2045
2309
|
}
|
|
2046
2310
|
if (!(e.tagName.toLowerCase() === "hr" && !e.hasAttribute("role"))) {
|
|
2047
|
-
for (const
|
|
2048
|
-
if (!e.hasAttribute(
|
|
2311
|
+
for (const r of n)
|
|
2312
|
+
if (!e.hasAttribute(r)) {
|
|
2049
2313
|
a.push({
|
|
2050
2314
|
ruleId: "aria-required-attr",
|
|
2051
2315
|
selector: c(e),
|
|
2052
2316
|
html: l(e),
|
|
2053
2317
|
impact: "critical",
|
|
2054
|
-
message: `Role "${i}" requires attribute "${
|
|
2318
|
+
message: `Role "${i}" requires attribute "${r}".`
|
|
2055
2319
|
});
|
|
2056
2320
|
break;
|
|
2057
2321
|
}
|
|
@@ -2061,24 +2325,24 @@ const We = {
|
|
|
2061
2325
|
return a;
|
|
2062
2326
|
}
|
|
2063
2327
|
};
|
|
2064
|
-
function
|
|
2065
|
-
var
|
|
2328
|
+
function Vt(t) {
|
|
2329
|
+
var r, o, s;
|
|
2066
2330
|
const a = [], e = t.className;
|
|
2067
2331
|
e && typeof e == "string" && e.trim() && a.push(`Classes: ${e.trim().slice(0, 100)}`);
|
|
2068
2332
|
const i = t.closest("form");
|
|
2069
2333
|
if (i) {
|
|
2070
|
-
const
|
|
2071
|
-
|
|
2334
|
+
const u = i.getAttribute("aria-label") || ((o = (r = i.querySelector("legend")) == null ? void 0 : r.textContent) == null ? void 0 : o.trim());
|
|
2335
|
+
u && a.push(`Form: ${u.slice(0, 60)}`);
|
|
2072
2336
|
}
|
|
2073
|
-
const
|
|
2074
|
-
if (
|
|
2075
|
-
const
|
|
2076
|
-
(s =
|
|
2337
|
+
const n = t.parentElement;
|
|
2338
|
+
if (n) {
|
|
2339
|
+
const u = n.closest("h1, h2, h3, h4, h5, h6") || n.querySelector("h1, h2, h3, h4, h5, h6");
|
|
2340
|
+
(s = u == null ? void 0 : u.textContent) != null && s.trim() && a.push(`Nearby heading: ${u.textContent.trim().slice(0, 60)}`);
|
|
2077
2341
|
}
|
|
2078
2342
|
return a.length > 0 ? a.join(`
|
|
2079
2343
|
`) : void 0;
|
|
2080
2344
|
}
|
|
2081
|
-
const
|
|
2345
|
+
const Ut = {
|
|
2082
2346
|
id: "button-name",
|
|
2083
2347
|
wcag: ["4.1.2"],
|
|
2084
2348
|
level: "A",
|
|
@@ -2088,19 +2352,19 @@ const yt = {
|
|
|
2088
2352
|
run(t) {
|
|
2089
2353
|
const a = [];
|
|
2090
2354
|
for (const e of t.querySelectorAll('button, [role="button"]')) {
|
|
2091
|
-
if (
|
|
2092
|
-
|
|
2355
|
+
if (m(e) || e.getRootNode() instanceof ShadowRoot) continue;
|
|
2356
|
+
b(e) || a.push({
|
|
2093
2357
|
ruleId: "button-name",
|
|
2094
2358
|
selector: c(e),
|
|
2095
2359
|
html: l(e),
|
|
2096
2360
|
impact: "critical",
|
|
2097
2361
|
message: "Button has no discernible text.",
|
|
2098
|
-
context:
|
|
2362
|
+
context: Vt(e)
|
|
2099
2363
|
});
|
|
2100
2364
|
}
|
|
2101
2365
|
return a;
|
|
2102
2366
|
}
|
|
2103
|
-
},
|
|
2367
|
+
}, jt = {
|
|
2104
2368
|
alert: /* @__PURE__ */ new Set(["aria-atomic", "aria-busy", "aria-live", "aria-relevant"]),
|
|
2105
2369
|
alertdialog: /* @__PURE__ */ new Set(["aria-describedby", "aria-modal"]),
|
|
2106
2370
|
application: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-disabled", "aria-errormessage", "aria-expanded", "aria-haspopup", "aria-invalid"]),
|
|
@@ -2172,7 +2436,7 @@ const yt = {
|
|
|
2172
2436
|
tree: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-disabled", "aria-errormessage", "aria-invalid", "aria-multiselectable", "aria-orientation", "aria-required"]),
|
|
2173
2437
|
treegrid: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-colcount", "aria-disabled", "aria-errormessage", "aria-invalid", "aria-multiselectable", "aria-orientation", "aria-readonly", "aria-required", "aria-rowcount"]),
|
|
2174
2438
|
treeitem: /* @__PURE__ */ new Set(["aria-checked", "aria-disabled", "aria-expanded", "aria-haspopup", "aria-level", "aria-posinset", "aria-selected", "aria-setsize"])
|
|
2175
|
-
},
|
|
2439
|
+
}, zt = /* @__PURE__ */ new Set([
|
|
2176
2440
|
"aria-atomic",
|
|
2177
2441
|
"aria-busy",
|
|
2178
2442
|
"aria-controls",
|
|
@@ -2196,7 +2460,7 @@ const yt = {
|
|
|
2196
2460
|
"aria-roledescription",
|
|
2197
2461
|
"aria-braillelabel",
|
|
2198
2462
|
"aria-brailleroledescription"
|
|
2199
|
-
]),
|
|
2463
|
+
]), Gt = {
|
|
2200
2464
|
id: "aria-allowed-attr",
|
|
2201
2465
|
wcag: ["4.1.2"],
|
|
2202
2466
|
level: "A",
|
|
@@ -2206,23 +2470,23 @@ const yt = {
|
|
|
2206
2470
|
run(t) {
|
|
2207
2471
|
const a = [];
|
|
2208
2472
|
for (const e of t.querySelectorAll("[role], [aria-*]")) {
|
|
2209
|
-
if (
|
|
2210
|
-
const i =
|
|
2473
|
+
if (m(e)) continue;
|
|
2474
|
+
const i = E(e);
|
|
2211
2475
|
if (!i) continue;
|
|
2212
|
-
const
|
|
2213
|
-
if (
|
|
2214
|
-
for (const
|
|
2215
|
-
|
|
2476
|
+
const n = jt[i];
|
|
2477
|
+
if (n)
|
|
2478
|
+
for (const r of e.attributes)
|
|
2479
|
+
r.name.startsWith("aria-") && (zt.has(r.name) || n.has(r.name) || a.push({
|
|
2216
2480
|
ruleId: "aria-allowed-attr",
|
|
2217
2481
|
selector: c(e),
|
|
2218
2482
|
html: l(e),
|
|
2219
2483
|
impact: "critical",
|
|
2220
|
-
message: `ARIA attribute "${
|
|
2484
|
+
message: `ARIA attribute "${r.name}" is not allowed on role "${i}".`
|
|
2221
2485
|
}));
|
|
2222
2486
|
}
|
|
2223
2487
|
return a;
|
|
2224
2488
|
}
|
|
2225
|
-
},
|
|
2489
|
+
}, Xt = /* @__PURE__ */ new Set([
|
|
2226
2490
|
"base",
|
|
2227
2491
|
"col",
|
|
2228
2492
|
"colgroup",
|
|
@@ -2237,7 +2501,7 @@ const yt = {
|
|
|
2237
2501
|
"template",
|
|
2238
2502
|
"title",
|
|
2239
2503
|
"track"
|
|
2240
|
-
]),
|
|
2504
|
+
]), k = {
|
|
2241
2505
|
a: /* @__PURE__ */ new Set(["button", "checkbox", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "switch", "tab", "treeitem", "link"]),
|
|
2242
2506
|
"a[href]": /* @__PURE__ */ new Set(["button", "checkbox", "menuitem", "menuitemcheckbox", "menuitemradio", "option", "radio", "switch", "tab", "treeitem"]),
|
|
2243
2507
|
abbr: "any",
|
|
@@ -2344,22 +2608,22 @@ const yt = {
|
|
|
2344
2608
|
video: /* @__PURE__ */ new Set(["application"]),
|
|
2345
2609
|
wbr: /* @__PURE__ */ new Set(["none", "presentation"])
|
|
2346
2610
|
};
|
|
2347
|
-
function
|
|
2611
|
+
function Kt(t) {
|
|
2348
2612
|
var e;
|
|
2349
2613
|
const a = t.tagName.toLowerCase();
|
|
2350
|
-
if (
|
|
2614
|
+
if (Xt.has(a))
|
|
2351
2615
|
return "none";
|
|
2352
2616
|
if (a === "a" && t.hasAttribute("href"))
|
|
2353
|
-
return
|
|
2617
|
+
return k["a[href]"];
|
|
2354
2618
|
if (a === "img" && t.getAttribute("alt") === "")
|
|
2355
|
-
return
|
|
2619
|
+
return k["img[alt='']"];
|
|
2356
2620
|
if (a === "input") {
|
|
2357
|
-
const
|
|
2358
|
-
return
|
|
2621
|
+
const n = `input[type=${((e = t.getAttribute("type")) == null ? void 0 : e.toLowerCase()) || "text"}]`;
|
|
2622
|
+
return n in k ? k[n] : "none";
|
|
2359
2623
|
}
|
|
2360
|
-
return
|
|
2624
|
+
return k[a] || "any";
|
|
2361
2625
|
}
|
|
2362
|
-
const
|
|
2626
|
+
const Yt = {
|
|
2363
2627
|
id: "aria-allowed-role",
|
|
2364
2628
|
wcag: ["4.1.2"],
|
|
2365
2629
|
level: "A",
|
|
@@ -2370,29 +2634,29 @@ const It = {
|
|
|
2370
2634
|
var e;
|
|
2371
2635
|
const a = [];
|
|
2372
2636
|
for (const i of t.querySelectorAll("[role]")) {
|
|
2373
|
-
if (
|
|
2374
|
-
const
|
|
2375
|
-
if (!
|
|
2376
|
-
const
|
|
2377
|
-
if (
|
|
2378
|
-
const o =
|
|
2637
|
+
if (m(i)) continue;
|
|
2638
|
+
const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
|
|
2639
|
+
if (!n) continue;
|
|
2640
|
+
const r = J(i);
|
|
2641
|
+
if (r && n === r) continue;
|
|
2642
|
+
const o = Kt(i);
|
|
2379
2643
|
o === "none" ? a.push({
|
|
2380
2644
|
ruleId: "aria-allowed-role",
|
|
2381
2645
|
selector: c(i),
|
|
2382
2646
|
html: l(i),
|
|
2383
2647
|
impact: "minor",
|
|
2384
2648
|
message: `Element <${i.tagName.toLowerCase()}> should not have an explicit role.`
|
|
2385
|
-
}) : o !== "any" && !o.has(
|
|
2649
|
+
}) : o !== "any" && !o.has(n) && a.push({
|
|
2386
2650
|
ruleId: "aria-allowed-role",
|
|
2387
2651
|
selector: c(i),
|
|
2388
2652
|
html: l(i),
|
|
2389
2653
|
impact: "minor",
|
|
2390
|
-
message: `Role "${
|
|
2654
|
+
message: `Role "${n}" is not allowed on element <${i.tagName.toLowerCase()}>.`
|
|
2391
2655
|
});
|
|
2392
2656
|
}
|
|
2393
2657
|
return a;
|
|
2394
2658
|
}
|
|
2395
|
-
},
|
|
2659
|
+
}, X = {
|
|
2396
2660
|
// Each array is an OR group - at least one of each inner array must be present
|
|
2397
2661
|
combobox: [["listbox", "tree", "grid", "dialog", "textbox"]],
|
|
2398
2662
|
// Must own/contain one of these
|
|
@@ -2409,7 +2673,7 @@ const It = {
|
|
|
2409
2673
|
tablist: [["tab"]],
|
|
2410
2674
|
tree: [["treeitem", "group"]],
|
|
2411
2675
|
treegrid: [["row", "rowgroup"]]
|
|
2412
|
-
},
|
|
2676
|
+
}, K = {
|
|
2413
2677
|
caption: ["figure", "table", "grid", "treegrid"],
|
|
2414
2678
|
// cell/gridcell/columnheader/rowheader must be in a row
|
|
2415
2679
|
// but we skip checking native td/th since they're handled by HTML semantics
|
|
@@ -2423,25 +2687,25 @@ const It = {
|
|
|
2423
2687
|
tab: ["tablist"],
|
|
2424
2688
|
treeitem: ["tree", "group"]
|
|
2425
2689
|
};
|
|
2426
|
-
function
|
|
2427
|
-
var
|
|
2428
|
-
const e = ((
|
|
2690
|
+
function Qt(t, a) {
|
|
2691
|
+
var r;
|
|
2692
|
+
const e = ((r = t.getAttribute("aria-owns")) == null ? void 0 : r.split(/\s+/)) || [], i = t.ownerDocument, n = /* @__PURE__ */ new Set();
|
|
2429
2693
|
for (const o of t.querySelectorAll("*")) {
|
|
2430
|
-
const s =
|
|
2431
|
-
s && !
|
|
2694
|
+
const s = E(o);
|
|
2695
|
+
s && !m(o) && n.add(s);
|
|
2432
2696
|
}
|
|
2433
2697
|
for (const o of e) {
|
|
2434
2698
|
const s = i.getElementById(o);
|
|
2435
2699
|
if (s) {
|
|
2436
|
-
const
|
|
2437
|
-
|
|
2700
|
+
const u = E(s);
|
|
2701
|
+
u && !m(s) && n.add(u);
|
|
2438
2702
|
}
|
|
2439
2703
|
}
|
|
2440
2704
|
for (const o of a)
|
|
2441
|
-
if (!o.some((
|
|
2705
|
+
if (!o.some((u) => n.has(u))) return !1;
|
|
2442
2706
|
return !0;
|
|
2443
2707
|
}
|
|
2444
|
-
const
|
|
2708
|
+
const Jt = {
|
|
2445
2709
|
id: "aria-required-children",
|
|
2446
2710
|
wcag: ["4.1.2"],
|
|
2447
2711
|
level: "A",
|
|
@@ -2452,24 +2716,24 @@ const Ct = {
|
|
|
2452
2716
|
var e;
|
|
2453
2717
|
const a = [];
|
|
2454
2718
|
for (const i of t.querySelectorAll("[role]")) {
|
|
2455
|
-
if (
|
|
2456
|
-
const
|
|
2457
|
-
if (!
|
|
2458
|
-
const
|
|
2459
|
-
if (!
|
|
2460
|
-
const o =
|
|
2719
|
+
if (m(i)) continue;
|
|
2720
|
+
const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
|
|
2721
|
+
if (!n || !(n in X)) continue;
|
|
2722
|
+
const r = X[n];
|
|
2723
|
+
if (!Qt(i, r)) {
|
|
2724
|
+
const o = r.map((s) => s.join(" or ")).join(", ");
|
|
2461
2725
|
a.push({
|
|
2462
2726
|
ruleId: "aria-required-children",
|
|
2463
2727
|
selector: c(i),
|
|
2464
2728
|
html: l(i),
|
|
2465
2729
|
impact: "critical",
|
|
2466
|
-
message: `Role "${
|
|
2730
|
+
message: `Role "${n}" requires children with role: ${o}.`
|
|
2467
2731
|
});
|
|
2468
2732
|
}
|
|
2469
2733
|
}
|
|
2470
2734
|
return a;
|
|
2471
2735
|
}
|
|
2472
|
-
},
|
|
2736
|
+
}, Zt = {
|
|
2473
2737
|
id: "aria-required-parent",
|
|
2474
2738
|
wcag: ["4.1.2"],
|
|
2475
2739
|
level: "A",
|
|
@@ -2480,14 +2744,14 @@ const Ct = {
|
|
|
2480
2744
|
var e;
|
|
2481
2745
|
const a = [];
|
|
2482
2746
|
for (const i of t.querySelectorAll("[role]")) {
|
|
2483
|
-
if (
|
|
2484
|
-
const
|
|
2485
|
-
if (!
|
|
2486
|
-
const
|
|
2747
|
+
if (m(i)) continue;
|
|
2748
|
+
const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
|
|
2749
|
+
if (!n || !(n in K)) continue;
|
|
2750
|
+
const r = K[n];
|
|
2487
2751
|
let o = i.parentElement, s = !1;
|
|
2488
2752
|
for (; o && o !== t.documentElement; ) {
|
|
2489
|
-
const
|
|
2490
|
-
if (
|
|
2753
|
+
const u = E(o);
|
|
2754
|
+
if (u && r.includes(u)) {
|
|
2491
2755
|
s = !0;
|
|
2492
2756
|
break;
|
|
2493
2757
|
}
|
|
@@ -2498,12 +2762,12 @@ const Ct = {
|
|
|
2498
2762
|
selector: c(i),
|
|
2499
2763
|
html: l(i),
|
|
2500
2764
|
impact: "critical",
|
|
2501
|
-
message: `Role "${
|
|
2765
|
+
message: `Role "${n}" must be contained within: ${r.join(", ")}.`
|
|
2502
2766
|
});
|
|
2503
2767
|
}
|
|
2504
2768
|
return a;
|
|
2505
2769
|
}
|
|
2506
|
-
},
|
|
2770
|
+
}, ea = [
|
|
2507
2771
|
"a[href]",
|
|
2508
2772
|
"button:not([disabled])",
|
|
2509
2773
|
'input:not([disabled]):not([type="hidden"])',
|
|
@@ -2519,37 +2783,32 @@ const Ct = {
|
|
|
2519
2783
|
"embed",
|
|
2520
2784
|
"area[href]"
|
|
2521
2785
|
].join(", ");
|
|
2522
|
-
function
|
|
2786
|
+
function ta(t) {
|
|
2523
2787
|
let a = t;
|
|
2524
2788
|
const e = t.ownerDocument, i = e.defaultView;
|
|
2525
2789
|
for (; a && a !== e.body; ) {
|
|
2526
2790
|
if (a.style.display === "none" || a.style.visibility === "hidden") return !1;
|
|
2527
2791
|
if (i) {
|
|
2528
|
-
const
|
|
2529
|
-
if (
|
|
2792
|
+
const n = i.getComputedStyle(a);
|
|
2793
|
+
if (n.display === "none" || n.visibility === "hidden") return !1;
|
|
2530
2794
|
}
|
|
2531
2795
|
a = a.parentElement;
|
|
2532
2796
|
}
|
|
2533
2797
|
return !0;
|
|
2534
2798
|
}
|
|
2535
|
-
const
|
|
2799
|
+
const aa = {
|
|
2536
2800
|
id: "aria-hidden-body",
|
|
2801
|
+
selector: 'body[aria-hidden="true"]',
|
|
2802
|
+
check: { type: "selector-exists" },
|
|
2803
|
+
impact: "critical",
|
|
2804
|
+
message: "aria-hidden='true' on body hides all content from assistive technologies.",
|
|
2805
|
+
description: "aria-hidden='true' must not be present on the document body.",
|
|
2537
2806
|
wcag: ["4.1.2"],
|
|
2538
2807
|
level: "A",
|
|
2539
|
-
description: "aria-hidden='true' must not be present on the document body.",
|
|
2540
2808
|
guidance: "Setting aria-hidden='true' on the body element hides all page content from assistive technologies, making the page completely inaccessible to screen reader users. Remove aria-hidden from the body element. If you need to hide content temporarily (e.g., behind a modal), use aria-hidden on specific sections instead.",
|
|
2541
2809
|
prompt: "Instruct to remove aria-hidden='true' from the body element.",
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
return (a == null ? void 0 : a.getAttribute("aria-hidden")) === "true" ? [{
|
|
2545
|
-
ruleId: "aria-hidden-body",
|
|
2546
|
-
selector: "body",
|
|
2547
|
-
html: l(a),
|
|
2548
|
-
impact: "critical",
|
|
2549
|
-
message: "aria-hidden='true' on body hides all content from assistive technologies."
|
|
2550
|
-
}] : [];
|
|
2551
|
-
}
|
|
2552
|
-
}, Nt = {
|
|
2810
|
+
skipAriaHidden: !1
|
|
2811
|
+
}, ia = x(aa), na = {
|
|
2553
2812
|
id: "aria-hidden-focus",
|
|
2554
2813
|
wcag: ["4.1.2"],
|
|
2555
2814
|
level: "A",
|
|
@@ -2560,14 +2819,14 @@ const Rt = {
|
|
|
2560
2819
|
const a = [];
|
|
2561
2820
|
for (const e of t.querySelectorAll('[aria-hidden="true"]')) {
|
|
2562
2821
|
if (e === t.body) continue;
|
|
2563
|
-
const i = e.querySelectorAll(
|
|
2564
|
-
for (const
|
|
2565
|
-
if (
|
|
2566
|
-
if (
|
|
2822
|
+
const i = e.querySelectorAll(ea);
|
|
2823
|
+
for (const n of i)
|
|
2824
|
+
if (n instanceof HTMLElement) {
|
|
2825
|
+
if (n.getAttribute("tabindex") === "-1" || n.disabled || n instanceof HTMLInputElement && n.type === "hidden" || !ta(n)) continue;
|
|
2567
2826
|
a.push({
|
|
2568
2827
|
ruleId: "aria-hidden-focus",
|
|
2569
|
-
selector: c(
|
|
2570
|
-
html: l(
|
|
2828
|
+
selector: c(n),
|
|
2829
|
+
html: l(n),
|
|
2571
2830
|
impact: "serious",
|
|
2572
2831
|
message: "Focusable element is inside an aria-hidden region."
|
|
2573
2832
|
});
|
|
@@ -2575,7 +2834,7 @@ const Rt = {
|
|
|
2575
2834
|
}
|
|
2576
2835
|
return a;
|
|
2577
2836
|
}
|
|
2578
|
-
},
|
|
2837
|
+
}, ra = {
|
|
2579
2838
|
id: "aria-command-name",
|
|
2580
2839
|
wcag: ["4.1.2"],
|
|
2581
2840
|
level: "A",
|
|
@@ -2586,10 +2845,10 @@ const Rt = {
|
|
|
2586
2845
|
var e;
|
|
2587
2846
|
const a = [];
|
|
2588
2847
|
for (const i of t.querySelectorAll('[role="button"], [role="link"], [role="menuitem"]')) {
|
|
2589
|
-
if (
|
|
2590
|
-
if (!
|
|
2591
|
-
const
|
|
2592
|
-
if ((e =
|
|
2848
|
+
if (m(i) || i.tagName.toLowerCase() === "button" || i.tagName.toLowerCase() === "a") continue;
|
|
2849
|
+
if (!b(i)) {
|
|
2850
|
+
const r = i.querySelector("img[alt]");
|
|
2851
|
+
if ((e = r == null ? void 0 : r.getAttribute("alt")) != null && e.trim()) continue;
|
|
2593
2852
|
a.push({
|
|
2594
2853
|
ruleId: "aria-command-name",
|
|
2595
2854
|
selector: c(i),
|
|
@@ -2601,7 +2860,7 @@ const Rt = {
|
|
|
2601
2860
|
}
|
|
2602
2861
|
return a;
|
|
2603
2862
|
}
|
|
2604
|
-
},
|
|
2863
|
+
}, oa = {
|
|
2605
2864
|
id: "aria-input-field-name",
|
|
2606
2865
|
wcag: ["4.1.2"],
|
|
2607
2866
|
level: "A",
|
|
@@ -2611,8 +2870,8 @@ const Rt = {
|
|
|
2611
2870
|
run(t) {
|
|
2612
2871
|
const a = [], e = '[role="combobox"], [role="listbox"], [role="searchbox"], [role="slider"], [role="spinbutton"], [role="textbox"]';
|
|
2613
2872
|
for (const i of t.querySelectorAll(e)) {
|
|
2614
|
-
if (
|
|
2615
|
-
|
|
2873
|
+
if (m(i) || i.matches("input, select, textarea")) continue;
|
|
2874
|
+
b(i) || a.push({
|
|
2616
2875
|
ruleId: "aria-input-field-name",
|
|
2617
2876
|
selector: c(i),
|
|
2618
2877
|
html: l(i),
|
|
@@ -2622,7 +2881,7 @@ const Rt = {
|
|
|
2622
2881
|
}
|
|
2623
2882
|
return a;
|
|
2624
2883
|
}
|
|
2625
|
-
},
|
|
2884
|
+
}, sa = {
|
|
2626
2885
|
id: "aria-toggle-field-name",
|
|
2627
2886
|
wcag: ["4.1.2"],
|
|
2628
2887
|
level: "A",
|
|
@@ -2632,8 +2891,8 @@ const Rt = {
|
|
|
2632
2891
|
run(t) {
|
|
2633
2892
|
const a = [], e = '[role="checkbox"], [role="switch"], [role="radio"], [role="menuitemcheckbox"], [role="menuitemradio"]';
|
|
2634
2893
|
for (const i of t.querySelectorAll(e)) {
|
|
2635
|
-
if (
|
|
2636
|
-
|
|
2894
|
+
if (m(i) || i.matches('input[type="checkbox"], input[type="radio"]')) continue;
|
|
2895
|
+
b(i) || a.push({
|
|
2637
2896
|
ruleId: "aria-toggle-field-name",
|
|
2638
2897
|
selector: c(i),
|
|
2639
2898
|
html: l(i),
|
|
@@ -2643,7 +2902,7 @@ const Rt = {
|
|
|
2643
2902
|
}
|
|
2644
2903
|
return a;
|
|
2645
2904
|
}
|
|
2646
|
-
},
|
|
2905
|
+
}, la = {
|
|
2647
2906
|
id: "aria-meter-name",
|
|
2648
2907
|
wcag: ["4.1.2"],
|
|
2649
2908
|
level: "A",
|
|
@@ -2653,8 +2912,8 @@ const Rt = {
|
|
|
2653
2912
|
run(t) {
|
|
2654
2913
|
const a = [];
|
|
2655
2914
|
for (const e of t.querySelectorAll('[role="meter"], meter')) {
|
|
2656
|
-
if (
|
|
2657
|
-
|
|
2915
|
+
if (m(e)) continue;
|
|
2916
|
+
b(e) || a.push({
|
|
2658
2917
|
ruleId: "aria-meter-name",
|
|
2659
2918
|
selector: c(e),
|
|
2660
2919
|
html: l(e),
|
|
@@ -2664,7 +2923,7 @@ const Rt = {
|
|
|
2664
2923
|
}
|
|
2665
2924
|
return a;
|
|
2666
2925
|
}
|
|
2667
|
-
},
|
|
2926
|
+
}, ca = {
|
|
2668
2927
|
id: "aria-progressbar-name",
|
|
2669
2928
|
wcag: ["4.1.2"],
|
|
2670
2929
|
level: "A",
|
|
@@ -2674,8 +2933,8 @@ const Rt = {
|
|
|
2674
2933
|
run(t) {
|
|
2675
2934
|
const a = [];
|
|
2676
2935
|
for (const e of t.querySelectorAll('[role="progressbar"], progress')) {
|
|
2677
|
-
if (
|
|
2678
|
-
|
|
2936
|
+
if (m(e)) continue;
|
|
2937
|
+
b(e) || a.push({
|
|
2679
2938
|
ruleId: "aria-progressbar-name",
|
|
2680
2939
|
selector: c(e),
|
|
2681
2940
|
html: l(e),
|
|
@@ -2685,7 +2944,7 @@ const Rt = {
|
|
|
2685
2944
|
}
|
|
2686
2945
|
return a;
|
|
2687
2946
|
}
|
|
2688
|
-
},
|
|
2947
|
+
}, da = {
|
|
2689
2948
|
id: "aria-dialog-name",
|
|
2690
2949
|
wcag: ["4.1.2"],
|
|
2691
2950
|
level: "A",
|
|
@@ -2695,8 +2954,8 @@ const Rt = {
|
|
|
2695
2954
|
run(t) {
|
|
2696
2955
|
const a = [];
|
|
2697
2956
|
for (const e of t.querySelectorAll('[role="dialog"], [role="alertdialog"], dialog')) {
|
|
2698
|
-
if (
|
|
2699
|
-
|
|
2957
|
+
if (m(e)) continue;
|
|
2958
|
+
b(e) || a.push({
|
|
2700
2959
|
ruleId: "aria-dialog-name",
|
|
2701
2960
|
selector: c(e),
|
|
2702
2961
|
html: l(e),
|
|
@@ -2706,7 +2965,7 @@ const Rt = {
|
|
|
2706
2965
|
}
|
|
2707
2966
|
return a;
|
|
2708
2967
|
}
|
|
2709
|
-
},
|
|
2968
|
+
}, ua = {
|
|
2710
2969
|
id: "aria-tooltip-name",
|
|
2711
2970
|
wcag: ["4.1.2"],
|
|
2712
2971
|
level: "A",
|
|
@@ -2716,8 +2975,8 @@ const Rt = {
|
|
|
2716
2975
|
run(t) {
|
|
2717
2976
|
const a = [];
|
|
2718
2977
|
for (const e of t.querySelectorAll('[role="tooltip"]')) {
|
|
2719
|
-
if (
|
|
2720
|
-
|
|
2978
|
+
if (m(e)) continue;
|
|
2979
|
+
b(e) || a.push({
|
|
2721
2980
|
ruleId: "aria-tooltip-name",
|
|
2722
2981
|
selector: c(e),
|
|
2723
2982
|
html: l(e),
|
|
@@ -2727,7 +2986,7 @@ const Rt = {
|
|
|
2727
2986
|
}
|
|
2728
2987
|
return a;
|
|
2729
2988
|
}
|
|
2730
|
-
},
|
|
2989
|
+
}, ma = {
|
|
2731
2990
|
id: "aria-treeitem-name",
|
|
2732
2991
|
wcag: ["4.1.2"],
|
|
2733
2992
|
level: "A",
|
|
@@ -2737,8 +2996,8 @@ const Rt = {
|
|
|
2737
2996
|
run(t) {
|
|
2738
2997
|
const a = [];
|
|
2739
2998
|
for (const e of t.querySelectorAll('[role="treeitem"]')) {
|
|
2740
|
-
if (
|
|
2741
|
-
|
|
2999
|
+
if (m(e)) continue;
|
|
3000
|
+
b(e) || a.push({
|
|
2742
3001
|
ruleId: "aria-treeitem-name",
|
|
2743
3002
|
selector: c(e),
|
|
2744
3003
|
html: l(e),
|
|
@@ -2748,7 +3007,7 @@ const Rt = {
|
|
|
2748
3007
|
}
|
|
2749
3008
|
return a;
|
|
2750
3009
|
}
|
|
2751
|
-
},
|
|
3010
|
+
}, pa = {
|
|
2752
3011
|
id: "aria-prohibited-attr",
|
|
2753
3012
|
wcag: ["4.1.2"],
|
|
2754
3013
|
level: "A",
|
|
@@ -2756,16 +3015,16 @@ const Rt = {
|
|
|
2756
3015
|
guidance: "Some ARIA roles prohibit certain attributes. For example, roles like 'none', 'presentation', 'generic', and text-level roles (code, emphasis, strong) prohibit aria-label and aria-labelledby because naming is not supported for these roles. Remove the prohibited attributes or change the role.",
|
|
2757
3016
|
prompt: "Identify the prohibited attribute and recommend removing it from this element.",
|
|
2758
3017
|
run(t) {
|
|
2759
|
-
return
|
|
3018
|
+
return _(t).prohibitedAttr;
|
|
2760
3019
|
}
|
|
2761
|
-
},
|
|
3020
|
+
}, ha = [
|
|
2762
3021
|
"a[href]",
|
|
2763
3022
|
"button:not([disabled])",
|
|
2764
3023
|
'input:not([disabled]):not([type="hidden"])',
|
|
2765
3024
|
"select:not([disabled])",
|
|
2766
3025
|
"textarea:not([disabled])",
|
|
2767
3026
|
'[tabindex]:not([tabindex="-1"])'
|
|
2768
|
-
].join(", "),
|
|
3027
|
+
].join(", "), ga = [
|
|
2769
3028
|
"aria-atomic",
|
|
2770
3029
|
"aria-busy",
|
|
2771
3030
|
"aria-controls",
|
|
@@ -2779,7 +3038,7 @@ const Rt = {
|
|
|
2779
3038
|
"aria-live",
|
|
2780
3039
|
"aria-owns",
|
|
2781
3040
|
"aria-relevant"
|
|
2782
|
-
],
|
|
3041
|
+
], ba = {
|
|
2783
3042
|
id: "presentation-role-conflict",
|
|
2784
3043
|
wcag: ["4.1.2"],
|
|
2785
3044
|
level: "A",
|
|
@@ -2789,12 +3048,12 @@ const Rt = {
|
|
|
2789
3048
|
run(t) {
|
|
2790
3049
|
const a = [];
|
|
2791
3050
|
for (const e of t.querySelectorAll('[role="presentation"], [role="none"]')) {
|
|
2792
|
-
if (
|
|
3051
|
+
if (m(e)) continue;
|
|
2793
3052
|
const i = [];
|
|
2794
|
-
e.matches(
|
|
2795
|
-
for (const
|
|
2796
|
-
if (e.hasAttribute(
|
|
2797
|
-
i.push(`has ${
|
|
3053
|
+
e.matches(ha) && i.push("element is focusable");
|
|
3054
|
+
for (const n of ga)
|
|
3055
|
+
if (e.hasAttribute(n)) {
|
|
3056
|
+
i.push(`has ${n}`);
|
|
2798
3057
|
break;
|
|
2799
3058
|
}
|
|
2800
3059
|
(e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby")) && i.push("has accessible name"), i.length > 0 && a.push({
|
|
@@ -2807,7 +3066,7 @@ const Rt = {
|
|
|
2807
3066
|
}
|
|
2808
3067
|
return a;
|
|
2809
3068
|
}
|
|
2810
|
-
},
|
|
3069
|
+
}, fa = {
|
|
2811
3070
|
id: "summary-name",
|
|
2812
3071
|
wcag: ["4.1.2"],
|
|
2813
3072
|
level: "A",
|
|
@@ -2817,8 +3076,8 @@ const Rt = {
|
|
|
2817
3076
|
run(t) {
|
|
2818
3077
|
const a = [];
|
|
2819
3078
|
for (const e of t.querySelectorAll("summary")) {
|
|
2820
|
-
if (
|
|
2821
|
-
|
|
3079
|
+
if (m(e)) continue;
|
|
3080
|
+
b(e) || a.push({
|
|
2822
3081
|
ruleId: "summary-name",
|
|
2823
3082
|
selector: c(e),
|
|
2824
3083
|
html: l(e),
|
|
@@ -2829,24 +3088,24 @@ const Rt = {
|
|
|
2829
3088
|
return a;
|
|
2830
3089
|
}
|
|
2831
3090
|
};
|
|
2832
|
-
function
|
|
2833
|
-
var
|
|
3091
|
+
function va(t) {
|
|
3092
|
+
var n, r;
|
|
2834
3093
|
const a = [], e = t.getAttribute("href");
|
|
2835
3094
|
e && a.push(`href: ${e}`);
|
|
2836
3095
|
const i = t.parentElement;
|
|
2837
3096
|
if (i) {
|
|
2838
3097
|
const o = i.closest("h1, h2, h3, h4, h5, h6");
|
|
2839
|
-
if ((
|
|
3098
|
+
if ((n = o == null ? void 0 : o.textContent) != null && n.trim())
|
|
2840
3099
|
a.push(`Nearby heading: ${o.textContent.trim().slice(0, 80)}`);
|
|
2841
3100
|
else {
|
|
2842
|
-
const s = (
|
|
3101
|
+
const s = (r = i.textContent) == null ? void 0 : r.trim().slice(0, 100);
|
|
2843
3102
|
s && a.push(`Parent text: ${s}`);
|
|
2844
3103
|
}
|
|
2845
3104
|
}
|
|
2846
3105
|
return a.length > 0 ? a.join(`
|
|
2847
3106
|
`) : void 0;
|
|
2848
3107
|
}
|
|
2849
|
-
const
|
|
3108
|
+
const ya = {
|
|
2850
3109
|
id: "link-name",
|
|
2851
3110
|
wcag: ["2.4.4", "4.1.2"],
|
|
2852
3111
|
level: "A",
|
|
@@ -2856,19 +3115,19 @@ const Gt = {
|
|
|
2856
3115
|
run(t) {
|
|
2857
3116
|
const a = [];
|
|
2858
3117
|
for (const e of t.querySelectorAll('a[href], [role="link"]')) {
|
|
2859
|
-
if (
|
|
2860
|
-
|
|
3118
|
+
if (m(e)) continue;
|
|
3119
|
+
b(e) || a.push({
|
|
2861
3120
|
ruleId: "link-name",
|
|
2862
3121
|
selector: c(e),
|
|
2863
3122
|
html: l(e),
|
|
2864
3123
|
impact: "serious",
|
|
2865
3124
|
message: "Link has no discernible text.",
|
|
2866
|
-
context:
|
|
3125
|
+
context: va(e)
|
|
2867
3126
|
});
|
|
2868
3127
|
}
|
|
2869
3128
|
return a;
|
|
2870
3129
|
}
|
|
2871
|
-
},
|
|
3130
|
+
}, wa = {
|
|
2872
3131
|
id: "skip-link",
|
|
2873
3132
|
wcag: ["2.4.1"],
|
|
2874
3133
|
level: "A",
|
|
@@ -2879,11 +3138,11 @@ const Gt = {
|
|
|
2879
3138
|
run(t) {
|
|
2880
3139
|
const a = [], e = t.querySelectorAll('a[href^="#"]');
|
|
2881
3140
|
for (const i of e) {
|
|
2882
|
-
const
|
|
2883
|
-
if (!
|
|
2884
|
-
const
|
|
2885
|
-
if (!(
|
|
2886
|
-
const s =
|
|
3141
|
+
const n = i.getAttribute("href");
|
|
3142
|
+
if (!n || n === "#") continue;
|
|
3143
|
+
const r = w(i).toLowerCase();
|
|
3144
|
+
if (!(r.includes("skip") || r.includes("jump") || r.includes("main content") || r.includes("navigation"))) continue;
|
|
3145
|
+
const s = n.slice(1);
|
|
2887
3146
|
t.getElementById(s) || a.push({
|
|
2888
3147
|
ruleId: "skip-link",
|
|
2889
3148
|
selector: c(i),
|
|
@@ -2894,7 +3153,7 @@ const Gt = {
|
|
|
2894
3153
|
}
|
|
2895
3154
|
return a;
|
|
2896
3155
|
}
|
|
2897
|
-
},
|
|
3156
|
+
}, Aa = {
|
|
2898
3157
|
id: "link-in-text-block",
|
|
2899
3158
|
wcag: ["1.4.1"],
|
|
2900
3159
|
level: "A",
|
|
@@ -2904,11 +3163,11 @@ const Gt = {
|
|
|
2904
3163
|
run(t) {
|
|
2905
3164
|
const a = [];
|
|
2906
3165
|
for (const e of t.querySelectorAll("a[href]")) {
|
|
2907
|
-
if (
|
|
3166
|
+
if (m(e)) continue;
|
|
2908
3167
|
const i = e.parentElement;
|
|
2909
3168
|
if (!i) continue;
|
|
2910
|
-
const
|
|
2911
|
-
if (
|
|
3169
|
+
const n = i.textContent || "", r = e.textContent || "";
|
|
3170
|
+
if (n.length > r.length + 20) {
|
|
2912
3171
|
const o = e.getAttribute("style") || "";
|
|
2913
3172
|
o.includes("text-decoration") && o.includes("none") && a.push({
|
|
2914
3173
|
ruleId: "link-in-text-block",
|
|
@@ -2921,7 +3180,7 @@ const Gt = {
|
|
|
2921
3180
|
}
|
|
2922
3181
|
return a;
|
|
2923
3182
|
}
|
|
2924
|
-
},
|
|
3183
|
+
}, Sa = {
|
|
2925
3184
|
id: "html-has-lang",
|
|
2926
3185
|
wcag: ["3.1.1"],
|
|
2927
3186
|
level: "A",
|
|
@@ -2939,7 +3198,7 @@ const Gt = {
|
|
|
2939
3198
|
message: "<html> element missing lang attribute."
|
|
2940
3199
|
}];
|
|
2941
3200
|
}
|
|
2942
|
-
},
|
|
3201
|
+
}, re = /^[a-z]{2,3}(-[a-z0-9]{2,8})*$/i, xa = {
|
|
2943
3202
|
id: "html-lang-valid",
|
|
2944
3203
|
wcag: ["3.1.1"],
|
|
2945
3204
|
level: "A",
|
|
@@ -2949,7 +3208,7 @@ const Gt = {
|
|
|
2949
3208
|
run(t) {
|
|
2950
3209
|
var e;
|
|
2951
3210
|
const a = (e = t.documentElement.getAttribute("lang")) == null ? void 0 : e.trim();
|
|
2952
|
-
return a && !
|
|
3211
|
+
return a && !re.test(a) ? [{
|
|
2953
3212
|
ruleId: "html-lang-valid",
|
|
2954
3213
|
selector: "html",
|
|
2955
3214
|
html: l(t.documentElement),
|
|
@@ -2957,7 +3216,7 @@ const Gt = {
|
|
|
2957
3216
|
message: `Invalid lang attribute value "${a}".`
|
|
2958
3217
|
}] : [];
|
|
2959
3218
|
}
|
|
2960
|
-
},
|
|
3219
|
+
}, ka = {
|
|
2961
3220
|
id: "valid-lang",
|
|
2962
3221
|
wcag: ["3.1.2"],
|
|
2963
3222
|
level: "AA",
|
|
@@ -2968,19 +3227,19 @@ const Gt = {
|
|
|
2968
3227
|
var e;
|
|
2969
3228
|
const a = [];
|
|
2970
3229
|
for (const i of t.querySelectorAll("[lang]")) {
|
|
2971
|
-
if (
|
|
2972
|
-
const
|
|
2973
|
-
|
|
3230
|
+
if (m(i) || i === t.documentElement) continue;
|
|
3231
|
+
const n = (e = i.getAttribute("lang")) == null ? void 0 : e.trim();
|
|
3232
|
+
n && !re.test(n) && a.push({
|
|
2974
3233
|
ruleId: "valid-lang",
|
|
2975
3234
|
selector: c(i),
|
|
2976
3235
|
html: l(i),
|
|
2977
3236
|
impact: "serious",
|
|
2978
|
-
message: `Invalid lang attribute value "${
|
|
3237
|
+
message: `Invalid lang attribute value "${n}".`
|
|
2979
3238
|
});
|
|
2980
3239
|
}
|
|
2981
3240
|
return a;
|
|
2982
3241
|
}
|
|
2983
|
-
},
|
|
3242
|
+
}, Ia = {
|
|
2984
3243
|
id: "html-xml-lang-mismatch",
|
|
2985
3244
|
wcag: ["3.1.1"],
|
|
2986
3245
|
level: "A",
|
|
@@ -2988,8 +3247,8 @@ const Gt = {
|
|
|
2988
3247
|
guidance: "In XHTML documents, if both lang and xml:lang are present, they must specify the same base language. Mismatched values confuse assistive technologies. Either remove xml:lang (preferred for HTML5) or ensure both attributes have identical values.",
|
|
2989
3248
|
prompt: "Explain whether to remove xml:lang or align it with the lang value.",
|
|
2990
3249
|
run(t) {
|
|
2991
|
-
var
|
|
2992
|
-
const a = t.documentElement, e = (
|
|
3250
|
+
var n, r;
|
|
3251
|
+
const a = t.documentElement, e = (n = a.getAttribute("lang")) == null ? void 0 : n.trim().toLowerCase(), i = (r = a.getAttribute("xml:lang")) == null ? void 0 : r.trim().toLowerCase();
|
|
2993
3252
|
if (e && i) {
|
|
2994
3253
|
const o = e.split("-")[0], s = i.split("-")[0];
|
|
2995
3254
|
if (o !== s)
|
|
@@ -3003,7 +3262,7 @@ const Gt = {
|
|
|
3003
3262
|
}
|
|
3004
3263
|
return [];
|
|
3005
3264
|
}
|
|
3006
|
-
},
|
|
3265
|
+
}, qa = {
|
|
3007
3266
|
id: "td-headers-attr",
|
|
3008
3267
|
wcag: ["1.3.1"],
|
|
3009
3268
|
level: "A",
|
|
@@ -3013,25 +3272,25 @@ const Gt = {
|
|
|
3013
3272
|
run(t) {
|
|
3014
3273
|
const a = [];
|
|
3015
3274
|
for (const e of t.querySelectorAll("td[headers]")) {
|
|
3016
|
-
if (
|
|
3275
|
+
if (m(e)) continue;
|
|
3017
3276
|
const i = e.closest("table");
|
|
3018
3277
|
if (!i) continue;
|
|
3019
|
-
const
|
|
3020
|
-
for (const
|
|
3021
|
-
if (!i.querySelector(`th#${CSS.escape(
|
|
3278
|
+
const n = e.getAttribute("headers").split(/\s+/);
|
|
3279
|
+
for (const r of n)
|
|
3280
|
+
if (!i.querySelector(`th#${CSS.escape(r)}, td#${CSS.escape(r)}`)) {
|
|
3022
3281
|
a.push({
|
|
3023
3282
|
ruleId: "td-headers-attr",
|
|
3024
3283
|
selector: c(e),
|
|
3025
3284
|
html: l(e),
|
|
3026
3285
|
impact: "serious",
|
|
3027
|
-
message: `Headers attribute references non-existent ID "${
|
|
3286
|
+
message: `Headers attribute references non-existent ID "${r}".`
|
|
3028
3287
|
});
|
|
3029
3288
|
break;
|
|
3030
3289
|
}
|
|
3031
3290
|
}
|
|
3032
3291
|
return a;
|
|
3033
3292
|
}
|
|
3034
|
-
},
|
|
3293
|
+
}, Ca = {
|
|
3035
3294
|
id: "th-has-data-cells",
|
|
3036
3295
|
wcag: ["1.3.1"],
|
|
3037
3296
|
level: "A",
|
|
@@ -3041,9 +3300,9 @@ const Gt = {
|
|
|
3041
3300
|
run(t) {
|
|
3042
3301
|
const a = [];
|
|
3043
3302
|
for (const e of t.querySelectorAll("table")) {
|
|
3044
|
-
if (
|
|
3045
|
-
const i = e.querySelectorAll("th"),
|
|
3046
|
-
i.length > 0 &&
|
|
3303
|
+
if (m(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none") continue;
|
|
3304
|
+
const i = e.querySelectorAll("th"), n = e.querySelectorAll("td");
|
|
3305
|
+
i.length > 0 && n.length === 0 && a.push({
|
|
3047
3306
|
ruleId: "th-has-data-cells",
|
|
3048
3307
|
selector: c(e),
|
|
3049
3308
|
html: l(e),
|
|
@@ -3053,7 +3312,7 @@ const Gt = {
|
|
|
3053
3312
|
}
|
|
3054
3313
|
return a;
|
|
3055
3314
|
}
|
|
3056
|
-
},
|
|
3315
|
+
}, Ta = {
|
|
3057
3316
|
id: "td-has-header",
|
|
3058
3317
|
wcag: ["1.3.1"],
|
|
3059
3318
|
level: "A",
|
|
@@ -3063,34 +3322,34 @@ const Gt = {
|
|
|
3063
3322
|
run(t) {
|
|
3064
3323
|
var e, i;
|
|
3065
3324
|
const a = [];
|
|
3066
|
-
for (const
|
|
3067
|
-
if (
|
|
3068
|
-
const
|
|
3325
|
+
for (const n of t.querySelectorAll("table")) {
|
|
3326
|
+
if (m(n) || n.getAttribute("role") === "presentation" || n.getAttribute("role") === "none") continue;
|
|
3327
|
+
const r = n.querySelectorAll("tr"), o = r.length;
|
|
3069
3328
|
let s = 0;
|
|
3070
|
-
for (const p of
|
|
3071
|
-
const
|
|
3329
|
+
for (const p of r) {
|
|
3330
|
+
const g = p.querySelectorAll("td, th");
|
|
3072
3331
|
let f = 0;
|
|
3073
|
-
for (const v of
|
|
3332
|
+
for (const v of g)
|
|
3074
3333
|
f += parseInt(v.getAttribute("colspan") || "1", 10);
|
|
3075
3334
|
s = Math.max(s, f);
|
|
3076
3335
|
}
|
|
3077
3336
|
if (o <= 3 && s <= 3) continue;
|
|
3078
|
-
const
|
|
3079
|
-
if (
|
|
3080
|
-
for (const p of
|
|
3081
|
-
if (
|
|
3082
|
-
const
|
|
3083
|
-
if (!
|
|
3084
|
-
const f =
|
|
3337
|
+
const u = n.querySelector("th") !== null, h = n.querySelector("th[scope]") !== null, d = n.querySelector("td[headers]") !== null;
|
|
3338
|
+
if (u)
|
|
3339
|
+
for (const p of n.querySelectorAll("td")) {
|
|
3340
|
+
if (m(p) || p.hasAttribute("headers")) continue;
|
|
3341
|
+
const g = p.closest("tr");
|
|
3342
|
+
if (!g) continue;
|
|
3343
|
+
const f = g.querySelector("th") !== null, v = Array.from(g.children).indexOf(p);
|
|
3085
3344
|
let y = !1;
|
|
3086
|
-
const
|
|
3087
|
-
if (
|
|
3088
|
-
const
|
|
3089
|
-
|
|
3345
|
+
const T = n.querySelector("thead");
|
|
3346
|
+
if (T) {
|
|
3347
|
+
const A = T.querySelector("tr");
|
|
3348
|
+
A && ((e = A.querySelectorAll("th, td")[v]) == null ? void 0 : e.tagName.toLowerCase()) === "th" && (y = !0);
|
|
3090
3349
|
}
|
|
3091
3350
|
if (!y) {
|
|
3092
|
-
const
|
|
3093
|
-
|
|
3351
|
+
const A = n.querySelector("tbody > tr, tr");
|
|
3352
|
+
A && ((i = A.querySelectorAll("th, td")[v]) == null ? void 0 : i.tagName.toLowerCase()) === "th" && (y = !0);
|
|
3094
3353
|
}
|
|
3095
3354
|
if (!f && !y && !h && !d) {
|
|
3096
3355
|
a.push({
|
|
@@ -3106,7 +3365,7 @@ const Gt = {
|
|
|
3106
3365
|
}
|
|
3107
3366
|
return a;
|
|
3108
3367
|
}
|
|
3109
|
-
},
|
|
3368
|
+
}, Ea = {
|
|
3110
3369
|
id: "scope-attr-valid",
|
|
3111
3370
|
wcag: ["1.3.1"],
|
|
3112
3371
|
level: "A",
|
|
@@ -3116,20 +3375,20 @@ const Gt = {
|
|
|
3116
3375
|
run(t) {
|
|
3117
3376
|
var i;
|
|
3118
3377
|
const a = [], e = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
|
|
3119
|
-
for (const
|
|
3120
|
-
if (
|
|
3121
|
-
const
|
|
3122
|
-
|
|
3378
|
+
for (const n of t.querySelectorAll("th[scope]")) {
|
|
3379
|
+
if (m(n)) continue;
|
|
3380
|
+
const r = (i = n.getAttribute("scope")) == null ? void 0 : i.toLowerCase();
|
|
3381
|
+
r && !e.has(r) && a.push({
|
|
3123
3382
|
ruleId: "scope-attr-valid",
|
|
3124
|
-
selector: c(
|
|
3125
|
-
html: l(
|
|
3383
|
+
selector: c(n),
|
|
3384
|
+
html: l(n),
|
|
3126
3385
|
impact: "moderate",
|
|
3127
|
-
message: `Invalid scope value "${
|
|
3386
|
+
message: `Invalid scope value "${r}". Use row, col, rowgroup, or colgroup.`
|
|
3128
3387
|
});
|
|
3129
3388
|
}
|
|
3130
3389
|
return a;
|
|
3131
3390
|
}
|
|
3132
|
-
},
|
|
3391
|
+
}, La = {
|
|
3133
3392
|
id: "empty-table-header",
|
|
3134
3393
|
wcag: [],
|
|
3135
3394
|
level: "A",
|
|
@@ -3140,9 +3399,9 @@ const Gt = {
|
|
|
3140
3399
|
run(t) {
|
|
3141
3400
|
const a = [];
|
|
3142
3401
|
for (const e of t.querySelectorAll("th")) {
|
|
3143
|
-
if (
|
|
3402
|
+
if (m(e)) continue;
|
|
3144
3403
|
const i = e.closest("table");
|
|
3145
|
-
(i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" ||
|
|
3404
|
+
(i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" || b(e) || a.push({
|
|
3146
3405
|
ruleId: "empty-table-header",
|
|
3147
3406
|
selector: c(e),
|
|
3148
3407
|
html: l(e),
|
|
@@ -3152,7 +3411,7 @@ const Gt = {
|
|
|
3152
3411
|
}
|
|
3153
3412
|
return a;
|
|
3154
3413
|
}
|
|
3155
|
-
},
|
|
3414
|
+
}, N = ["aria-labelledby", "aria-describedby", "aria-controls", "aria-owns", "aria-flowto"], Ra = {
|
|
3156
3415
|
id: "duplicate-id-aria",
|
|
3157
3416
|
wcag: ["4.1.2"],
|
|
3158
3417
|
level: "A",
|
|
@@ -3161,46 +3420,46 @@ const Gt = {
|
|
|
3161
3420
|
prompt: "Identify which attribute references this ID and suggest a unique replacement.",
|
|
3162
3421
|
run(t) {
|
|
3163
3422
|
const a = [], e = /* @__PURE__ */ new Set();
|
|
3164
|
-
for (const
|
|
3165
|
-
for (const
|
|
3166
|
-
const o =
|
|
3423
|
+
for (const n of t.querySelectorAll("[aria-labelledby], [aria-describedby], [aria-controls], [aria-owns], [aria-flowto]"))
|
|
3424
|
+
for (const r of N) {
|
|
3425
|
+
const o = n.getAttribute(r);
|
|
3167
3426
|
o && o.split(/\s+/).forEach((s) => e.add(s));
|
|
3168
3427
|
}
|
|
3169
|
-
for (const
|
|
3170
|
-
const
|
|
3171
|
-
|
|
3428
|
+
for (const n of t.querySelectorAll("label[for]")) {
|
|
3429
|
+
const r = n.getAttribute("for");
|
|
3430
|
+
r && e.add(r);
|
|
3172
3431
|
}
|
|
3173
3432
|
const i = /* @__PURE__ */ new Map();
|
|
3174
|
-
for (const
|
|
3175
|
-
e.has(
|
|
3176
|
-
for (const [
|
|
3177
|
-
if (
|
|
3178
|
-
const o = t.querySelectorAll(`#${CSS.escape(
|
|
3179
|
-
|
|
3180
|
-
),
|
|
3433
|
+
for (const n of t.querySelectorAll("[id]"))
|
|
3434
|
+
e.has(n.id) && (n instanceof HTMLElement && (n.style.display === "none" || n.style.visibility === "hidden" || n.hidden) || i.set(n.id, (i.get(n.id) ?? 0) + 1));
|
|
3435
|
+
for (const [n, r] of i) {
|
|
3436
|
+
if (r <= 1) continue;
|
|
3437
|
+
const o = t.querySelectorAll(`#${CSS.escape(n)}`), s = t.querySelector(
|
|
3438
|
+
N.map((d) => `[${d}~="${CSS.escape(n)}"]`).join(", ")
|
|
3439
|
+
), u = t.querySelector(`label[for="${CSS.escape(n)}"]`);
|
|
3181
3440
|
let h;
|
|
3182
3441
|
if (s) {
|
|
3183
|
-
const d =
|
|
3442
|
+
const d = N.find(
|
|
3184
3443
|
(p) => {
|
|
3185
|
-
var
|
|
3186
|
-
return (
|
|
3444
|
+
var g;
|
|
3445
|
+
return (g = s.getAttribute(p)) == null ? void 0 : g.split(/\s+/).includes(n);
|
|
3187
3446
|
}
|
|
3188
3447
|
);
|
|
3189
3448
|
d && (h = d);
|
|
3190
|
-
} else
|
|
3449
|
+
} else u && (h = "label[for]");
|
|
3191
3450
|
a.push({
|
|
3192
3451
|
ruleId: "duplicate-id-aria",
|
|
3193
3452
|
selector: c(o[1]),
|
|
3194
3453
|
html: l(o[1]),
|
|
3195
3454
|
impact: "critical",
|
|
3196
|
-
message: `Duplicate ID "${
|
|
3455
|
+
message: `Duplicate ID "${n}" referenced by ${h ?? "an accessibility attribute"}.`,
|
|
3197
3456
|
context: `First element: ${l(o[0])}${h ? `
|
|
3198
3457
|
Referenced by: ${h}` : ""}`
|
|
3199
3458
|
});
|
|
3200
3459
|
}
|
|
3201
3460
|
return a;
|
|
3202
3461
|
}
|
|
3203
|
-
},
|
|
3462
|
+
}, Na = {
|
|
3204
3463
|
id: "video-caption",
|
|
3205
3464
|
wcag: ["1.2.2"],
|
|
3206
3465
|
level: "A",
|
|
@@ -3210,7 +3469,7 @@ Referenced by: ${h}` : ""}`
|
|
|
3210
3469
|
run(t) {
|
|
3211
3470
|
const a = [];
|
|
3212
3471
|
for (const e of t.querySelectorAll("video")) {
|
|
3213
|
-
if (
|
|
3472
|
+
if (m(e) || e.hasAttribute("muted") || e.hasAttribute("autoplay")) continue;
|
|
3214
3473
|
e.querySelector('track[kind="captions"], track[kind="subtitles"]') || a.push({
|
|
3215
3474
|
ruleId: "video-caption",
|
|
3216
3475
|
selector: c(e),
|
|
@@ -3221,7 +3480,7 @@ Referenced by: ${h}` : ""}`
|
|
|
3221
3480
|
}
|
|
3222
3481
|
return a;
|
|
3223
3482
|
}
|
|
3224
|
-
},
|
|
3483
|
+
}, Ma = {
|
|
3225
3484
|
id: "audio-caption",
|
|
3226
3485
|
wcag: ["1.2.1"],
|
|
3227
3486
|
level: "A",
|
|
@@ -3231,9 +3490,9 @@ Referenced by: ${h}` : ""}`
|
|
|
3231
3490
|
run(t) {
|
|
3232
3491
|
const a = [];
|
|
3233
3492
|
for (const e of t.querySelectorAll("audio")) {
|
|
3234
|
-
if (
|
|
3235
|
-
const
|
|
3236
|
-
|
|
3493
|
+
if (m(e) || e.querySelector('track[kind="captions"], track[kind="descriptions"]') || e.hasAttribute("aria-describedby")) continue;
|
|
3494
|
+
const n = e.parentElement;
|
|
3495
|
+
n && n.querySelector('a[href*="transcript"], a[href*="text"]') || a.push({
|
|
3237
3496
|
ruleId: "audio-caption",
|
|
3238
3497
|
selector: c(e),
|
|
3239
3498
|
html: l(e),
|
|
@@ -3243,122 +3502,195 @@ Referenced by: ${h}` : ""}`
|
|
|
3243
3502
|
}
|
|
3244
3503
|
return a;
|
|
3245
3504
|
}
|
|
3246
|
-
},
|
|
3505
|
+
}, $a = /* @__PURE__ */ new Set([
|
|
3506
|
+
"SCRIPT",
|
|
3507
|
+
"STYLE",
|
|
3508
|
+
"NOSCRIPT",
|
|
3509
|
+
"TEMPLATE",
|
|
3510
|
+
"IFRAME",
|
|
3511
|
+
"OBJECT",
|
|
3512
|
+
"EMBED",
|
|
3513
|
+
"SVG",
|
|
3514
|
+
"CANVAS",
|
|
3515
|
+
"VIDEO",
|
|
3516
|
+
"AUDIO",
|
|
3517
|
+
"IMG",
|
|
3518
|
+
"BR",
|
|
3519
|
+
"HR"
|
|
3520
|
+
]);
|
|
3521
|
+
function Y([t, a, e]) {
|
|
3522
|
+
return "#" + [t, a, e].map((i) => i.toString(16).padStart(2, "0")).join("");
|
|
3523
|
+
}
|
|
3524
|
+
function Ha(t) {
|
|
3525
|
+
return t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement || t instanceof HTMLButtonElement ? t.disabled : !!t.closest("fieldset[disabled]");
|
|
3526
|
+
}
|
|
3527
|
+
function Da(t) {
|
|
3528
|
+
if (m(t)) return !0;
|
|
3529
|
+
let a = t;
|
|
3530
|
+
for (; a; ) {
|
|
3531
|
+
const e = C(a);
|
|
3532
|
+
if (e.display === "none" || e.visibility === "hidden") return !0;
|
|
3533
|
+
a = a.parentElement;
|
|
3534
|
+
}
|
|
3535
|
+
return !1;
|
|
3536
|
+
}
|
|
3537
|
+
const Ba = {
|
|
3538
|
+
id: "color-contrast",
|
|
3539
|
+
wcag: ["1.4.3"],
|
|
3540
|
+
level: "AA",
|
|
3541
|
+
description: "Text elements must have sufficient color contrast against the background.",
|
|
3542
|
+
guidance: "WCAG SC 1.4.3 requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (>=24px or >=18.66px bold). Increase the contrast by darkening the text or lightening the background, or vice versa.",
|
|
3543
|
+
prompt: "Suggest changing the text or background color to meet the minimum contrast ratio.",
|
|
3544
|
+
run(t) {
|
|
3545
|
+
const a = [], e = t.body;
|
|
3546
|
+
if (!e) return [];
|
|
3547
|
+
const i = t.createTreeWalker(e, NodeFilter.SHOW_TEXT), n = /* @__PURE__ */ new Set();
|
|
3548
|
+
let r;
|
|
3549
|
+
for (; r = i.nextNode(); ) {
|
|
3550
|
+
if (!r.textContent || !r.textContent.trim()) continue;
|
|
3551
|
+
const o = r.parentElement;
|
|
3552
|
+
if (!o || n.has(o) || (n.add(o), $a.has(o.tagName)) || Ha(o) || Da(o)) continue;
|
|
3553
|
+
const s = C(o);
|
|
3554
|
+
if (parseFloat(s.opacity) === 0) continue;
|
|
3555
|
+
const u = ne(s.color);
|
|
3556
|
+
if (!u) continue;
|
|
3557
|
+
const h = s.color.match(/rgba\(.+?,\s*([\d.]+)\s*\)/);
|
|
3558
|
+
if (h && parseFloat(h[1]) === 0) continue;
|
|
3559
|
+
const d = Ie(o);
|
|
3560
|
+
if (!d) continue;
|
|
3561
|
+
const p = U(u[0], u[1], u[2]), g = U(d[0], d[1], d[2]), f = ke(p, g), v = Ce(o) ? 3 : 4.5;
|
|
3562
|
+
if (f < v) {
|
|
3563
|
+
const y = Math.round(f * 100) / 100, T = Y(u), A = Y(d);
|
|
3564
|
+
a.push({
|
|
3565
|
+
ruleId: "color-contrast",
|
|
3566
|
+
selector: c(o),
|
|
3567
|
+
html: l(o),
|
|
3568
|
+
impact: "serious",
|
|
3569
|
+
message: `Insufficient color contrast ratio of ${y}:1 (required ${v}:1).`,
|
|
3570
|
+
context: `foreground: ${T} rgb(${u.join(", ")}), background: ${A} rgb(${d.join(", ")}), ratio: ${y}:1, required: ${v}:1`
|
|
3571
|
+
});
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
return a;
|
|
3575
|
+
}
|
|
3576
|
+
}, oe = [
|
|
3247
3577
|
// Document Structure
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3578
|
+
It,
|
|
3579
|
+
qt,
|
|
3580
|
+
Ct,
|
|
3581
|
+
Tt,
|
|
3582
|
+
Et,
|
|
3583
|
+
Rt,
|
|
3584
|
+
Nt,
|
|
3585
|
+
$t,
|
|
3586
|
+
Dt,
|
|
3257
3587
|
// Images
|
|
3258
|
-
me,
|
|
3259
|
-
pe,
|
|
3260
|
-
he,
|
|
3261
|
-
ge,
|
|
3262
|
-
fe,
|
|
3263
|
-
ve,
|
|
3264
|
-
ye,
|
|
3265
|
-
we,
|
|
3266
|
-
Ae,
|
|
3267
|
-
// Forms
|
|
3268
|
-
Se,
|
|
3269
|
-
xe,
|
|
3270
|
-
ke,
|
|
3271
|
-
Ie,
|
|
3272
|
-
Ce,
|
|
3273
|
-
Te,
|
|
3274
|
-
Le,
|
|
3275
|
-
// Keyboard
|
|
3276
3588
|
Ee,
|
|
3589
|
+
Le,
|
|
3590
|
+
Re,
|
|
3277
3591
|
Ne,
|
|
3278
|
-
|
|
3592
|
+
$e,
|
|
3593
|
+
He,
|
|
3594
|
+
De,
|
|
3595
|
+
Be,
|
|
3279
3596
|
Fe,
|
|
3597
|
+
// Forms
|
|
3280
3598
|
Pe,
|
|
3281
|
-
// Structure
|
|
3282
|
-
_e,
|
|
3283
|
-
st,
|
|
3284
|
-
mt,
|
|
3285
3599
|
Ve,
|
|
3286
3600
|
Ue,
|
|
3287
3601
|
je,
|
|
3288
|
-
ze,
|
|
3289
3602
|
Ge,
|
|
3290
|
-
Ke,
|
|
3291
3603
|
Xe,
|
|
3604
|
+
Ke,
|
|
3605
|
+
// Keyboard
|
|
3292
3606
|
Qe,
|
|
3293
|
-
Ye,
|
|
3294
|
-
Je,
|
|
3295
3607
|
Ze,
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3608
|
+
ot,
|
|
3609
|
+
st,
|
|
3610
|
+
lt,
|
|
3611
|
+
// Structure
|
|
3612
|
+
ct,
|
|
3613
|
+
Lt,
|
|
3614
|
+
Bt,
|
|
3615
|
+
dt,
|
|
3616
|
+
ut,
|
|
3617
|
+
mt,
|
|
3299
3618
|
pt,
|
|
3300
3619
|
ht,
|
|
3301
3620
|
gt,
|
|
3621
|
+
bt,
|
|
3302
3622
|
ft,
|
|
3623
|
+
vt,
|
|
3624
|
+
yt,
|
|
3625
|
+
At,
|
|
3303
3626
|
St,
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
Tt,
|
|
3307
|
-
Rt,
|
|
3308
|
-
Nt,
|
|
3309
|
-
$t,
|
|
3310
|
-
Mt,
|
|
3311
|
-
Ht,
|
|
3312
|
-
Dt,
|
|
3313
|
-
Bt,
|
|
3627
|
+
kt,
|
|
3628
|
+
// ARIA
|
|
3314
3629
|
Ot,
|
|
3315
3630
|
Wt,
|
|
3316
|
-
|
|
3631
|
+
_t,
|
|
3317
3632
|
Pt,
|
|
3318
|
-
Ut,
|
|
3319
|
-
yt,
|
|
3320
|
-
jt,
|
|
3321
|
-
// Links
|
|
3322
3633
|
Gt,
|
|
3323
|
-
Kt,
|
|
3324
|
-
Xt,
|
|
3325
|
-
// Language
|
|
3326
|
-
Qt,
|
|
3327
3634
|
Yt,
|
|
3328
3635
|
Jt,
|
|
3329
3636
|
Zt,
|
|
3330
|
-
// Tables
|
|
3331
|
-
ea,
|
|
3332
|
-
ta,
|
|
3333
|
-
aa,
|
|
3334
3637
|
ia,
|
|
3638
|
+
na,
|
|
3335
3639
|
ra,
|
|
3640
|
+
oa,
|
|
3641
|
+
sa,
|
|
3642
|
+
la,
|
|
3643
|
+
ca,
|
|
3644
|
+
da,
|
|
3645
|
+
ua,
|
|
3646
|
+
ma,
|
|
3647
|
+
pa,
|
|
3648
|
+
ba,
|
|
3649
|
+
Ut,
|
|
3650
|
+
fa,
|
|
3651
|
+
// Links
|
|
3652
|
+
ya,
|
|
3653
|
+
wa,
|
|
3654
|
+
Aa,
|
|
3655
|
+
// Language
|
|
3656
|
+
Sa,
|
|
3657
|
+
xa,
|
|
3658
|
+
ka,
|
|
3659
|
+
Ia,
|
|
3660
|
+
// Tables
|
|
3661
|
+
qa,
|
|
3662
|
+
Ca,
|
|
3663
|
+
Ta,
|
|
3664
|
+
Ea,
|
|
3665
|
+
La,
|
|
3336
3666
|
// Parsing
|
|
3337
|
-
|
|
3667
|
+
Ra,
|
|
3338
3668
|
// Media
|
|
3339
|
-
|
|
3340
|
-
|
|
3669
|
+
Na,
|
|
3670
|
+
Ma,
|
|
3671
|
+
// Color
|
|
3672
|
+
Ba
|
|
3341
3673
|
];
|
|
3342
|
-
let
|
|
3343
|
-
function
|
|
3344
|
-
t.additionalRules && (
|
|
3674
|
+
let F = [], se = /* @__PURE__ */ new Set();
|
|
3675
|
+
function Fa(t) {
|
|
3676
|
+
t.additionalRules && (F = t.additionalRules), t.disabledRules && (se = new Set(t.disabledRules));
|
|
3345
3677
|
}
|
|
3346
|
-
function
|
|
3347
|
-
return
|
|
3678
|
+
function le() {
|
|
3679
|
+
return oe.filter((a) => !se.has(a.id)).concat(F);
|
|
3348
3680
|
}
|
|
3349
|
-
function
|
|
3350
|
-
|
|
3351
|
-
const a =
|
|
3681
|
+
function Pa(t) {
|
|
3682
|
+
ee(), Q(), Z(), ie(), ae(), te();
|
|
3683
|
+
const a = le(), e = [];
|
|
3352
3684
|
let i = 0;
|
|
3353
3685
|
return {
|
|
3354
|
-
processChunk(
|
|
3355
|
-
const
|
|
3686
|
+
processChunk(n) {
|
|
3687
|
+
const r = performance.now();
|
|
3356
3688
|
for (; i < a.length; ) {
|
|
3357
3689
|
try {
|
|
3358
3690
|
e.push(...a[i].run(t));
|
|
3359
3691
|
} catch {
|
|
3360
3692
|
}
|
|
3361
|
-
if (i++, performance.now() -
|
|
3693
|
+
if (i++, performance.now() - r >= n) break;
|
|
3362
3694
|
}
|
|
3363
3695
|
return i < a.length;
|
|
3364
3696
|
},
|
|
@@ -3367,13 +3699,13 @@ function ma(t) {
|
|
|
3367
3699
|
}
|
|
3368
3700
|
};
|
|
3369
3701
|
}
|
|
3370
|
-
function
|
|
3702
|
+
function Va(t) {
|
|
3371
3703
|
var i;
|
|
3372
|
-
|
|
3373
|
-
const a =
|
|
3374
|
-
for (const
|
|
3704
|
+
ee(), Q(), Z(), ie(), ae(), te();
|
|
3705
|
+
const a = le(), e = [];
|
|
3706
|
+
for (const n of a)
|
|
3375
3707
|
try {
|
|
3376
|
-
e.push(...
|
|
3708
|
+
e.push(...n.run(t));
|
|
3377
3709
|
} catch {
|
|
3378
3710
|
}
|
|
3379
3711
|
return {
|
|
@@ -3383,227 +3715,31 @@ function pa(t) {
|
|
|
3383
3715
|
ruleCount: a.length
|
|
3384
3716
|
};
|
|
3385
3717
|
}
|
|
3386
|
-
const
|
|
3387
|
-
function
|
|
3388
|
-
const a =
|
|
3389
|
-
return a ||
|
|
3390
|
-
}
|
|
3391
|
-
function ga(t) {
|
|
3392
|
-
if (typeof t != "object" || t === null)
|
|
3393
|
-
return "Rule spec must be an object";
|
|
3394
|
-
const a = t;
|
|
3395
|
-
if (typeof a.id != "string" || a.id.length === 0)
|
|
3396
|
-
return "Rule must have a non-empty string id";
|
|
3397
|
-
if (typeof a.selector != "string" || a.selector.length === 0)
|
|
3398
|
-
return "Rule must have a non-empty string selector";
|
|
3399
|
-
if (typeof a.check != "object" || a.check === null)
|
|
3400
|
-
return "Rule must have a check object";
|
|
3401
|
-
const e = a.check;
|
|
3402
|
-
if (![
|
|
3403
|
-
"selector-exists",
|
|
3404
|
-
"attribute-value",
|
|
3405
|
-
"attribute-missing",
|
|
3406
|
-
"attribute-regex",
|
|
3407
|
-
"child-required",
|
|
3408
|
-
"child-invalid"
|
|
3409
|
-
].includes(e.type))
|
|
3410
|
-
return `Invalid check type: ${String(e.type)}`;
|
|
3411
|
-
if (typeof a.impact != "string" || !["critical", "serious", "moderate", "minor"].includes(a.impact))
|
|
3412
|
-
return "Rule must have a valid impact (critical|serious|moderate|minor)";
|
|
3413
|
-
if (typeof a.message != "string" || a.message.length === 0)
|
|
3414
|
-
return "Rule must have a non-empty message";
|
|
3415
|
-
if (typeof a.description != "string")
|
|
3416
|
-
return "Rule must have a description string";
|
|
3417
|
-
if (!Array.isArray(a.wcag))
|
|
3418
|
-
return "Rule must have a wcag array";
|
|
3419
|
-
if (typeof a.level != "string" || !["A", "AA"].includes(a.level))
|
|
3420
|
-
return "Rule must have level A or AA";
|
|
3421
|
-
const r = ca(e);
|
|
3422
|
-
return r || null;
|
|
3423
|
-
}
|
|
3424
|
-
function ca(t) {
|
|
3425
|
-
switch (t.type) {
|
|
3426
|
-
case "selector-exists":
|
|
3427
|
-
return null;
|
|
3428
|
-
case "attribute-value":
|
|
3429
|
-
return typeof t.attribute != "string" ? "attribute-value check requires attribute string" : [">", "<", "=", "!=", "in", "not-in"].includes(t.operator) ? t.value === void 0 ? "attribute-value check requires value" : null : "attribute-value check requires valid operator";
|
|
3430
|
-
case "attribute-missing":
|
|
3431
|
-
return typeof t.attribute != "string" ? "attribute-missing check requires attribute string" : null;
|
|
3432
|
-
case "attribute-regex":
|
|
3433
|
-
return typeof t.attribute != "string" ? "attribute-regex check requires attribute string" : typeof t.pattern != "string" ? "attribute-regex check requires pattern string" : typeof t.shouldMatch != "boolean" ? "attribute-regex check requires shouldMatch boolean" : null;
|
|
3434
|
-
case "child-required":
|
|
3435
|
-
return typeof t.childSelector != "string" ? "child-required check requires childSelector string" : null;
|
|
3436
|
-
case "child-invalid":
|
|
3437
|
-
return Array.isArray(t.allowedChildren) ? null : "child-invalid check requires allowedChildren array";
|
|
3438
|
-
default:
|
|
3439
|
-
return `Unknown check type: ${String(t.type)}`;
|
|
3440
|
-
}
|
|
3441
|
-
}
|
|
3442
|
-
function A(t, a, e) {
|
|
3443
|
-
let i = t;
|
|
3444
|
-
if (i.includes("{{tag}}") && (i = i.replace(/\{\{tag\}\}/g, a.tagName.toLowerCase())), i.includes("{{value}}")) {
|
|
3445
|
-
let r = "";
|
|
3446
|
-
"attribute" in e && e.attribute && (r = a.getAttribute(e.attribute) ?? ""), i = i.replace(/\{\{value\}\}/g, r);
|
|
3447
|
-
}
|
|
3448
|
-
return i;
|
|
3449
|
-
}
|
|
3450
|
-
function ba(t) {
|
|
3451
|
-
const a = t.skipAriaHidden !== !1;
|
|
3452
|
-
return {
|
|
3453
|
-
id: t.id,
|
|
3454
|
-
wcag: t.wcag,
|
|
3455
|
-
level: t.level,
|
|
3456
|
-
tags: t.tags,
|
|
3457
|
-
description: t.description,
|
|
3458
|
-
guidance: t.guidance,
|
|
3459
|
-
prompt: t.prompt,
|
|
3460
|
-
run(e) {
|
|
3461
|
-
const i = [];
|
|
3462
|
-
switch (t.check.type) {
|
|
3463
|
-
case "selector-exists": {
|
|
3464
|
-
for (const r of e.querySelectorAll(t.selector))
|
|
3465
|
-
a && u(r) || i.push({
|
|
3466
|
-
ruleId: t.id,
|
|
3467
|
-
selector: c(r),
|
|
3468
|
-
html: l(r),
|
|
3469
|
-
impact: t.impact,
|
|
3470
|
-
message: A(t.message, r, t.check),
|
|
3471
|
-
element: r
|
|
3472
|
-
});
|
|
3473
|
-
break;
|
|
3474
|
-
}
|
|
3475
|
-
case "attribute-value": {
|
|
3476
|
-
const { attribute: r, operator: n, value: o } = t.check;
|
|
3477
|
-
for (const s of e.querySelectorAll(t.selector)) {
|
|
3478
|
-
if (a && u(s)) continue;
|
|
3479
|
-
const m = s.getAttribute(r);
|
|
3480
|
-
m !== null && da(m, n, o) && i.push({
|
|
3481
|
-
ruleId: t.id,
|
|
3482
|
-
selector: c(s),
|
|
3483
|
-
html: l(s),
|
|
3484
|
-
impact: t.impact,
|
|
3485
|
-
message: A(t.message, s, t.check),
|
|
3486
|
-
element: s
|
|
3487
|
-
});
|
|
3488
|
-
}
|
|
3489
|
-
break;
|
|
3490
|
-
}
|
|
3491
|
-
case "attribute-missing": {
|
|
3492
|
-
const { attribute: r } = t.check;
|
|
3493
|
-
for (const n of e.querySelectorAll(t.selector))
|
|
3494
|
-
a && u(n) || n.hasAttribute(r) || i.push({
|
|
3495
|
-
ruleId: t.id,
|
|
3496
|
-
selector: c(n),
|
|
3497
|
-
html: l(n),
|
|
3498
|
-
impact: t.impact,
|
|
3499
|
-
message: A(t.message, n, t.check),
|
|
3500
|
-
element: n
|
|
3501
|
-
});
|
|
3502
|
-
break;
|
|
3503
|
-
}
|
|
3504
|
-
case "attribute-regex": {
|
|
3505
|
-
const { attribute: r, pattern: n, flags: o, shouldMatch: s } = t.check;
|
|
3506
|
-
let m;
|
|
3507
|
-
try {
|
|
3508
|
-
m = new RegExp(n, o);
|
|
3509
|
-
} catch {
|
|
3510
|
-
break;
|
|
3511
|
-
}
|
|
3512
|
-
for (const h of e.querySelectorAll(t.selector)) {
|
|
3513
|
-
if (a && u(h)) continue;
|
|
3514
|
-
const d = h.getAttribute(r);
|
|
3515
|
-
if (d === null) continue;
|
|
3516
|
-
const p = m.test(d);
|
|
3517
|
-
s && !p ? i.push({
|
|
3518
|
-
ruleId: t.id,
|
|
3519
|
-
selector: c(h),
|
|
3520
|
-
html: l(h),
|
|
3521
|
-
impact: t.impact,
|
|
3522
|
-
message: A(t.message, h, t.check),
|
|
3523
|
-
element: h
|
|
3524
|
-
}) : !s && p && i.push({
|
|
3525
|
-
ruleId: t.id,
|
|
3526
|
-
selector: c(h),
|
|
3527
|
-
html: l(h),
|
|
3528
|
-
impact: t.impact,
|
|
3529
|
-
message: A(t.message, h, t.check),
|
|
3530
|
-
element: h
|
|
3531
|
-
});
|
|
3532
|
-
}
|
|
3533
|
-
break;
|
|
3534
|
-
}
|
|
3535
|
-
case "child-required": {
|
|
3536
|
-
const { childSelector: r } = t.check;
|
|
3537
|
-
for (const n of e.querySelectorAll(t.selector))
|
|
3538
|
-
a && u(n) || n.querySelector(r) || i.push({
|
|
3539
|
-
ruleId: t.id,
|
|
3540
|
-
selector: c(n),
|
|
3541
|
-
html: l(n),
|
|
3542
|
-
impact: t.impact,
|
|
3543
|
-
message: A(t.message, n, t.check),
|
|
3544
|
-
element: n
|
|
3545
|
-
});
|
|
3546
|
-
break;
|
|
3547
|
-
}
|
|
3548
|
-
case "child-invalid": {
|
|
3549
|
-
const r = new Set(
|
|
3550
|
-
t.check.allowedChildren.map((n) => n.toLowerCase())
|
|
3551
|
-
);
|
|
3552
|
-
for (const n of e.querySelectorAll(t.selector))
|
|
3553
|
-
if (!(a && u(n))) {
|
|
3554
|
-
for (const o of n.children)
|
|
3555
|
-
if (!r.has(o.tagName.toLowerCase())) {
|
|
3556
|
-
i.push({
|
|
3557
|
-
ruleId: t.id,
|
|
3558
|
-
selector: c(o),
|
|
3559
|
-
html: l(o),
|
|
3560
|
-
impact: t.impact,
|
|
3561
|
-
message: A(t.message, o, t.check),
|
|
3562
|
-
element: o
|
|
3563
|
-
});
|
|
3564
|
-
break;
|
|
3565
|
-
}
|
|
3566
|
-
}
|
|
3567
|
-
break;
|
|
3568
|
-
}
|
|
3569
|
-
}
|
|
3570
|
-
return i;
|
|
3571
|
-
}
|
|
3572
|
-
};
|
|
3573
|
-
}
|
|
3574
|
-
function da(t, a, e) {
|
|
3575
|
-
switch (a) {
|
|
3576
|
-
case ">":
|
|
3577
|
-
return parseFloat(t) > e;
|
|
3578
|
-
case "<":
|
|
3579
|
-
return parseFloat(t) < e;
|
|
3580
|
-
case "=":
|
|
3581
|
-
return t === String(e);
|
|
3582
|
-
case "!=":
|
|
3583
|
-
return t !== String(e);
|
|
3584
|
-
case "in":
|
|
3585
|
-
return Array.isArray(e) && e.includes(t);
|
|
3586
|
-
case "not-in":
|
|
3587
|
-
return Array.isArray(e) && !e.includes(t);
|
|
3588
|
-
default:
|
|
3589
|
-
return !1;
|
|
3590
|
-
}
|
|
3718
|
+
const Oa = new Map(oe.map((t) => [t.id, t]));
|
|
3719
|
+
function Ua(t) {
|
|
3720
|
+
const a = Oa.get(t);
|
|
3721
|
+
return a || F.find((e) => e.id === t);
|
|
3591
3722
|
}
|
|
3592
3723
|
export {
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3724
|
+
ae as clearAriaAttrAuditCache,
|
|
3725
|
+
ee as clearAriaHiddenCache,
|
|
3726
|
+
ie as clearColorCaches,
|
|
3727
|
+
Q as clearComputedRoleCache,
|
|
3728
|
+
x as compileDeclarativeRule,
|
|
3729
|
+
Fa as configureRules,
|
|
3730
|
+
Pa as createChunkedAudit,
|
|
3731
|
+
b as getAccessibleName,
|
|
3597
3732
|
w as getAccessibleTextContent,
|
|
3598
|
-
|
|
3599
|
-
|
|
3733
|
+
le as getActiveRules,
|
|
3734
|
+
E as getComputedRole,
|
|
3600
3735
|
l as getHtmlSnippet,
|
|
3601
|
-
|
|
3602
|
-
|
|
3736
|
+
J as getImplicitRole,
|
|
3737
|
+
Ua as getRuleById,
|
|
3603
3738
|
c as getSelector,
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3739
|
+
m as isAriaHidden,
|
|
3740
|
+
me as isValidRole,
|
|
3741
|
+
Wa as querySelectorShadowAware,
|
|
3742
|
+
oe as rules,
|
|
3743
|
+
Va as runAudit,
|
|
3744
|
+
_a as validateDeclarativeRule
|
|
3609
3745
|
};
|