@accesslint/core 0.3.0 → 0.3.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/dist/index.cjs +5 -5
- package/dist/index.iife.js +5 -5
- package/dist/index.js +1254 -890
- 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/aria/aria-required-attr.d.ts.map +1 -1
- package/dist/rules/aria/aria-roles.d.ts.map +1 -1
- package/dist/rules/aria/button-name.d.ts.map +1 -1
- package/dist/rules/aria/presentation-role-conflict.d.ts.map +1 -1
- package/dist/rules/forms/autocomplete-valid.d.ts.map +1 -1
- package/dist/rules/forms/label.d.ts.map +1 -1
- package/dist/rules/images/img-alt.d.ts.map +1 -1
- package/dist/rules/images/object-alt.d.ts.map +1 -1
- package/dist/rules/images/svg-img-alt.d.ts.map +1 -1
- package/dist/rules/language/html-has-lang.d.ts.map +1 -1
- package/dist/rules/links/link-rules.d.ts.map +1 -1
- package/dist/rules/structure/meta-rules.d.ts.map +1 -1
- package/dist/rules/tables/table-headers.d.ts.map +1 -1
- package/dist/rules/utils/aria.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
let
|
|
2
|
-
function
|
|
3
|
-
|
|
1
|
+
let D = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
function be() {
|
|
3
|
+
D = /* @__PURE__ */ new WeakMap();
|
|
4
4
|
}
|
|
5
|
-
function
|
|
5
|
+
function le(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,71 +117,71 @@ function J(t) {
|
|
|
117
117
|
return null;
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
-
function
|
|
120
|
+
function C(t) {
|
|
121
121
|
var n;
|
|
122
|
-
const a =
|
|
122
|
+
const a = D.get(t);
|
|
123
123
|
if (a !== void 0) return a;
|
|
124
|
-
const i = ((n = t.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase()) || null ||
|
|
125
|
-
return
|
|
124
|
+
const i = ((n = t.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase()) || null || le(t);
|
|
125
|
+
return D.set(t, i), i;
|
|
126
126
|
}
|
|
127
|
-
let
|
|
128
|
-
function
|
|
129
|
-
|
|
127
|
+
let O = /* @__PURE__ */ new WeakMap();
|
|
128
|
+
function fe() {
|
|
129
|
+
O = /* @__PURE__ */ new WeakMap();
|
|
130
130
|
}
|
|
131
|
-
function
|
|
132
|
-
const a =
|
|
131
|
+
function v(t) {
|
|
132
|
+
const a = O.get(t);
|
|
133
133
|
if (a !== void 0) return a;
|
|
134
|
-
const e =
|
|
135
|
-
return
|
|
134
|
+
const e = ve(t);
|
|
135
|
+
return O.set(t, e), e;
|
|
136
136
|
}
|
|
137
|
-
function
|
|
138
|
-
var r, o, s,
|
|
137
|
+
function ve(t) {
|
|
138
|
+
var r, o, s, c, h;
|
|
139
139
|
const a = t.getAttribute("aria-labelledby");
|
|
140
140
|
if (a) {
|
|
141
|
-
const
|
|
142
|
-
const g = t.ownerDocument.getElementById(
|
|
141
|
+
const l = a.split(/\s+/).map((m) => {
|
|
142
|
+
const g = t.ownerDocument.getElementById(m);
|
|
143
143
|
return g ? y(g).trim() : "";
|
|
144
144
|
}).filter(Boolean);
|
|
145
|
-
if (
|
|
145
|
+
if (l.length) return l.join(" ");
|
|
146
146
|
}
|
|
147
147
|
const e = (r = t.getAttribute("aria-label")) == null ? void 0 : r.trim();
|
|
148
148
|
if (e) return e;
|
|
149
149
|
if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) {
|
|
150
150
|
if (t.id) {
|
|
151
|
-
const g = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`),
|
|
152
|
-
if (
|
|
151
|
+
const g = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`), b = g ? y(g).trim() : "";
|
|
152
|
+
if (b) return b;
|
|
153
153
|
}
|
|
154
|
-
const
|
|
155
|
-
if (
|
|
154
|
+
const l = t.closest("label"), m = l ? y(l).trim() : "";
|
|
155
|
+
if (m) return m;
|
|
156
156
|
}
|
|
157
157
|
const i = (o = t.getAttribute("title")) == null ? void 0 : o.trim();
|
|
158
158
|
if (i) return i;
|
|
159
159
|
if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) {
|
|
160
|
-
const
|
|
161
|
-
if (
|
|
160
|
+
const l = (s = t.getAttribute("placeholder")) == null ? void 0 : s.trim();
|
|
161
|
+
if (l) return l;
|
|
162
162
|
}
|
|
163
163
|
const n = t.tagName.toLowerCase();
|
|
164
164
|
if (n === "fieldset") {
|
|
165
|
-
const
|
|
166
|
-
if (
|
|
167
|
-
const
|
|
168
|
-
if (
|
|
165
|
+
const l = t.querySelector(":scope > legend");
|
|
166
|
+
if (l) {
|
|
167
|
+
const m = y(l).trim();
|
|
168
|
+
if (m) return m;
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
if (n === "table") {
|
|
172
|
-
const
|
|
173
|
-
if (
|
|
174
|
-
const
|
|
175
|
-
if (
|
|
172
|
+
const l = t.querySelector(":scope > caption");
|
|
173
|
+
if (l) {
|
|
174
|
+
const m = y(l).trim();
|
|
175
|
+
if (m) return m;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
if (!(t instanceof HTMLInputElement)) {
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
179
|
+
const l = y(t).trim();
|
|
180
|
+
if (l) return l;
|
|
181
181
|
}
|
|
182
|
-
return t instanceof HTMLImageElement || t instanceof HTMLAreaElement ? ((
|
|
182
|
+
return t instanceof HTMLImageElement || t instanceof HTMLAreaElement ? ((c = t.alt) == null ? void 0 : c.trim()) ?? "" : t instanceof HTMLInputElement && t.type === "image" ? ((h = t.alt) == null ? void 0 : h.trim()) ?? "" : "";
|
|
183
183
|
}
|
|
184
|
-
const
|
|
184
|
+
const we = /* @__PURE__ */ new Set([
|
|
185
185
|
"alert",
|
|
186
186
|
"alertdialog",
|
|
187
187
|
"application",
|
|
@@ -265,56 +265,67 @@ const ce = /* @__PURE__ */ new Set([
|
|
|
265
265
|
"treegrid",
|
|
266
266
|
"treeitem"
|
|
267
267
|
]);
|
|
268
|
-
function
|
|
268
|
+
function ye(t) {
|
|
269
269
|
const a = t.trim().toLowerCase().replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "");
|
|
270
|
-
return
|
|
270
|
+
return we.has(a);
|
|
271
271
|
}
|
|
272
|
-
let
|
|
273
|
-
function
|
|
274
|
-
|
|
272
|
+
let B = /* @__PURE__ */ new WeakMap();
|
|
273
|
+
function Ae() {
|
|
274
|
+
B = /* @__PURE__ */ new WeakMap();
|
|
275
275
|
}
|
|
276
|
-
function
|
|
277
|
-
const a =
|
|
276
|
+
function p(t) {
|
|
277
|
+
const a = B.get(t);
|
|
278
278
|
if (a !== void 0) return a;
|
|
279
279
|
let e;
|
|
280
|
-
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 = p(t.parentElement) : e = !1, B.set(t, e), e;
|
|
281
281
|
}
|
|
282
|
-
function
|
|
282
|
+
function Se(t) {
|
|
283
283
|
return !!(t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && (t.hidden || t.style.display === "none"));
|
|
284
284
|
}
|
|
285
285
|
function y(t) {
|
|
286
|
-
var e, i, n, r;
|
|
286
|
+
var e, i, n, r, o;
|
|
287
287
|
let a = "";
|
|
288
|
-
for (const
|
|
289
|
-
if (
|
|
290
|
-
a +=
|
|
291
|
-
else if (
|
|
292
|
-
const
|
|
293
|
-
if (!
|
|
294
|
-
const
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
288
|
+
for (const s of t.childNodes)
|
|
289
|
+
if (s.nodeType === 3)
|
|
290
|
+
a += s.textContent ?? "";
|
|
291
|
+
else if (s.nodeType === 1) {
|
|
292
|
+
const c = s;
|
|
293
|
+
if (!Se(c)) {
|
|
294
|
+
const h = (e = c.tagName) == null ? void 0 : e.toLowerCase();
|
|
295
|
+
if (h === "img" || h === "area") {
|
|
296
|
+
const l = c.getAttribute("aria-labelledby");
|
|
297
|
+
if (l) {
|
|
298
|
+
const m = l.split(/\s+/).map((g) => {
|
|
299
|
+
var b, f;
|
|
300
|
+
return ((f = (b = c.ownerDocument.getElementById(g)) == null ? void 0 : b.textContent) == null ? void 0 : f.trim()) ?? "";
|
|
301
|
+
}).filter(Boolean);
|
|
302
|
+
if (m.length) {
|
|
303
|
+
a += m.join(" ");
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
a += ((i = c.getAttribute("aria-label")) == null ? void 0 : i.trim()) ?? c.getAttribute("alt") ?? ((n = c.getAttribute("title")) == null ? void 0 : n.trim()) ?? "";
|
|
308
|
+
} else if (h === "svg") {
|
|
309
|
+
const l = (r = c.getAttribute("aria-label")) == null ? void 0 : r.trim();
|
|
310
|
+
if (l)
|
|
311
|
+
a += l;
|
|
301
312
|
else {
|
|
302
|
-
const
|
|
303
|
-
|
|
313
|
+
const m = c.querySelector("title");
|
|
314
|
+
m && (a += m.textContent ?? "");
|
|
304
315
|
}
|
|
305
|
-
} else (
|
|
316
|
+
} else (o = c.getAttribute("aria-label")) != null && o.trim() ? a += c.getAttribute("aria-label").trim() : a += y(c);
|
|
306
317
|
}
|
|
307
318
|
}
|
|
308
319
|
return a;
|
|
309
320
|
}
|
|
310
|
-
let
|
|
311
|
-
function
|
|
312
|
-
|
|
321
|
+
let W = /* @__PURE__ */ new WeakMap();
|
|
322
|
+
function xe() {
|
|
323
|
+
W = /* @__PURE__ */ new WeakMap();
|
|
313
324
|
}
|
|
314
|
-
function
|
|
325
|
+
function ke(t) {
|
|
315
326
|
return t.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
316
327
|
}
|
|
317
|
-
const
|
|
328
|
+
const Ie = [
|
|
318
329
|
"data-testid",
|
|
319
330
|
"data-test-id",
|
|
320
331
|
"data-cy",
|
|
@@ -324,12 +335,12 @@ const ge = [
|
|
|
324
335
|
"for",
|
|
325
336
|
"aria-label"
|
|
326
337
|
];
|
|
327
|
-
function
|
|
338
|
+
function Ee(t) {
|
|
328
339
|
const a = t.tagName.toLowerCase();
|
|
329
|
-
for (const i of
|
|
340
|
+
for (const i of Ie) {
|
|
330
341
|
const n = t.getAttribute(i);
|
|
331
342
|
if (n != null && n.length > 0 && n.length < 100)
|
|
332
|
-
return `${a}[${i}="${
|
|
343
|
+
return `${a}[${i}="${ke(n)}"]`;
|
|
333
344
|
}
|
|
334
345
|
const e = t.parentElement;
|
|
335
346
|
if (e) {
|
|
@@ -341,7 +352,7 @@ function be(t) {
|
|
|
341
352
|
}
|
|
342
353
|
return a;
|
|
343
354
|
}
|
|
344
|
-
function
|
|
355
|
+
function M(t) {
|
|
345
356
|
if (t.id) return `#${CSS.escape(t.id)}`;
|
|
346
357
|
const a = t.getRootNode(), e = a instanceof ShadowRoot ? null : a.documentElement, i = [];
|
|
347
358
|
let n = t;
|
|
@@ -350,7 +361,7 @@ function R(t) {
|
|
|
350
361
|
i.unshift(`#${CSS.escape(n.id)}`);
|
|
351
362
|
break;
|
|
352
363
|
}
|
|
353
|
-
if (i.unshift(
|
|
364
|
+
if (i.unshift(Ee(n)), i.length >= 2) {
|
|
354
365
|
const r = i.join(" > ");
|
|
355
366
|
try {
|
|
356
367
|
const o = a.querySelectorAll(r);
|
|
@@ -362,30 +373,30 @@ function R(t) {
|
|
|
362
373
|
}
|
|
363
374
|
return i.join(" > ");
|
|
364
375
|
}
|
|
365
|
-
function
|
|
376
|
+
function d(t) {
|
|
366
377
|
var r;
|
|
367
|
-
const a =
|
|
378
|
+
const a = W.get(t);
|
|
368
379
|
if (a !== void 0) return a;
|
|
369
380
|
const e = [];
|
|
370
381
|
let i = t;
|
|
371
382
|
for (; i; ) {
|
|
372
383
|
const o = i.getRootNode();
|
|
373
384
|
if (o instanceof ShadowRoot)
|
|
374
|
-
e.unshift({ selector:
|
|
385
|
+
e.unshift({ selector: M(i), delimiter: " >>> " }), i = o.host;
|
|
375
386
|
else {
|
|
376
387
|
const s = (r = o.defaultView) == null ? void 0 : r.frameElement;
|
|
377
388
|
if (s)
|
|
378
|
-
e.unshift({ selector:
|
|
389
|
+
e.unshift({ selector: M(i), delimiter: " >>>iframe> " }), i = s;
|
|
379
390
|
else {
|
|
380
|
-
e.unshift({ selector:
|
|
391
|
+
e.unshift({ selector: M(i), delimiter: "" });
|
|
381
392
|
break;
|
|
382
393
|
}
|
|
383
394
|
}
|
|
384
395
|
}
|
|
385
396
|
const n = e.map((o, s) => (s === 0 ? "" : o.delimiter) + o.selector).join("");
|
|
386
|
-
return
|
|
397
|
+
return W.set(t, n), n;
|
|
387
398
|
}
|
|
388
|
-
function
|
|
399
|
+
function bi(t) {
|
|
389
400
|
const a = [], e = [];
|
|
390
401
|
let i = t;
|
|
391
402
|
for (; i; ) {
|
|
@@ -418,11 +429,11 @@ function ja(t) {
|
|
|
418
429
|
}
|
|
419
430
|
return null;
|
|
420
431
|
}
|
|
421
|
-
function
|
|
432
|
+
function u(t) {
|
|
422
433
|
const a = t.outerHTML;
|
|
423
434
|
return a.length > 200 ? a.slice(0, 200) + "..." : a;
|
|
424
435
|
}
|
|
425
|
-
const
|
|
436
|
+
const Te = /* @__PURE__ */ new Set([
|
|
426
437
|
"aria-activedescendant",
|
|
427
438
|
"aria-atomic",
|
|
428
439
|
"aria-autocomplete",
|
|
@@ -476,7 +487,7 @@ const fe = /* @__PURE__ */ new Set([
|
|
|
476
487
|
"aria-valuemin",
|
|
477
488
|
"aria-valuenow",
|
|
478
489
|
"aria-valuetext"
|
|
479
|
-
]),
|
|
490
|
+
]), U = /* @__PURE__ */ new Set([
|
|
480
491
|
"aria-atomic",
|
|
481
492
|
"aria-busy",
|
|
482
493
|
"aria-disabled",
|
|
@@ -487,7 +498,7 @@ const fe = /* @__PURE__ */ new Set([
|
|
|
487
498
|
"aria-multiselectable",
|
|
488
499
|
"aria-readonly",
|
|
489
500
|
"aria-required"
|
|
490
|
-
]),
|
|
501
|
+
]), G = /* @__PURE__ */ new Set(["aria-checked", "aria-pressed"]), Le = /* @__PURE__ */ new Set([
|
|
491
502
|
"aria-colcount",
|
|
492
503
|
"aria-colindex",
|
|
493
504
|
"aria-colspan",
|
|
@@ -497,12 +508,13 @@ const fe = /* @__PURE__ */ new Set([
|
|
|
497
508
|
"aria-rowindex",
|
|
498
509
|
"aria-rowspan",
|
|
499
510
|
"aria-setsize"
|
|
500
|
-
]),
|
|
511
|
+
]), Ce = /* @__PURE__ */ new Set([
|
|
501
512
|
"aria-valuemax",
|
|
502
513
|
"aria-valuemin",
|
|
503
514
|
"aria-valuenow"
|
|
504
|
-
]),
|
|
515
|
+
]), X = {
|
|
505
516
|
"aria-autocomplete": /* @__PURE__ */ new Set(["inline", "list", "both", "none"]),
|
|
517
|
+
"aria-expanded": /* @__PURE__ */ new Set(["true", "false", "undefined"]),
|
|
506
518
|
"aria-current": /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"]),
|
|
507
519
|
"aria-dropeffect": /* @__PURE__ */ new Set(["copy", "execute", "link", "move", "none", "popup"]),
|
|
508
520
|
"aria-haspopup": /* @__PURE__ */ new Set(["true", "false", "menu", "listbox", "tree", "grid", "dialog"]),
|
|
@@ -511,7 +523,7 @@ const fe = /* @__PURE__ */ new Set([
|
|
|
511
523
|
"aria-orientation": /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]),
|
|
512
524
|
"aria-relevant": /* @__PURE__ */ new Set(["additions", "all", "removals", "text"]),
|
|
513
525
|
"aria-sort": /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"])
|
|
514
|
-
},
|
|
526
|
+
}, Y = /* @__PURE__ */ new Set([
|
|
515
527
|
"caption",
|
|
516
528
|
"code",
|
|
517
529
|
"deletion",
|
|
@@ -528,7 +540,7 @@ const fe = /* @__PURE__ */ new Set([
|
|
|
528
540
|
"suggestion",
|
|
529
541
|
"term",
|
|
530
542
|
"time"
|
|
531
|
-
]),
|
|
543
|
+
]), qe = {
|
|
532
544
|
abbr: !0,
|
|
533
545
|
bdi: !0,
|
|
534
546
|
bdo: !0,
|
|
@@ -556,7 +568,7 @@ const fe = /* @__PURE__ */ new Set([
|
|
|
556
568
|
u: !0,
|
|
557
569
|
var: !0,
|
|
558
570
|
wbr: !0
|
|
559
|
-
},
|
|
571
|
+
}, Re = {
|
|
560
572
|
alert: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
|
|
561
573
|
article: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
|
|
562
574
|
banner: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
|
|
@@ -589,183 +601,185 @@ const fe = /* @__PURE__ */ new Set([
|
|
|
589
601
|
time: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
|
|
590
602
|
tooltip: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"])
|
|
591
603
|
};
|
|
592
|
-
let
|
|
593
|
-
function
|
|
594
|
-
|
|
604
|
+
let E = null, T = null;
|
|
605
|
+
function Ne() {
|
|
606
|
+
E = null, T = null;
|
|
595
607
|
}
|
|
596
|
-
function
|
|
608
|
+
function V(t) {
|
|
597
609
|
var n;
|
|
598
|
-
if (
|
|
610
|
+
if (T && (E == null ? void 0 : E.deref()) === t) return T;
|
|
599
611
|
const a = [], e = [], i = [];
|
|
600
612
|
for (const r of t.querySelectorAll("*")) {
|
|
601
613
|
let o = !1;
|
|
602
|
-
for (const
|
|
603
|
-
if (
|
|
614
|
+
for (const l of r.attributes)
|
|
615
|
+
if (l.name.startsWith("aria-")) {
|
|
604
616
|
o = !0;
|
|
605
617
|
break;
|
|
606
618
|
}
|
|
607
619
|
if (!o) continue;
|
|
608
|
-
let s,
|
|
609
|
-
const h = () => (s === void 0 && (s =
|
|
610
|
-
for (const
|
|
611
|
-
if (
|
|
612
|
-
const
|
|
620
|
+
let s, c;
|
|
621
|
+
const h = () => (s === void 0 && (s = d(r), c = u(r)), { selector: s, html: c });
|
|
622
|
+
for (const l of r.attributes)
|
|
623
|
+
if (l.name.startsWith("aria-") && !Te.has(l.name)) {
|
|
624
|
+
const m = h();
|
|
613
625
|
a.push({
|
|
614
626
|
ruleId: "aria-valid-attr",
|
|
615
|
-
selector:
|
|
616
|
-
html:
|
|
627
|
+
selector: m.selector,
|
|
628
|
+
html: m.html,
|
|
617
629
|
impact: "critical",
|
|
618
|
-
message: `Invalid ARIA attribute "${
|
|
630
|
+
message: `Invalid ARIA attribute "${l.name}".`
|
|
619
631
|
});
|
|
620
632
|
break;
|
|
621
633
|
}
|
|
622
|
-
for (const
|
|
623
|
-
if (!
|
|
624
|
-
const
|
|
625
|
-
if (
|
|
626
|
-
if (
|
|
627
|
-
|
|
628
|
-
|
|
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 (we.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 (ye.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 (V[d.name]) {
|
|
670
|
-
const g = p.split(/\s+/);
|
|
671
|
-
for (const f of g)
|
|
672
|
-
if (!V[d.name].has(f)) {
|
|
673
|
-
const v = h();
|
|
634
|
+
for (const l of r.attributes) {
|
|
635
|
+
if (!l.name.startsWith("aria-")) continue;
|
|
636
|
+
const m = l.value.trim();
|
|
637
|
+
if (!(m === "" && !U.has(l.name) && !G.has(l.name))) {
|
|
638
|
+
if (U.has(l.name)) {
|
|
639
|
+
if (m !== "true" && m !== "false") {
|
|
640
|
+
const g = h();
|
|
674
641
|
e.push({
|
|
675
642
|
ruleId: "aria-valid-attr-value",
|
|
676
|
-
selector:
|
|
677
|
-
html:
|
|
643
|
+
selector: g.selector,
|
|
644
|
+
html: g.html,
|
|
678
645
|
impact: "critical",
|
|
679
|
-
message:
|
|
646
|
+
message: `${l.name} must be "true" or "false", got "${m}".`
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
} else if (G.has(l.name)) {
|
|
650
|
+
if (m !== "true" && m !== "false" && m !== "mixed") {
|
|
651
|
+
const g = h();
|
|
652
|
+
e.push({
|
|
653
|
+
ruleId: "aria-valid-attr-value",
|
|
654
|
+
selector: g.selector,
|
|
655
|
+
html: g.html,
|
|
656
|
+
impact: "critical",
|
|
657
|
+
message: `${l.name} must be "true", "false", or "mixed", got "${m}".`
|
|
680
658
|
});
|
|
681
|
-
break;
|
|
682
659
|
}
|
|
660
|
+
} else if (Le.has(l.name)) {
|
|
661
|
+
if (m === "" || !/^-?\d+$/.test(m)) {
|
|
662
|
+
const g = h();
|
|
663
|
+
e.push({
|
|
664
|
+
ruleId: "aria-valid-attr-value",
|
|
665
|
+
selector: g.selector,
|
|
666
|
+
html: g.html,
|
|
667
|
+
impact: "critical",
|
|
668
|
+
message: `${l.name} must be an integer, got "${m}".`
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
} else if (Ce.has(l.name)) {
|
|
672
|
+
if (m === "" || isNaN(Number(m))) {
|
|
673
|
+
const g = h();
|
|
674
|
+
e.push({
|
|
675
|
+
ruleId: "aria-valid-attr-value",
|
|
676
|
+
selector: g.selector,
|
|
677
|
+
html: g.html,
|
|
678
|
+
impact: "critical",
|
|
679
|
+
message: `${l.name} must be a number, got "${m}".`
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
} else if (X[l.name]) {
|
|
683
|
+
const g = m.split(/\s+/);
|
|
684
|
+
for (const b of g)
|
|
685
|
+
if (!X[l.name].has(b)) {
|
|
686
|
+
const f = h();
|
|
687
|
+
e.push({
|
|
688
|
+
ruleId: "aria-valid-attr-value",
|
|
689
|
+
selector: f.selector,
|
|
690
|
+
html: f.html,
|
|
691
|
+
impact: "critical",
|
|
692
|
+
message: `Invalid value "${m}" for ${l.name}.`
|
|
693
|
+
});
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
683
697
|
}
|
|
684
698
|
}
|
|
685
|
-
if (!
|
|
686
|
-
const
|
|
687
|
-
if (!
|
|
688
|
-
const g = r.hasAttribute("aria-label"),
|
|
689
|
-
if (g ||
|
|
690
|
-
const
|
|
699
|
+
if (!p(r)) {
|
|
700
|
+
const l = (n = r.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase(), m = r.tagName.toLowerCase();
|
|
701
|
+
if (!l && qe[m]) {
|
|
702
|
+
const g = r.hasAttribute("aria-label"), b = r.hasAttribute("aria-labelledby");
|
|
703
|
+
if (g || b) {
|
|
704
|
+
const f = h();
|
|
691
705
|
i.push({
|
|
692
706
|
ruleId: "aria-prohibited-attr",
|
|
693
|
-
selector:
|
|
694
|
-
html:
|
|
707
|
+
selector: f.selector,
|
|
708
|
+
html: f.html,
|
|
695
709
|
impact: "serious",
|
|
696
|
-
message: `aria-label and aria-labelledby are prohibited on <${
|
|
710
|
+
message: `aria-label and aria-labelledby are prohibited on <${m}> elements.`
|
|
697
711
|
});
|
|
698
712
|
}
|
|
699
|
-
} else if (
|
|
700
|
-
if (
|
|
701
|
-
const
|
|
702
|
-
if (
|
|
713
|
+
} else if (l) {
|
|
714
|
+
if (Y.has(l)) {
|
|
715
|
+
const b = r.hasAttribute("aria-label"), f = r.hasAttribute("aria-labelledby");
|
|
716
|
+
if (b || f) {
|
|
703
717
|
const w = h();
|
|
704
718
|
i.push({
|
|
705
719
|
ruleId: "aria-prohibited-attr",
|
|
706
720
|
selector: w.selector,
|
|
707
721
|
html: w.html,
|
|
708
722
|
impact: "serious",
|
|
709
|
-
message: `aria-label and aria-labelledby are prohibited on role "${
|
|
723
|
+
message: `aria-label and aria-labelledby are prohibited on role "${l}".`
|
|
710
724
|
});
|
|
711
725
|
}
|
|
712
726
|
}
|
|
713
|
-
const g =
|
|
727
|
+
const g = Re[l];
|
|
714
728
|
if (g) {
|
|
715
|
-
for (const
|
|
716
|
-
if (
|
|
717
|
-
if ((
|
|
729
|
+
for (const b of r.attributes)
|
|
730
|
+
if (b.name.startsWith("aria-") && g.has(b.name)) {
|
|
731
|
+
if ((b.name === "aria-label" || b.name === "aria-labelledby") && Y.has(l))
|
|
718
732
|
continue;
|
|
719
|
-
const
|
|
733
|
+
const f = h();
|
|
720
734
|
i.push({
|
|
721
735
|
ruleId: "aria-prohibited-attr",
|
|
722
|
-
selector:
|
|
723
|
-
html:
|
|
736
|
+
selector: f.selector,
|
|
737
|
+
html: f.html,
|
|
724
738
|
impact: "serious",
|
|
725
|
-
message: `Attribute "${
|
|
739
|
+
message: `Attribute "${b.name}" is prohibited on role "${l}".`
|
|
726
740
|
});
|
|
727
741
|
}
|
|
728
742
|
}
|
|
729
743
|
}
|
|
730
744
|
}
|
|
731
745
|
}
|
|
732
|
-
return
|
|
746
|
+
return E = new WeakRef(t), T = { validAttr: a, validAttrValue: e, prohibitedAttr: i }, T;
|
|
733
747
|
}
|
|
734
|
-
let
|
|
735
|
-
function
|
|
736
|
-
|
|
748
|
+
let _ = /* @__PURE__ */ new WeakMap(), F = /* @__PURE__ */ new WeakMap(), j = /* @__PURE__ */ new WeakMap();
|
|
749
|
+
function Me() {
|
|
750
|
+
_ = /* @__PURE__ */ new WeakMap(), F = /* @__PURE__ */ new WeakMap(), j = /* @__PURE__ */ new WeakMap();
|
|
737
751
|
}
|
|
738
|
-
function
|
|
739
|
-
let a =
|
|
740
|
-
return a || (a = getComputedStyle(t),
|
|
752
|
+
function A(t) {
|
|
753
|
+
let a = _.get(t);
|
|
754
|
+
return a || (a = getComputedStyle(t), _.set(t, a), a);
|
|
741
755
|
}
|
|
742
|
-
function
|
|
756
|
+
function q(t, a, e) {
|
|
743
757
|
const [i, n, r] = [t, a, e].map((o) => {
|
|
744
758
|
const s = o / 255;
|
|
745
759
|
return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
746
760
|
});
|
|
747
761
|
return 0.2126 * i + 0.7152 * n + 0.0722 * r;
|
|
748
762
|
}
|
|
749
|
-
function
|
|
763
|
+
function ce(t, a) {
|
|
750
764
|
const e = Math.max(t, a), i = Math.min(t, a);
|
|
751
765
|
return (e + 0.05) / (i + 0.05);
|
|
752
766
|
}
|
|
753
|
-
function
|
|
767
|
+
function R(t) {
|
|
754
768
|
const a = t.match(
|
|
755
769
|
/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*[\d.]+)?\s*\)/
|
|
756
770
|
);
|
|
757
771
|
return a ? [parseInt(a[1]), parseInt(a[2]), parseInt(a[3])] : null;
|
|
758
772
|
}
|
|
759
|
-
function
|
|
760
|
-
const a =
|
|
773
|
+
function $e(t) {
|
|
774
|
+
const a = F.get(t);
|
|
761
775
|
if (a !== void 0) return a;
|
|
762
|
-
const e =
|
|
763
|
-
return
|
|
776
|
+
const e = He(t);
|
|
777
|
+
return F.set(t, e), e;
|
|
764
778
|
}
|
|
765
|
-
function
|
|
779
|
+
function He(t) {
|
|
766
780
|
let a = t;
|
|
767
781
|
for (; a; ) {
|
|
768
|
-
const e =
|
|
782
|
+
const e = A(a), i = e.backgroundImage;
|
|
769
783
|
if (i && i !== "none" && i !== "initial") return null;
|
|
770
784
|
const n = e.backgroundColor;
|
|
771
785
|
if (n === "transparent" || n === "rgba(0, 0, 0, 0)") {
|
|
@@ -777,26 +791,26 @@ function Te(t) {
|
|
|
777
791
|
a = a.parentElement;
|
|
778
792
|
continue;
|
|
779
793
|
}
|
|
780
|
-
return
|
|
794
|
+
return R(n);
|
|
781
795
|
}
|
|
782
796
|
return [255, 255, 255];
|
|
783
797
|
}
|
|
784
|
-
const
|
|
785
|
-
function
|
|
786
|
-
const a =
|
|
798
|
+
const De = /* @__PURE__ */ new Set(["IMG", "PICTURE", "VIDEO", "SVG"]);
|
|
799
|
+
function Oe(t) {
|
|
800
|
+
const a = j.get(t);
|
|
787
801
|
if (a !== void 0) return a;
|
|
788
|
-
const e =
|
|
789
|
-
return
|
|
802
|
+
const e = Be(t);
|
|
803
|
+
return j.set(t, e), e;
|
|
790
804
|
}
|
|
791
|
-
function
|
|
805
|
+
function Be(t) {
|
|
792
806
|
let a = t, e = !1;
|
|
793
807
|
for (; a; ) {
|
|
794
|
-
const i =
|
|
808
|
+
const i = A(a).position;
|
|
795
809
|
if ((i === "absolute" || i === "fixed") && (e = !0), a !== t && i !== "static") {
|
|
796
810
|
for (const n of a.children)
|
|
797
|
-
if (!(n === t || n.contains(t)) &&
|
|
811
|
+
if (!(n === t || n.contains(t)) && De.has(n.tagName)) {
|
|
798
812
|
if (e) return !0;
|
|
799
|
-
const r =
|
|
813
|
+
const r = A(n).position;
|
|
800
814
|
if (r === "absolute" || r === "fixed") return !0;
|
|
801
815
|
}
|
|
802
816
|
if (e) break;
|
|
@@ -805,11 +819,11 @@ function Re(t) {
|
|
|
805
819
|
}
|
|
806
820
|
return !1;
|
|
807
821
|
}
|
|
808
|
-
function
|
|
809
|
-
const a =
|
|
822
|
+
function We(t) {
|
|
823
|
+
const a = A(t), e = parseFloat(a.fontSize), i = parseInt(a.fontWeight) || (a.fontWeight === "bold" ? 700 : 400);
|
|
810
824
|
return e >= 24 || e >= 18.66 && i >= 700;
|
|
811
825
|
}
|
|
812
|
-
function
|
|
826
|
+
function $(t) {
|
|
813
827
|
var r, o;
|
|
814
828
|
const a = [], e = t.closest("a");
|
|
815
829
|
if (e) {
|
|
@@ -823,13 +837,21 @@ function Me(t) {
|
|
|
823
837
|
}
|
|
824
838
|
const n = t.parentElement;
|
|
825
839
|
if (n && n !== e) {
|
|
826
|
-
const s = (o = n.textContent) == null ? void 0 : o.replace(
|
|
827
|
-
|
|
840
|
+
const s = t instanceof HTMLImageElement && t.alt || "", c = (o = n.textContent) == null ? void 0 : o.replace(s, "").trim().slice(0, 100);
|
|
841
|
+
c && a.push(`Adjacent text: ${c}`);
|
|
828
842
|
}
|
|
829
843
|
return a.length > 0 ? a.join(`
|
|
830
844
|
`) : void 0;
|
|
831
845
|
}
|
|
832
|
-
|
|
846
|
+
function K(t) {
|
|
847
|
+
let a = t;
|
|
848
|
+
for (; a; ) {
|
|
849
|
+
if (a instanceof HTMLElement && a.style.visibility === "hidden") return !0;
|
|
850
|
+
a = a.parentElement;
|
|
851
|
+
}
|
|
852
|
+
return !1;
|
|
853
|
+
}
|
|
854
|
+
const _e = {
|
|
833
855
|
id: "img-alt",
|
|
834
856
|
wcag: ["1.1.1"],
|
|
835
857
|
level: "A",
|
|
@@ -838,18 +860,64 @@ const $e = {
|
|
|
838
860
|
prompt: "Describe what alt text to add. If the image appears decorative based on context (spacer, background, icon next to text that already describes it), recommend alt=''. Otherwise suggest descriptive alt text based on the src or surrounding context.",
|
|
839
861
|
run(t) {
|
|
840
862
|
const a = [];
|
|
841
|
-
for (const e of t.querySelectorAll("img"))
|
|
842
|
-
|
|
863
|
+
for (const e of t.querySelectorAll("img")) {
|
|
864
|
+
if (p(e) || K(e)) continue;
|
|
865
|
+
const i = e.getAttribute("role");
|
|
866
|
+
if (i === "presentation" || i === "none") {
|
|
867
|
+
const r = e.getAttribute("tabindex");
|
|
868
|
+
if (!r || r === "-1") continue;
|
|
869
|
+
}
|
|
870
|
+
const n = e.getAttribute("alt");
|
|
871
|
+
if (n !== null && n.trim() === "" && n !== "") {
|
|
872
|
+
a.push({
|
|
873
|
+
ruleId: "img-alt",
|
|
874
|
+
selector: d(e),
|
|
875
|
+
html: u(e),
|
|
876
|
+
impact: "critical",
|
|
877
|
+
message: 'Image has whitespace-only alt text. Use alt="" for decorative images or provide descriptive text.',
|
|
878
|
+
context: $(e)
|
|
879
|
+
});
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
!e.hasAttribute("alt") && !v(e) && a.push({
|
|
843
883
|
ruleId: "img-alt",
|
|
844
|
-
selector:
|
|
845
|
-
html:
|
|
884
|
+
selector: d(e),
|
|
885
|
+
html: u(e),
|
|
846
886
|
impact: "critical",
|
|
847
887
|
message: "Image element missing alt attribute.",
|
|
848
|
-
context:
|
|
888
|
+
context: $(e)
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
for (const e of t.querySelectorAll('[role="img"]:not(img):not(svg)'))
|
|
892
|
+
p(e) || K(e) || v(e) || a.push({
|
|
893
|
+
ruleId: "img-alt",
|
|
894
|
+
selector: d(e),
|
|
895
|
+
html: u(e),
|
|
896
|
+
impact: "critical",
|
|
897
|
+
message: 'Element with role="img" has no accessible name. Add aria-label or aria-labelledby.',
|
|
898
|
+
context: $(e)
|
|
849
899
|
});
|
|
850
900
|
return a;
|
|
851
901
|
}
|
|
852
|
-
}
|
|
902
|
+
};
|
|
903
|
+
function Fe(t) {
|
|
904
|
+
var r, o, s;
|
|
905
|
+
const a = t.getAttribute("aria-labelledby");
|
|
906
|
+
if (a) {
|
|
907
|
+
const c = a.split(/\s+/).map((h) => {
|
|
908
|
+
var l, m;
|
|
909
|
+
return ((m = (l = t.ownerDocument.getElementById(h)) == null ? void 0 : l.textContent) == null ? void 0 : m.trim()) ?? "";
|
|
910
|
+
}).filter(Boolean);
|
|
911
|
+
if (c.length) return c.join(" ");
|
|
912
|
+
}
|
|
913
|
+
const e = (r = t.getAttribute("aria-label")) == null ? void 0 : r.trim();
|
|
914
|
+
if (e) return e;
|
|
915
|
+
const i = t.querySelector("title");
|
|
916
|
+
if ((o = i == null ? void 0 : i.textContent) != null && o.trim()) return i.textContent.trim();
|
|
917
|
+
const n = (s = t.getAttribute("title")) == null ? void 0 : s.trim();
|
|
918
|
+
return n || "";
|
|
919
|
+
}
|
|
920
|
+
const je = {
|
|
853
921
|
id: "svg-img-alt",
|
|
854
922
|
wcag: ["1.1.1"],
|
|
855
923
|
level: "A",
|
|
@@ -857,20 +925,23 @@ const $e = {
|
|
|
857
925
|
guidance: "Inline SVGs with role='img' need accessible names. Add a <title> element as the first child of the SVG (screen readers will announce it), or use aria-label on the SVG element. For complex SVGs, use aria-labelledby referencing both a <title> and <desc> element. Decorative SVGs should use aria-hidden='true' instead.",
|
|
858
926
|
prompt: "Based on the SVG content or context, suggest either adding aria-label with a description, or if decorative, replacing role='img' with aria-hidden='true'.",
|
|
859
927
|
run(t) {
|
|
860
|
-
const a = [];
|
|
861
|
-
for (const
|
|
862
|
-
if (
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
928
|
+
const a = [], e = 'svg[role="img"], [role="graphics-document"], [role="graphics-symbol"]';
|
|
929
|
+
for (const i of t.querySelectorAll(e)) {
|
|
930
|
+
if (p(i)) continue;
|
|
931
|
+
if (!Fe(i)) {
|
|
932
|
+
const r = i.getAttribute("role");
|
|
933
|
+
a.push({
|
|
934
|
+
ruleId: "svg-img-alt",
|
|
935
|
+
selector: d(i),
|
|
936
|
+
html: u(i),
|
|
937
|
+
impact: "serious",
|
|
938
|
+
message: `${i.tagName.toLowerCase()} with role='${r}' has no accessible name.`
|
|
939
|
+
});
|
|
940
|
+
}
|
|
870
941
|
}
|
|
871
942
|
return a;
|
|
872
943
|
}
|
|
873
|
-
},
|
|
944
|
+
}, Pe = {
|
|
874
945
|
id: "input-image-alt",
|
|
875
946
|
wcag: ["1.1.1", "4.1.2"],
|
|
876
947
|
level: "A",
|
|
@@ -880,16 +951,16 @@ const $e = {
|
|
|
880
951
|
run(t) {
|
|
881
952
|
const a = [];
|
|
882
953
|
for (const e of t.querySelectorAll('input[type="image"]'))
|
|
883
|
-
|
|
954
|
+
p(e) || v(e) || a.push({
|
|
884
955
|
ruleId: "input-image-alt",
|
|
885
|
-
selector:
|
|
886
|
-
html:
|
|
956
|
+
selector: d(e),
|
|
957
|
+
html: u(e),
|
|
887
958
|
impact: "critical",
|
|
888
959
|
message: "Image input missing alt text."
|
|
889
960
|
});
|
|
890
961
|
return a;
|
|
891
962
|
}
|
|
892
|
-
},
|
|
963
|
+
}, Ve = {
|
|
893
964
|
id: "image-redundant-alt",
|
|
894
965
|
wcag: [],
|
|
895
966
|
level: "A",
|
|
@@ -908,8 +979,8 @@ const $e = {
|
|
|
908
979
|
const o = ((e = r.textContent) == null ? void 0 : e.trim().toLowerCase()) || "";
|
|
909
980
|
o && o === n && a.push({
|
|
910
981
|
ruleId: "image-redundant-alt",
|
|
911
|
-
selector:
|
|
912
|
-
html:
|
|
982
|
+
selector: d(i),
|
|
983
|
+
html: u(i),
|
|
913
984
|
impact: "minor",
|
|
914
985
|
message: `Alt text "${i.getAttribute("alt")}" duplicates surrounding ${r.tagName.toLowerCase()} text.`
|
|
915
986
|
});
|
|
@@ -917,7 +988,7 @@ const $e = {
|
|
|
917
988
|
}
|
|
918
989
|
return a;
|
|
919
990
|
}
|
|
920
|
-
},
|
|
991
|
+
}, ze = ["image", "picture", "photo", "graphic", "icon", "img"], Ue = {
|
|
921
992
|
id: "image-alt-redundant-words",
|
|
922
993
|
wcag: [],
|
|
923
994
|
level: "A",
|
|
@@ -929,17 +1000,17 @@ const $e = {
|
|
|
929
1000
|
const a = [];
|
|
930
1001
|
for (const e of t.querySelectorAll("img[alt]")) {
|
|
931
1002
|
const i = e.getAttribute("alt").toLowerCase();
|
|
932
|
-
i &&
|
|
1003
|
+
i && ze.some((n) => i.split(/\s+/).includes(n)) && a.push({
|
|
933
1004
|
ruleId: "image-alt-redundant-words",
|
|
934
|
-
selector:
|
|
935
|
-
html:
|
|
1005
|
+
selector: d(e),
|
|
1006
|
+
html: u(e),
|
|
936
1007
|
impact: "minor",
|
|
937
1008
|
message: `Alt text "${e.getAttribute("alt")}" contains redundant word(s).`
|
|
938
1009
|
});
|
|
939
1010
|
}
|
|
940
1011
|
return a;
|
|
941
1012
|
}
|
|
942
|
-
},
|
|
1013
|
+
}, Ge = {
|
|
943
1014
|
id: "area-alt",
|
|
944
1015
|
wcag: ["1.1.1", "4.1.2"],
|
|
945
1016
|
level: "A",
|
|
@@ -949,37 +1020,70 @@ const $e = {
|
|
|
949
1020
|
run(t) {
|
|
950
1021
|
const a = [];
|
|
951
1022
|
for (const e of t.querySelectorAll("area[href]")) {
|
|
952
|
-
if (
|
|
953
|
-
|
|
1023
|
+
if (p(e)) continue;
|
|
1024
|
+
v(e) || a.push({
|
|
954
1025
|
ruleId: "area-alt",
|
|
955
|
-
selector:
|
|
956
|
-
html:
|
|
1026
|
+
selector: d(e),
|
|
1027
|
+
html: u(e),
|
|
957
1028
|
impact: "critical",
|
|
958
1029
|
message: "Image map <area> element is missing alternative text."
|
|
959
1030
|
});
|
|
960
1031
|
}
|
|
961
1032
|
return a;
|
|
962
1033
|
}
|
|
963
|
-
}
|
|
1034
|
+
};
|
|
1035
|
+
function Xe(t) {
|
|
1036
|
+
var n, r;
|
|
1037
|
+
const a = t.getAttribute("aria-labelledby");
|
|
1038
|
+
if (a) {
|
|
1039
|
+
const o = a.split(/\s+/).map((s) => {
|
|
1040
|
+
var c, h;
|
|
1041
|
+
return ((h = (c = t.ownerDocument.getElementById(s)) == null ? void 0 : c.textContent) == null ? void 0 : h.trim()) ?? "";
|
|
1042
|
+
}).filter(Boolean);
|
|
1043
|
+
if (o.length) return o.join(" ");
|
|
1044
|
+
}
|
|
1045
|
+
const e = (n = t.getAttribute("aria-label")) == null ? void 0 : n.trim();
|
|
1046
|
+
if (e) return e;
|
|
1047
|
+
const i = (r = t.getAttribute("title")) == null ? void 0 : r.trim();
|
|
1048
|
+
return i || "";
|
|
1049
|
+
}
|
|
1050
|
+
const Ye = {
|
|
964
1051
|
id: "object-alt",
|
|
965
1052
|
wcag: ["1.1.1"],
|
|
966
1053
|
level: "A",
|
|
967
1054
|
description: "<object> elements must have alternative text.",
|
|
968
|
-
guidance: "Object elements embed external content that may not be accessible to all users. Provide alternative text via aria-label, aria-labelledby, or fallback content inside
|
|
969
|
-
prompt: "Based on the data/type attributes, suggest adding aria-label or
|
|
1055
|
+
guidance: "Object elements embed external content that may not be accessible to all users. Provide alternative text via aria-label, aria-labelledby, or a title attribute. The fallback content inside <object> is only shown when the object fails to load and does not serve as an accessible name.",
|
|
1056
|
+
prompt: "Based on the data/type attributes, suggest adding aria-label or a title attribute describing what the embedded content represents.",
|
|
970
1057
|
run(t) {
|
|
1058
|
+
var e;
|
|
971
1059
|
const a = [];
|
|
972
|
-
for (const
|
|
973
|
-
|
|
1060
|
+
for (const i of t.querySelectorAll("object")) {
|
|
1061
|
+
if (p(i) || i instanceof HTMLElement && i.style.visibility === "hidden") continue;
|
|
1062
|
+
let n = i.parentElement, r = !1;
|
|
1063
|
+
for (; n; ) {
|
|
1064
|
+
if (n instanceof HTMLElement && n.style.visibility === "hidden") {
|
|
1065
|
+
r = !0;
|
|
1066
|
+
break;
|
|
1067
|
+
}
|
|
1068
|
+
n = n.parentElement;
|
|
1069
|
+
}
|
|
1070
|
+
if (r || i.getAttribute("role") === "presentation" || i.getAttribute("role") === "none" || Xe(i)) continue;
|
|
1071
|
+
const o = i.getAttribute("data") || "";
|
|
1072
|
+
if (!((i.getAttribute("type") || "").startsWith("image/") || /\.(png|jpg|jpeg|gif|svg|webp|bmp|ico)$/i.test(o))) {
|
|
1073
|
+
const h = i.querySelector("img[alt]");
|
|
1074
|
+
if (h && ((e = h.getAttribute("alt")) != null && e.trim())) continue;
|
|
1075
|
+
}
|
|
1076
|
+
a.push({
|
|
974
1077
|
ruleId: "object-alt",
|
|
975
|
-
selector:
|
|
976
|
-
html:
|
|
1078
|
+
selector: d(i),
|
|
1079
|
+
html: u(i),
|
|
977
1080
|
impact: "serious",
|
|
978
|
-
message: "<object> element is missing alternative text. Add aria-label, aria-labelledby, or
|
|
1081
|
+
message: "<object> element is missing alternative text. Add aria-label, aria-labelledby, or a title attribute."
|
|
979
1082
|
});
|
|
1083
|
+
}
|
|
980
1084
|
return a;
|
|
981
1085
|
}
|
|
982
|
-
},
|
|
1086
|
+
}, Ke = {
|
|
983
1087
|
id: "role-img-alt",
|
|
984
1088
|
wcag: ["1.1.1"],
|
|
985
1089
|
level: "A",
|
|
@@ -989,11 +1093,11 @@ const $e = {
|
|
|
989
1093
|
run(t) {
|
|
990
1094
|
const a = [];
|
|
991
1095
|
for (const e of t.querySelectorAll('[role="img"]')) {
|
|
992
|
-
if (
|
|
993
|
-
|
|
1096
|
+
if (p(e) || e.tagName.toLowerCase() === "svg" || e.tagName.toLowerCase() === "img") continue;
|
|
1097
|
+
v(e) || a.push({
|
|
994
1098
|
ruleId: "role-img-alt",
|
|
995
|
-
selector:
|
|
996
|
-
html:
|
|
1099
|
+
selector: d(e),
|
|
1100
|
+
html: u(e),
|
|
997
1101
|
impact: "serious",
|
|
998
1102
|
message: "Element with role='img' has no accessible name. Add aria-label or aria-labelledby."
|
|
999
1103
|
});
|
|
@@ -1001,7 +1105,7 @@ const $e = {
|
|
|
1001
1105
|
return a;
|
|
1002
1106
|
}
|
|
1003
1107
|
};
|
|
1004
|
-
function
|
|
1108
|
+
function fi(t) {
|
|
1005
1109
|
if (typeof t != "object" || t === null)
|
|
1006
1110
|
return "Rule spec must be an object";
|
|
1007
1111
|
const a = t;
|
|
@@ -1031,10 +1135,10 @@ function za(t) {
|
|
|
1031
1135
|
return "Rule must have a wcag array";
|
|
1032
1136
|
if (typeof a.level != "string" || !["A", "AA"].includes(a.level))
|
|
1033
1137
|
return "Rule must have level A or AA";
|
|
1034
|
-
const n =
|
|
1138
|
+
const n = Qe(e);
|
|
1035
1139
|
return n || null;
|
|
1036
1140
|
}
|
|
1037
|
-
function
|
|
1141
|
+
function Qe(t) {
|
|
1038
1142
|
switch (t.type) {
|
|
1039
1143
|
case "selector-exists":
|
|
1040
1144
|
return null;
|
|
@@ -1052,7 +1156,7 @@ function Ve(t) {
|
|
|
1052
1156
|
return `Unknown check type: ${String(t.type)}`;
|
|
1053
1157
|
}
|
|
1054
1158
|
}
|
|
1055
|
-
function
|
|
1159
|
+
function x(t, a, e) {
|
|
1056
1160
|
let i = t;
|
|
1057
1161
|
if (i.includes("{{tag}}") && (i = i.replace(/\{\{tag\}\}/g, a.tagName.toLowerCase())), i.includes("{{value}}")) {
|
|
1058
1162
|
let n = "";
|
|
@@ -1075,12 +1179,12 @@ function k(t) {
|
|
|
1075
1179
|
switch (t.check.type) {
|
|
1076
1180
|
case "selector-exists": {
|
|
1077
1181
|
for (const n of e.querySelectorAll(t.selector))
|
|
1078
|
-
a &&
|
|
1182
|
+
a && p(n) || i.push({
|
|
1079
1183
|
ruleId: t.id,
|
|
1080
|
-
selector:
|
|
1081
|
-
html:
|
|
1184
|
+
selector: d(n),
|
|
1185
|
+
html: u(n),
|
|
1082
1186
|
impact: t.impact,
|
|
1083
|
-
message:
|
|
1187
|
+
message: x(t.message, n, t.check),
|
|
1084
1188
|
element: n
|
|
1085
1189
|
});
|
|
1086
1190
|
break;
|
|
@@ -1088,14 +1192,14 @@ function k(t) {
|
|
|
1088
1192
|
case "attribute-value": {
|
|
1089
1193
|
const { attribute: n, operator: r, value: o } = t.check;
|
|
1090
1194
|
for (const s of e.querySelectorAll(t.selector)) {
|
|
1091
|
-
if (a &&
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1195
|
+
if (a && p(s)) continue;
|
|
1196
|
+
const c = s.getAttribute(n);
|
|
1197
|
+
c !== null && Je(c, r, o) && i.push({
|
|
1094
1198
|
ruleId: t.id,
|
|
1095
|
-
selector:
|
|
1096
|
-
html:
|
|
1199
|
+
selector: d(s),
|
|
1200
|
+
html: u(s),
|
|
1097
1201
|
impact: t.impact,
|
|
1098
|
-
message:
|
|
1202
|
+
message: x(t.message, s, t.check),
|
|
1099
1203
|
element: s
|
|
1100
1204
|
});
|
|
1101
1205
|
}
|
|
@@ -1104,42 +1208,42 @@ function k(t) {
|
|
|
1104
1208
|
case "attribute-missing": {
|
|
1105
1209
|
const { attribute: n } = t.check;
|
|
1106
1210
|
for (const r of e.querySelectorAll(t.selector))
|
|
1107
|
-
a &&
|
|
1211
|
+
a && p(r) || r.hasAttribute(n) || i.push({
|
|
1108
1212
|
ruleId: t.id,
|
|
1109
|
-
selector:
|
|
1110
|
-
html:
|
|
1213
|
+
selector: d(r),
|
|
1214
|
+
html: u(r),
|
|
1111
1215
|
impact: t.impact,
|
|
1112
|
-
message:
|
|
1216
|
+
message: x(t.message, r, t.check),
|
|
1113
1217
|
element: r
|
|
1114
1218
|
});
|
|
1115
1219
|
break;
|
|
1116
1220
|
}
|
|
1117
1221
|
case "attribute-regex": {
|
|
1118
1222
|
const { attribute: n, pattern: r, flags: o, shouldMatch: s } = t.check;
|
|
1119
|
-
let
|
|
1223
|
+
let c;
|
|
1120
1224
|
try {
|
|
1121
|
-
|
|
1225
|
+
c = new RegExp(r, o);
|
|
1122
1226
|
} catch {
|
|
1123
1227
|
break;
|
|
1124
1228
|
}
|
|
1125
1229
|
for (const h of e.querySelectorAll(t.selector)) {
|
|
1126
|
-
if (a &&
|
|
1127
|
-
const
|
|
1128
|
-
if (
|
|
1129
|
-
const
|
|
1130
|
-
s && !
|
|
1230
|
+
if (a && p(h)) continue;
|
|
1231
|
+
const l = h.getAttribute(n);
|
|
1232
|
+
if (l === null) continue;
|
|
1233
|
+
const m = c.test(l);
|
|
1234
|
+
s && !m ? i.push({
|
|
1131
1235
|
ruleId: t.id,
|
|
1132
|
-
selector:
|
|
1133
|
-
html:
|
|
1236
|
+
selector: d(h),
|
|
1237
|
+
html: u(h),
|
|
1134
1238
|
impact: t.impact,
|
|
1135
|
-
message:
|
|
1239
|
+
message: x(t.message, h, t.check),
|
|
1136
1240
|
element: h
|
|
1137
|
-
}) : !s &&
|
|
1241
|
+
}) : !s && m && i.push({
|
|
1138
1242
|
ruleId: t.id,
|
|
1139
|
-
selector:
|
|
1140
|
-
html:
|
|
1243
|
+
selector: d(h),
|
|
1244
|
+
html: u(h),
|
|
1141
1245
|
impact: t.impact,
|
|
1142
|
-
message:
|
|
1246
|
+
message: x(t.message, h, t.check),
|
|
1143
1247
|
element: h
|
|
1144
1248
|
});
|
|
1145
1249
|
}
|
|
@@ -1148,12 +1252,12 @@ function k(t) {
|
|
|
1148
1252
|
case "child-required": {
|
|
1149
1253
|
const { childSelector: n } = t.check;
|
|
1150
1254
|
for (const r of e.querySelectorAll(t.selector))
|
|
1151
|
-
a &&
|
|
1255
|
+
a && p(r) || r.querySelector(n) || i.push({
|
|
1152
1256
|
ruleId: t.id,
|
|
1153
|
-
selector:
|
|
1154
|
-
html:
|
|
1257
|
+
selector: d(r),
|
|
1258
|
+
html: u(r),
|
|
1155
1259
|
impact: t.impact,
|
|
1156
|
-
message:
|
|
1260
|
+
message: x(t.message, r, t.check),
|
|
1157
1261
|
element: r
|
|
1158
1262
|
});
|
|
1159
1263
|
break;
|
|
@@ -1163,15 +1267,15 @@ function k(t) {
|
|
|
1163
1267
|
t.check.allowedChildren.map((r) => r.toLowerCase())
|
|
1164
1268
|
);
|
|
1165
1269
|
for (const r of e.querySelectorAll(t.selector))
|
|
1166
|
-
if (!(a &&
|
|
1270
|
+
if (!(a && p(r))) {
|
|
1167
1271
|
for (const o of r.children)
|
|
1168
1272
|
if (!n.has(o.tagName.toLowerCase())) {
|
|
1169
1273
|
i.push({
|
|
1170
1274
|
ruleId: t.id,
|
|
1171
|
-
selector:
|
|
1172
|
-
html:
|
|
1275
|
+
selector: d(o),
|
|
1276
|
+
html: u(o),
|
|
1173
1277
|
impact: t.impact,
|
|
1174
|
-
message:
|
|
1278
|
+
message: x(t.message, o, t.check),
|
|
1175
1279
|
element: o
|
|
1176
1280
|
});
|
|
1177
1281
|
break;
|
|
@@ -1184,7 +1288,7 @@ function k(t) {
|
|
|
1184
1288
|
}
|
|
1185
1289
|
};
|
|
1186
1290
|
}
|
|
1187
|
-
function
|
|
1291
|
+
function Je(t, a, e) {
|
|
1188
1292
|
switch (a) {
|
|
1189
1293
|
case ">":
|
|
1190
1294
|
return parseFloat(t) > e;
|
|
@@ -1202,7 +1306,7 @@ function Ue(t, a, e) {
|
|
|
1202
1306
|
return !1;
|
|
1203
1307
|
}
|
|
1204
1308
|
}
|
|
1205
|
-
const
|
|
1309
|
+
const Ze = {
|
|
1206
1310
|
id: "server-side-image-map",
|
|
1207
1311
|
selector: "img[ismap], input[type='image'][ismap]",
|
|
1208
1312
|
check: { type: "selector-exists" },
|
|
@@ -1213,7 +1317,70 @@ const je = {
|
|
|
1213
1317
|
level: "A",
|
|
1214
1318
|
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.",
|
|
1215
1319
|
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."
|
|
1216
|
-
},
|
|
1320
|
+
}, et = k(Ze), tt = [
|
|
1321
|
+
'[role="checkbox"]',
|
|
1322
|
+
'[role="combobox"]',
|
|
1323
|
+
'[role="listbox"]',
|
|
1324
|
+
'[role="menuitemcheckbox"]',
|
|
1325
|
+
'[role="menuitemradio"]',
|
|
1326
|
+
'[role="radio"]',
|
|
1327
|
+
'[role="searchbox"]',
|
|
1328
|
+
'[role="slider"]',
|
|
1329
|
+
'[role="spinbutton"]',
|
|
1330
|
+
'[role="switch"]',
|
|
1331
|
+
'[role="textbox"]'
|
|
1332
|
+
].join(", "), at = /* @__PURE__ */ new Set([
|
|
1333
|
+
"checkbox",
|
|
1334
|
+
"menuitemcheckbox",
|
|
1335
|
+
"menuitemradio",
|
|
1336
|
+
"radio",
|
|
1337
|
+
"switch"
|
|
1338
|
+
]), it = /* @__PURE__ */ new Set([
|
|
1339
|
+
"combobox",
|
|
1340
|
+
"listbox",
|
|
1341
|
+
"searchbox",
|
|
1342
|
+
"slider",
|
|
1343
|
+
"spinbutton",
|
|
1344
|
+
"textbox"
|
|
1345
|
+
]);
|
|
1346
|
+
function nt(t) {
|
|
1347
|
+
var o, s, c, h;
|
|
1348
|
+
const a = (o = t.getAttribute("role")) == null ? void 0 : o.trim().toLowerCase();
|
|
1349
|
+
if (a && at.has(a) || (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) && !(a && it.has(a)))
|
|
1350
|
+
return v(t);
|
|
1351
|
+
const i = t.getAttribute("aria-labelledby");
|
|
1352
|
+
if (i) {
|
|
1353
|
+
const l = i.split(/\s+/).map((m) => {
|
|
1354
|
+
const g = t.ownerDocument.getElementById(m);
|
|
1355
|
+
return g ? y(g).trim() : "";
|
|
1356
|
+
}).filter(Boolean);
|
|
1357
|
+
if (l.length) return l.join(" ");
|
|
1358
|
+
}
|
|
1359
|
+
const n = (s = t.getAttribute("aria-label")) == null ? void 0 : s.trim();
|
|
1360
|
+
if (n) return n;
|
|
1361
|
+
if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) {
|
|
1362
|
+
if (t.id) {
|
|
1363
|
+
const m = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`);
|
|
1364
|
+
if (m) {
|
|
1365
|
+
const g = y(m).trim();
|
|
1366
|
+
if (g) return g;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
const l = t.closest("label");
|
|
1370
|
+
if (l) {
|
|
1371
|
+
const m = y(l).trim();
|
|
1372
|
+
if (m) return m;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
const r = (c = t.getAttribute("title")) == null ? void 0 : c.trim();
|
|
1376
|
+
if (r) return r;
|
|
1377
|
+
if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) {
|
|
1378
|
+
const l = (h = t.getAttribute("placeholder")) == null ? void 0 : h.trim();
|
|
1379
|
+
if (l) return l;
|
|
1380
|
+
}
|
|
1381
|
+
return "";
|
|
1382
|
+
}
|
|
1383
|
+
const rt = {
|
|
1217
1384
|
id: "label",
|
|
1218
1385
|
wcag: ["4.1.2"],
|
|
1219
1386
|
level: "A",
|
|
@@ -1221,22 +1388,23 @@ const je = {
|
|
|
1221
1388
|
guidance: "Every form input needs an accessible label so users understand what information to enter. Use a <label> element with a for attribute matching the input's id, wrap the input in a <label>, or use aria-label/aria-labelledby for custom components. Placeholders are not sufficient as labels since they disappear when typing.",
|
|
1222
1389
|
prompt: "Based on the input type, name attribute, or placeholder, suggest a label element with appropriate text, or an aria-label.",
|
|
1223
1390
|
run(t) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
)
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1391
|
+
var n;
|
|
1392
|
+
const a = [], i = t.querySelectorAll(`input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select, ${tt}`);
|
|
1393
|
+
for (const r of i) {
|
|
1394
|
+
if (p(r) || r instanceof HTMLElement && (r.hidden || r.style.display === "none")) continue;
|
|
1395
|
+
const o = (n = r.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase();
|
|
1396
|
+
if (o === "presentation" || o === "none") continue;
|
|
1397
|
+
nt(r) || a.push({
|
|
1230
1398
|
ruleId: "label",
|
|
1231
|
-
selector:
|
|
1232
|
-
html:
|
|
1399
|
+
selector: d(r),
|
|
1400
|
+
html: u(r),
|
|
1233
1401
|
impact: "critical",
|
|
1234
1402
|
message: "Form element has no accessible label."
|
|
1235
1403
|
});
|
|
1236
1404
|
}
|
|
1237
1405
|
return a;
|
|
1238
1406
|
}
|
|
1239
|
-
},
|
|
1407
|
+
}, ot = {
|
|
1240
1408
|
id: "form-field-multiple-labels",
|
|
1241
1409
|
wcag: [],
|
|
1242
1410
|
level: "A",
|
|
@@ -1247,7 +1415,7 @@ const je = {
|
|
|
1247
1415
|
run(t) {
|
|
1248
1416
|
const a = [], e = t.querySelectorAll('input:not([type="hidden"]), textarea, select');
|
|
1249
1417
|
for (const i of e) {
|
|
1250
|
-
if (
|
|
1418
|
+
if (p(i) || !i.id) continue;
|
|
1251
1419
|
const n = t.querySelectorAll(`label[for="${CSS.escape(i.id)}"]`);
|
|
1252
1420
|
let r = 0, o = i.parentElement;
|
|
1253
1421
|
for (; o; ) {
|
|
@@ -1260,15 +1428,15 @@ const je = {
|
|
|
1260
1428
|
const s = n.length + r;
|
|
1261
1429
|
s > 1 && a.push({
|
|
1262
1430
|
ruleId: "form-field-multiple-labels",
|
|
1263
|
-
selector:
|
|
1264
|
-
html:
|
|
1431
|
+
selector: d(i),
|
|
1432
|
+
html: u(i),
|
|
1265
1433
|
impact: "moderate",
|
|
1266
1434
|
message: `Form field has ${s} labels. Use a single label element.`
|
|
1267
1435
|
});
|
|
1268
1436
|
}
|
|
1269
1437
|
return a;
|
|
1270
1438
|
}
|
|
1271
|
-
},
|
|
1439
|
+
}, st = {
|
|
1272
1440
|
id: "select-name",
|
|
1273
1441
|
wcag: ["4.1.2"],
|
|
1274
1442
|
level: "A",
|
|
@@ -1278,16 +1446,16 @@ const je = {
|
|
|
1278
1446
|
run(t) {
|
|
1279
1447
|
const a = [];
|
|
1280
1448
|
for (const e of t.querySelectorAll("select"))
|
|
1281
|
-
|
|
1449
|
+
p(e) || v(e) || a.push({
|
|
1282
1450
|
ruleId: "select-name",
|
|
1283
|
-
selector:
|
|
1284
|
-
html:
|
|
1451
|
+
selector: d(e),
|
|
1452
|
+
html: u(e),
|
|
1285
1453
|
impact: "critical",
|
|
1286
1454
|
message: "Select element has no accessible name."
|
|
1287
1455
|
});
|
|
1288
1456
|
return a;
|
|
1289
1457
|
}
|
|
1290
|
-
},
|
|
1458
|
+
}, lt = {
|
|
1291
1459
|
id: "input-button-name",
|
|
1292
1460
|
wcag: ["4.1.2"],
|
|
1293
1461
|
level: "A",
|
|
@@ -1300,19 +1468,19 @@ const je = {
|
|
|
1300
1468
|
for (const n of t.querySelectorAll(
|
|
1301
1469
|
'input[type="submit"], input[type="button"], input[type="reset"]'
|
|
1302
1470
|
)) {
|
|
1303
|
-
if (
|
|
1471
|
+
if (p(n)) continue;
|
|
1304
1472
|
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");
|
|
1305
|
-
!r && !s && !
|
|
1473
|
+
!r && !s && !v(n) && a.push({
|
|
1306
1474
|
ruleId: "input-button-name",
|
|
1307
|
-
selector:
|
|
1308
|
-
html:
|
|
1475
|
+
selector: d(n),
|
|
1476
|
+
html: u(n),
|
|
1309
1477
|
impact: "critical",
|
|
1310
1478
|
message: "Input button has no discernible text."
|
|
1311
1479
|
});
|
|
1312
1480
|
}
|
|
1313
1481
|
return a;
|
|
1314
1482
|
}
|
|
1315
|
-
},
|
|
1483
|
+
}, ct = /* @__PURE__ */ new Set([
|
|
1316
1484
|
"off",
|
|
1317
1485
|
"on",
|
|
1318
1486
|
"name",
|
|
@@ -1367,7 +1535,27 @@ const je = {
|
|
|
1367
1535
|
"impp",
|
|
1368
1536
|
"url",
|
|
1369
1537
|
"photo"
|
|
1370
|
-
]),
|
|
1538
|
+
]), ut = /* @__PURE__ */ new Set([
|
|
1539
|
+
"tel",
|
|
1540
|
+
"tel-country-code",
|
|
1541
|
+
"tel-national",
|
|
1542
|
+
"tel-area-code",
|
|
1543
|
+
"tel-local",
|
|
1544
|
+
"tel-extension",
|
|
1545
|
+
"email",
|
|
1546
|
+
"impp"
|
|
1547
|
+
]), dt = /* @__PURE__ */ new Set(["home", "work", "mobile", "fax", "pager"]), mt = /* @__PURE__ */ new Set(["shipping", "billing"]), ht = /* @__PURE__ */ new Set(["webauthn"]);
|
|
1548
|
+
function pt(t) {
|
|
1549
|
+
const a = t.toLowerCase().split(/\s+/).filter(Boolean);
|
|
1550
|
+
if (a.length === 0) return !0;
|
|
1551
|
+
let e = 0;
|
|
1552
|
+
a[e].startsWith("section-") && e++, e < a.length && mt.has(a[e]) && e++;
|
|
1553
|
+
let i = !1;
|
|
1554
|
+
if (e < a.length && dt.has(a[e]) && (i = !0, e++), e >= a.length) return !1;
|
|
1555
|
+
const n = a[e];
|
|
1556
|
+
return !ct.has(n) || i && !ut.has(n) ? !1 : (e++, e < a.length && ht.has(a[e]) && e++, e === a.length);
|
|
1557
|
+
}
|
|
1558
|
+
const gt = {
|
|
1371
1559
|
id: "autocomplete-valid",
|
|
1372
1560
|
wcag: ["1.3.5"],
|
|
1373
1561
|
level: "AA",
|
|
@@ -1377,30 +1565,29 @@ const je = {
|
|
|
1377
1565
|
run(t) {
|
|
1378
1566
|
const a = [];
|
|
1379
1567
|
for (const e of t.querySelectorAll("[autocomplete]")) {
|
|
1568
|
+
if (p(e) || e instanceof HTMLElement && e.style.display === "none" || e.disabled || e.getAttribute("aria-disabled") === "true") continue;
|
|
1380
1569
|
const i = e.getAttribute("autocomplete").trim();
|
|
1381
|
-
|
|
1382
|
-
const n = i.split(/\s+/), r = n[n.length - 1];
|
|
1383
|
-
Qe.has(r) || a.push({
|
|
1570
|
+
i && (pt(i) || a.push({
|
|
1384
1571
|
ruleId: "autocomplete-valid",
|
|
1385
|
-
selector:
|
|
1386
|
-
html:
|
|
1572
|
+
selector: d(e),
|
|
1573
|
+
html: u(e),
|
|
1387
1574
|
impact: "serious",
|
|
1388
1575
|
message: `Invalid autocomplete value "${i}".`
|
|
1389
|
-
});
|
|
1576
|
+
}));
|
|
1390
1577
|
}
|
|
1391
1578
|
return a;
|
|
1392
1579
|
}
|
|
1393
1580
|
};
|
|
1394
|
-
function
|
|
1581
|
+
function Q(t) {
|
|
1395
1582
|
return t.toLowerCase().replace(/\s+/g, " ").trim();
|
|
1396
1583
|
}
|
|
1397
|
-
function
|
|
1398
|
-
const e =
|
|
1584
|
+
function J(t, a) {
|
|
1585
|
+
const e = Q(t), i = Q(a);
|
|
1399
1586
|
if (!e || !i || e.includes(i) || i.includes(e)) return !0;
|
|
1400
1587
|
const n = i.split(/\s+/).map((r) => r.replace(/[.,;:!?\u2026]+$/g, "")).filter((r) => r.length > 2);
|
|
1401
1588
|
return n.length >= 2 && n.filter((o) => e.includes(o)).length / n.length > 0.5;
|
|
1402
1589
|
}
|
|
1403
|
-
function
|
|
1590
|
+
function P(t) {
|
|
1404
1591
|
let a = "";
|
|
1405
1592
|
for (const e of t.childNodes)
|
|
1406
1593
|
if (e.nodeType === 3)
|
|
@@ -1410,11 +1597,11 @@ function F(t) {
|
|
|
1410
1597
|
if (n === "style" || n === "script" || n === "svg" || i.getAttribute("aria-hidden") === "true" || i instanceof HTMLElement && i.style.display === "none") continue;
|
|
1411
1598
|
const r = i.getAttribute("role");
|
|
1412
1599
|
if (r === "img" || r === "presentation" || r === "none") continue;
|
|
1413
|
-
a +=
|
|
1600
|
+
a += P(i);
|
|
1414
1601
|
}
|
|
1415
1602
|
return a;
|
|
1416
1603
|
}
|
|
1417
|
-
const
|
|
1604
|
+
const bt = {
|
|
1418
1605
|
id: "label-content-name-mismatch",
|
|
1419
1606
|
wcag: ["2.5.3"],
|
|
1420
1607
|
level: "A",
|
|
@@ -1424,43 +1611,43 @@ const Ze = {
|
|
|
1424
1611
|
run(t) {
|
|
1425
1612
|
const a = [];
|
|
1426
1613
|
for (const e of t.querySelectorAll('button, [role="button"], a[href], input[type="submit"], input[type="button"]')) {
|
|
1427
|
-
if (
|
|
1428
|
-
const i =
|
|
1614
|
+
if (p(e)) continue;
|
|
1615
|
+
const i = v(e);
|
|
1429
1616
|
if (!i) continue;
|
|
1430
1617
|
let n = "";
|
|
1431
|
-
e instanceof HTMLInputElement ? n = e.value || "" : n =
|
|
1618
|
+
e instanceof HTMLInputElement ? n = e.value || "" : n = P(e);
|
|
1432
1619
|
const r = n.trim();
|
|
1433
1620
|
if (!r || r.length <= 2) continue;
|
|
1434
1621
|
const o = e.hasAttribute("aria-label"), s = e.hasAttribute("aria-labelledby");
|
|
1435
|
-
!o && !s ||
|
|
1622
|
+
!o && !s || J(i, n) || a.push({
|
|
1436
1623
|
ruleId: "label-content-name-mismatch",
|
|
1437
|
-
selector:
|
|
1438
|
-
html:
|
|
1624
|
+
selector: d(e),
|
|
1625
|
+
html: u(e),
|
|
1439
1626
|
impact: "serious",
|
|
1440
1627
|
message: `Accessible name "${i}" does not contain visible text "${n.trim()}".`
|
|
1441
1628
|
});
|
|
1442
1629
|
}
|
|
1443
1630
|
for (const e of t.querySelectorAll("input, select, textarea")) {
|
|
1444
|
-
if (
|
|
1445
|
-
const i =
|
|
1631
|
+
if (p(e) || e instanceof HTMLInputElement && ["hidden", "submit", "button", "image"].includes(e.type)) continue;
|
|
1632
|
+
const i = v(e);
|
|
1446
1633
|
if (!i || !e.hasAttribute("aria-label")) continue;
|
|
1447
1634
|
const r = e.id;
|
|
1448
1635
|
let o = "";
|
|
1449
1636
|
if (r) {
|
|
1450
1637
|
const s = t.querySelector(`label[for="${CSS.escape(r)}"]`);
|
|
1451
|
-
s && (o =
|
|
1638
|
+
s && (o = P(s));
|
|
1452
1639
|
}
|
|
1453
|
-
o.trim() && (
|
|
1640
|
+
o.trim() && (J(i, o) || a.push({
|
|
1454
1641
|
ruleId: "label-content-name-mismatch",
|
|
1455
|
-
selector:
|
|
1456
|
-
html:
|
|
1642
|
+
selector: d(e),
|
|
1643
|
+
html: u(e),
|
|
1457
1644
|
impact: "serious",
|
|
1458
1645
|
message: `Accessible name "${i}" does not contain visible label "${o.trim()}".`
|
|
1459
1646
|
}));
|
|
1460
1647
|
}
|
|
1461
1648
|
return a;
|
|
1462
1649
|
}
|
|
1463
|
-
},
|
|
1650
|
+
}, ft = {
|
|
1464
1651
|
id: "label-title-only",
|
|
1465
1652
|
wcag: [],
|
|
1466
1653
|
level: "A",
|
|
@@ -1474,26 +1661,26 @@ const Ze = {
|
|
|
1474
1661
|
'input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select'
|
|
1475
1662
|
);
|
|
1476
1663
|
for (const s of e) {
|
|
1477
|
-
if (
|
|
1478
|
-
const
|
|
1479
|
-
let
|
|
1664
|
+
if (p(s)) continue;
|
|
1665
|
+
const c = 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()), l = s.hasAttribute("aria-labelledby");
|
|
1666
|
+
let m = !1;
|
|
1480
1667
|
const g = s.id;
|
|
1481
1668
|
if (g) {
|
|
1482
|
-
const
|
|
1483
|
-
(r =
|
|
1669
|
+
const f = s.ownerDocument.querySelector(`label[for="${CSS.escape(g)}"]`);
|
|
1670
|
+
(r = f == null ? void 0 : f.textContent) != null && r.trim() && (m = !0);
|
|
1484
1671
|
}
|
|
1485
|
-
const
|
|
1486
|
-
(o =
|
|
1672
|
+
const b = s.closest("label");
|
|
1673
|
+
(o = b == null ? void 0 : b.textContent) != null && o.trim() && (m = !0), c && !h && !l && !m && a.push({
|
|
1487
1674
|
ruleId: "label-title-only",
|
|
1488
|
-
selector:
|
|
1489
|
-
html:
|
|
1675
|
+
selector: d(s),
|
|
1676
|
+
html: u(s),
|
|
1490
1677
|
impact: "serious",
|
|
1491
1678
|
message: "Form element uses title attribute as only label. Use <label>, aria-label, or aria-labelledby instead."
|
|
1492
1679
|
});
|
|
1493
1680
|
}
|
|
1494
1681
|
return a;
|
|
1495
1682
|
}
|
|
1496
|
-
},
|
|
1683
|
+
}, vt = {
|
|
1497
1684
|
id: "tabindex",
|
|
1498
1685
|
selector: "[tabindex]",
|
|
1499
1686
|
check: { type: "attribute-value", attribute: "tabindex", operator: ">", value: 0 },
|
|
@@ -1505,7 +1692,7 @@ const Ze = {
|
|
|
1505
1692
|
tags: ["best-practice"],
|
|
1506
1693
|
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.",
|
|
1507
1694
|
prompt: "Change the positive tabindex value to tabindex='0' and rely on DOM order for tab sequence instead."
|
|
1508
|
-
},
|
|
1695
|
+
}, wt = k(vt), yt = /* @__PURE__ */ new Set([
|
|
1509
1696
|
"div",
|
|
1510
1697
|
"span",
|
|
1511
1698
|
"p",
|
|
@@ -1532,7 +1719,7 @@ const Ze = {
|
|
|
1532
1719
|
"tr",
|
|
1533
1720
|
"td",
|
|
1534
1721
|
"th"
|
|
1535
|
-
]),
|
|
1722
|
+
]), At = {
|
|
1536
1723
|
id: "focus-order-semantics",
|
|
1537
1724
|
wcag: [],
|
|
1538
1725
|
tags: ["best-practice"],
|
|
@@ -1544,18 +1731,18 @@ const Ze = {
|
|
|
1544
1731
|
const a = [];
|
|
1545
1732
|
for (const e of t.querySelectorAll('[tabindex="0"]')) {
|
|
1546
1733
|
const i = e.tagName.toLowerCase();
|
|
1547
|
-
if (!
|
|
1734
|
+
if (!yt.has(i)) continue;
|
|
1548
1735
|
e.getAttribute("role") || a.push({
|
|
1549
1736
|
ruleId: "focus-order-semantics",
|
|
1550
|
-
selector:
|
|
1551
|
-
html:
|
|
1737
|
+
selector: d(e),
|
|
1738
|
+
html: u(e),
|
|
1552
1739
|
impact: "moderate",
|
|
1553
1740
|
message: `Non-interactive <${i}> with tabindex="0" has no interactive role.`
|
|
1554
1741
|
});
|
|
1555
1742
|
}
|
|
1556
1743
|
return a;
|
|
1557
1744
|
}
|
|
1558
|
-
},
|
|
1745
|
+
}, St = /* @__PURE__ */ new Set([
|
|
1559
1746
|
"a",
|
|
1560
1747
|
"audio",
|
|
1561
1748
|
"button",
|
|
@@ -1564,7 +1751,7 @@ const Ze = {
|
|
|
1564
1751
|
"select",
|
|
1565
1752
|
"textarea",
|
|
1566
1753
|
"video"
|
|
1567
|
-
]),
|
|
1754
|
+
]), xt = /* @__PURE__ */ new Set([
|
|
1568
1755
|
"button",
|
|
1569
1756
|
"checkbox",
|
|
1570
1757
|
"combobox",
|
|
@@ -1588,7 +1775,7 @@ const Ze = {
|
|
|
1588
1775
|
"tabpanel",
|
|
1589
1776
|
"textbox",
|
|
1590
1777
|
"treeitem"
|
|
1591
|
-
]),
|
|
1778
|
+
]), kt = {
|
|
1592
1779
|
grid: /* @__PURE__ */ new Set(["gridcell", "row", "columnheader", "rowheader"]),
|
|
1593
1780
|
listbox: /* @__PURE__ */ new Set(["option"]),
|
|
1594
1781
|
menu: /* @__PURE__ */ new Set(["menuitem", "menuitemcheckbox", "menuitemradio"]),
|
|
@@ -1598,26 +1785,26 @@ const Ze = {
|
|
|
1598
1785
|
tree: /* @__PURE__ */ new Set(["treeitem"]),
|
|
1599
1786
|
treegrid: /* @__PURE__ */ new Set(["gridcell", "row", "columnheader", "rowheader", "treeitem"])
|
|
1600
1787
|
};
|
|
1601
|
-
function
|
|
1788
|
+
function It(t, a) {
|
|
1602
1789
|
var n, r, o;
|
|
1603
1790
|
const e = (n = t.getAttribute("role")) == null ? void 0 : n.toLowerCase(), i = (r = a.getAttribute("role")) == null ? void 0 : r.toLowerCase();
|
|
1604
|
-
return !e || !i ? !1 : ((o =
|
|
1791
|
+
return !e || !i ? !1 : ((o = kt[e]) == null ? void 0 : o.has(i)) ?? !1;
|
|
1605
1792
|
}
|
|
1606
|
-
function
|
|
1793
|
+
function Et(t) {
|
|
1607
1794
|
var n;
|
|
1608
1795
|
const a = t.tagName.toLowerCase();
|
|
1609
|
-
if (
|
|
1796
|
+
if (St.has(a))
|
|
1610
1797
|
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);
|
|
1611
1798
|
const e = (n = t.getAttribute("role")) == null ? void 0 : n.toLowerCase();
|
|
1612
|
-
if (e &&
|
|
1799
|
+
if (e && xt.has(e)) return !0;
|
|
1613
1800
|
const i = t.getAttribute("tabindex");
|
|
1614
1801
|
return i !== null && i !== "-1" || t.getAttribute("contenteditable") === "true";
|
|
1615
1802
|
}
|
|
1616
|
-
function
|
|
1803
|
+
function Tt(t) {
|
|
1617
1804
|
const a = t.tagName.toLowerCase();
|
|
1618
1805
|
return !!(a === "a" && t.hasAttribute("href") || a === "button" && !t.disabled);
|
|
1619
1806
|
}
|
|
1620
|
-
const
|
|
1807
|
+
const Lt = {
|
|
1621
1808
|
id: "nested-interactive",
|
|
1622
1809
|
wcag: ["4.1.2"],
|
|
1623
1810
|
level: "A",
|
|
@@ -1632,24 +1819,24 @@ const ut = {
|
|
|
1632
1819
|
for (; o; ) {
|
|
1633
1820
|
for (; r.length > 0 && !r[r.length - 1].contains(o); )
|
|
1634
1821
|
r.pop();
|
|
1635
|
-
if (!
|
|
1822
|
+
if (!p(o) && Et(o)) {
|
|
1636
1823
|
if (r.length > 0) {
|
|
1637
1824
|
const s = r[r.length - 1];
|
|
1638
|
-
|
|
1825
|
+
It(s, o) || a.push({
|
|
1639
1826
|
ruleId: "nested-interactive",
|
|
1640
|
-
selector:
|
|
1641
|
-
html:
|
|
1827
|
+
selector: d(o),
|
|
1828
|
+
html: u(o),
|
|
1642
1829
|
impact: "serious",
|
|
1643
1830
|
message: `Interactive element <${o.tagName.toLowerCase()}> is nested inside <${s.tagName.toLowerCase()}>.`
|
|
1644
1831
|
});
|
|
1645
1832
|
}
|
|
1646
|
-
|
|
1833
|
+
Tt(o) && r.push(o);
|
|
1647
1834
|
}
|
|
1648
1835
|
o = n.nextNode();
|
|
1649
1836
|
}
|
|
1650
1837
|
return a;
|
|
1651
1838
|
}
|
|
1652
|
-
},
|
|
1839
|
+
}, Ct = {
|
|
1653
1840
|
id: "scrollable-region-focusable",
|
|
1654
1841
|
wcag: ["2.1.1"],
|
|
1655
1842
|
level: "A",
|
|
@@ -1659,23 +1846,23 @@ const ut = {
|
|
|
1659
1846
|
run(t) {
|
|
1660
1847
|
const a = [];
|
|
1661
1848
|
for (const e of t.querySelectorAll("*")) {
|
|
1662
|
-
if (
|
|
1663
|
-
const i =
|
|
1849
|
+
if (p(e) || !(e instanceof HTMLElement)) continue;
|
|
1850
|
+
const i = A(e), n = i.overflowX, r = i.overflowY;
|
|
1664
1851
|
if (!(n === "scroll" || n === "auto" || r === "scroll" || r === "auto") || !(e.scrollHeight > e.clientHeight || e.scrollWidth > e.clientWidth)) continue;
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1852
|
+
const c = e.getAttribute("tabindex");
|
|
1853
|
+
c !== null && c !== "-1" || e.querySelector(
|
|
1667
1854
|
'a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
1668
1855
|
) || a.push({
|
|
1669
1856
|
ruleId: "scrollable-region-focusable",
|
|
1670
|
-
selector:
|
|
1671
|
-
html:
|
|
1857
|
+
selector: d(e),
|
|
1858
|
+
html: u(e),
|
|
1672
1859
|
impact: "serious",
|
|
1673
1860
|
message: "Scrollable region is not keyboard accessible. Add tabindex='0' or include focusable elements."
|
|
1674
1861
|
});
|
|
1675
1862
|
}
|
|
1676
1863
|
return a;
|
|
1677
1864
|
}
|
|
1678
|
-
},
|
|
1865
|
+
}, qt = {
|
|
1679
1866
|
id: "accesskeys",
|
|
1680
1867
|
wcag: [],
|
|
1681
1868
|
level: "A",
|
|
@@ -1687,7 +1874,7 @@ const ut = {
|
|
|
1687
1874
|
var i;
|
|
1688
1875
|
const a = [], e = /* @__PURE__ */ new Map();
|
|
1689
1876
|
for (const n of t.querySelectorAll("[accesskey]")) {
|
|
1690
|
-
if (
|
|
1877
|
+
if (p(n)) continue;
|
|
1691
1878
|
const r = (i = n.getAttribute("accesskey")) == null ? void 0 : i.trim().toLowerCase();
|
|
1692
1879
|
if (!r) continue;
|
|
1693
1880
|
const o = e.get(r) || [];
|
|
@@ -1698,14 +1885,14 @@ const ut = {
|
|
|
1698
1885
|
for (const o of r.slice(1))
|
|
1699
1886
|
a.push({
|
|
1700
1887
|
ruleId: "accesskeys",
|
|
1701
|
-
selector:
|
|
1702
|
-
html:
|
|
1888
|
+
selector: d(o),
|
|
1889
|
+
html: u(o),
|
|
1703
1890
|
impact: "serious",
|
|
1704
1891
|
message: `Duplicate accesskey "${n}". Each accesskey must be unique.`
|
|
1705
1892
|
});
|
|
1706
1893
|
return a;
|
|
1707
1894
|
}
|
|
1708
|
-
},
|
|
1895
|
+
}, Rt = {
|
|
1709
1896
|
id: "heading-order",
|
|
1710
1897
|
wcag: [],
|
|
1711
1898
|
level: "A",
|
|
@@ -1717,20 +1904,20 @@ const ut = {
|
|
|
1717
1904
|
const a = [], e = t.querySelectorAll("h1, h2, h3, h4, h5, h6, [role='heading']");
|
|
1718
1905
|
let i = 0, n = null;
|
|
1719
1906
|
for (const r of e) {
|
|
1720
|
-
if (
|
|
1907
|
+
if (p(r)) continue;
|
|
1721
1908
|
let o;
|
|
1722
1909
|
r.hasAttribute("aria-level") ? o = parseInt(r.getAttribute("aria-level"), 10) : o = parseInt(r.tagName[1], 10), i > 0 && o > i + 1 && a.push({
|
|
1723
1910
|
ruleId: "heading-order",
|
|
1724
|
-
selector:
|
|
1725
|
-
html:
|
|
1911
|
+
selector: d(r),
|
|
1912
|
+
html: u(r),
|
|
1726
1913
|
impact: "moderate",
|
|
1727
1914
|
message: `Heading level ${o} skipped from level ${i}.`,
|
|
1728
|
-
context: n ? `Previous heading: ${
|
|
1915
|
+
context: n ? `Previous heading: ${u(n)}` : void 0
|
|
1729
1916
|
}), i = o, n = r;
|
|
1730
1917
|
}
|
|
1731
1918
|
return a;
|
|
1732
1919
|
}
|
|
1733
|
-
},
|
|
1920
|
+
}, N = 'article, aside, main, nav, section, [role="article"], [role="complementary"], [role="main"], [role="navigation"], [role="region"]', Z = '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"]', Nt = {
|
|
1734
1921
|
id: "landmark-one-main",
|
|
1735
1922
|
wcag: [],
|
|
1736
1923
|
level: "A",
|
|
@@ -1748,13 +1935,13 @@ const ut = {
|
|
|
1748
1935
|
message: "Page has no main landmark."
|
|
1749
1936
|
}] : a.length > 1 ? Array.from(a).slice(1).map((e) => ({
|
|
1750
1937
|
ruleId: "landmark-one-main",
|
|
1751
|
-
selector:
|
|
1752
|
-
html:
|
|
1938
|
+
selector: d(e),
|
|
1939
|
+
html: u(e),
|
|
1753
1940
|
impact: "moderate",
|
|
1754
1941
|
message: "Page has multiple main landmarks."
|
|
1755
1942
|
})) : [];
|
|
1756
1943
|
}
|
|
1757
|
-
},
|
|
1944
|
+
}, Mt = {
|
|
1758
1945
|
id: "landmark-no-duplicate-banner",
|
|
1759
1946
|
wcag: [],
|
|
1760
1947
|
level: "A",
|
|
@@ -1763,18 +1950,18 @@ const ut = {
|
|
|
1763
1950
|
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.",
|
|
1764
1951
|
prompt: "Explain whether to remove this duplicate banner or nest it inside a sectioning element.",
|
|
1765
1952
|
run(t) {
|
|
1766
|
-
const a = [], e = t.querySelectorAll('header, [role="banner"]'), i = Array.from(e).filter((n) => !n.closest(
|
|
1953
|
+
const a = [], e = t.querySelectorAll('header, [role="banner"]'), i = Array.from(e).filter((n) => !n.closest(N));
|
|
1767
1954
|
return i.length > 1 && i.slice(1).forEach(
|
|
1768
1955
|
(n) => a.push({
|
|
1769
1956
|
ruleId: "landmark-no-duplicate-banner",
|
|
1770
|
-
selector:
|
|
1771
|
-
html:
|
|
1957
|
+
selector: d(n),
|
|
1958
|
+
html: u(n),
|
|
1772
1959
|
impact: "moderate",
|
|
1773
1960
|
message: "Page has multiple banner landmarks."
|
|
1774
1961
|
})
|
|
1775
1962
|
), a;
|
|
1776
1963
|
}
|
|
1777
|
-
},
|
|
1964
|
+
}, $t = {
|
|
1778
1965
|
id: "landmark-no-duplicate-contentinfo",
|
|
1779
1966
|
wcag: [],
|
|
1780
1967
|
level: "A",
|
|
@@ -1783,18 +1970,18 @@ const ut = {
|
|
|
1783
1970
|
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.",
|
|
1784
1971
|
prompt: "Explain whether to remove this duplicate footer or nest it inside a sectioning element.",
|
|
1785
1972
|
run(t) {
|
|
1786
|
-
const a = [], e = t.querySelectorAll('footer, [role="contentinfo"]'), i = Array.from(e).filter((n) => !n.closest(
|
|
1973
|
+
const a = [], e = t.querySelectorAll('footer, [role="contentinfo"]'), i = Array.from(e).filter((n) => !n.closest(N));
|
|
1787
1974
|
return i.length > 1 && i.slice(1).forEach(
|
|
1788
1975
|
(n) => a.push({
|
|
1789
1976
|
ruleId: "landmark-no-duplicate-contentinfo",
|
|
1790
|
-
selector:
|
|
1791
|
-
html:
|
|
1977
|
+
selector: d(n),
|
|
1978
|
+
html: u(n),
|
|
1792
1979
|
impact: "moderate",
|
|
1793
1980
|
message: "Page has multiple contentinfo landmarks."
|
|
1794
1981
|
})
|
|
1795
1982
|
), a;
|
|
1796
1983
|
}
|
|
1797
|
-
},
|
|
1984
|
+
}, Ht = {
|
|
1798
1985
|
id: "landmark-no-duplicate-main",
|
|
1799
1986
|
wcag: [],
|
|
1800
1987
|
level: "A",
|
|
@@ -1807,14 +1994,14 @@ const ut = {
|
|
|
1807
1994
|
return e.length > 1 && Array.from(e).slice(1).forEach(
|
|
1808
1995
|
(i) => a.push({
|
|
1809
1996
|
ruleId: "landmark-no-duplicate-main",
|
|
1810
|
-
selector:
|
|
1811
|
-
html:
|
|
1997
|
+
selector: d(i),
|
|
1998
|
+
html: u(i),
|
|
1812
1999
|
impact: "moderate",
|
|
1813
2000
|
message: "Page has multiple main landmarks."
|
|
1814
2001
|
})
|
|
1815
2002
|
), a;
|
|
1816
2003
|
}
|
|
1817
|
-
},
|
|
2004
|
+
}, Dt = {
|
|
1818
2005
|
id: "landmark-banner-is-top-level",
|
|
1819
2006
|
wcag: [],
|
|
1820
2007
|
level: "A",
|
|
@@ -1825,16 +2012,16 @@ const ut = {
|
|
|
1825
2012
|
run(t) {
|
|
1826
2013
|
const a = [], e = t.querySelectorAll('[role="banner"]');
|
|
1827
2014
|
for (const i of e)
|
|
1828
|
-
i.closest(
|
|
2015
|
+
i.closest(N) && a.push({
|
|
1829
2016
|
ruleId: "landmark-banner-is-top-level",
|
|
1830
|
-
selector:
|
|
1831
|
-
html:
|
|
2017
|
+
selector: d(i),
|
|
2018
|
+
html: u(i),
|
|
1832
2019
|
impact: "moderate",
|
|
1833
2020
|
message: "Banner landmark is nested within another landmark."
|
|
1834
2021
|
});
|
|
1835
2022
|
return a;
|
|
1836
2023
|
}
|
|
1837
|
-
},
|
|
2024
|
+
}, Ot = {
|
|
1838
2025
|
id: "landmark-contentinfo-is-top-level",
|
|
1839
2026
|
wcag: [],
|
|
1840
2027
|
level: "A",
|
|
@@ -1845,16 +2032,16 @@ const ut = {
|
|
|
1845
2032
|
run(t) {
|
|
1846
2033
|
const a = [], e = t.querySelectorAll('[role="contentinfo"]');
|
|
1847
2034
|
for (const i of e)
|
|
1848
|
-
i.closest(
|
|
2035
|
+
i.closest(N) && a.push({
|
|
1849
2036
|
ruleId: "landmark-contentinfo-is-top-level",
|
|
1850
|
-
selector:
|
|
1851
|
-
html:
|
|
2037
|
+
selector: d(i),
|
|
2038
|
+
html: u(i),
|
|
1852
2039
|
impact: "moderate",
|
|
1853
2040
|
message: "Contentinfo landmark is nested within another landmark."
|
|
1854
2041
|
});
|
|
1855
2042
|
return a;
|
|
1856
2043
|
}
|
|
1857
|
-
},
|
|
2044
|
+
}, Bt = {
|
|
1858
2045
|
id: "landmark-main-is-top-level",
|
|
1859
2046
|
wcag: [],
|
|
1860
2047
|
level: "A",
|
|
@@ -1868,15 +2055,15 @@ const ut = {
|
|
|
1868
2055
|
const n = i.parentElement;
|
|
1869
2056
|
n != null && n.closest('article, aside, nav, section, [role="article"], [role="complementary"], [role="navigation"], [role="region"]') && a.push({
|
|
1870
2057
|
ruleId: "landmark-main-is-top-level",
|
|
1871
|
-
selector:
|
|
1872
|
-
html:
|
|
2058
|
+
selector: d(i),
|
|
2059
|
+
html: u(i),
|
|
1873
2060
|
impact: "moderate",
|
|
1874
2061
|
message: "Main landmark is nested within another landmark."
|
|
1875
2062
|
});
|
|
1876
2063
|
}
|
|
1877
2064
|
return a;
|
|
1878
2065
|
}
|
|
1879
|
-
},
|
|
2066
|
+
}, Wt = {
|
|
1880
2067
|
id: "landmark-complementary-is-top-level",
|
|
1881
2068
|
wcag: [],
|
|
1882
2069
|
level: "A",
|
|
@@ -1890,15 +2077,15 @@ const ut = {
|
|
|
1890
2077
|
const n = i.parentElement;
|
|
1891
2078
|
n && !n.matches('body, main, [role="main"]') && i.closest('article, nav, section, [role="article"], [role="navigation"], [role="region"]') && a.push({
|
|
1892
2079
|
ruleId: "landmark-complementary-is-top-level",
|
|
1893
|
-
selector:
|
|
1894
|
-
html:
|
|
2080
|
+
selector: d(i),
|
|
2081
|
+
html: u(i),
|
|
1895
2082
|
impact: "moderate",
|
|
1896
2083
|
message: "Complementary landmark should be top-level."
|
|
1897
2084
|
});
|
|
1898
2085
|
}
|
|
1899
2086
|
return a;
|
|
1900
2087
|
}
|
|
1901
|
-
},
|
|
2088
|
+
}, _t = {
|
|
1902
2089
|
id: "landmark-unique",
|
|
1903
2090
|
wcag: [],
|
|
1904
2091
|
level: "A",
|
|
@@ -1914,27 +2101,27 @@ const ut = {
|
|
|
1914
2101
|
{ selector: 'form[aria-label], form[aria-labelledby], [role="form"], [role="search"]', type: "form" }
|
|
1915
2102
|
];
|
|
1916
2103
|
for (const { selector: i, type: n } of e) {
|
|
1917
|
-
const r = Array.from(t.querySelectorAll(i)).filter((s) => !
|
|
2104
|
+
const r = Array.from(t.querySelectorAll(i)).filter((s) => !p(s));
|
|
1918
2105
|
if (r.length <= 1) continue;
|
|
1919
2106
|
const o = /* @__PURE__ */ new Map();
|
|
1920
2107
|
for (const s of r) {
|
|
1921
|
-
const
|
|
1922
|
-
h.push(s), o.set(
|
|
2108
|
+
const c = v(s).toLowerCase() || "", h = o.get(c) || [];
|
|
2109
|
+
h.push(s), o.set(c, h);
|
|
1923
2110
|
}
|
|
1924
|
-
for (const [s,
|
|
1925
|
-
if (
|
|
1926
|
-
for (const h of
|
|
2111
|
+
for (const [s, c] of o)
|
|
2112
|
+
if (c.length > 1)
|
|
2113
|
+
for (const h of c.slice(1))
|
|
1927
2114
|
a.push({
|
|
1928
2115
|
ruleId: "landmark-unique",
|
|
1929
|
-
selector:
|
|
1930
|
-
html:
|
|
2116
|
+
selector: d(h),
|
|
2117
|
+
html: u(h),
|
|
1931
2118
|
impact: "moderate",
|
|
1932
2119
|
message: s ? `Multiple ${n} landmarks have the same label "${s}".` : `Multiple ${n} landmarks have no label. Add unique aria-label attributes.`
|
|
1933
2120
|
});
|
|
1934
2121
|
}
|
|
1935
2122
|
return a;
|
|
1936
2123
|
}
|
|
1937
|
-
},
|
|
2124
|
+
}, Ft = {
|
|
1938
2125
|
id: "region",
|
|
1939
2126
|
wcag: [],
|
|
1940
2127
|
level: "A",
|
|
@@ -1947,19 +2134,19 @@ const ut = {
|
|
|
1947
2134
|
const a = [], e = t.body;
|
|
1948
2135
|
if (!e) return [];
|
|
1949
2136
|
for (const n of e.children) {
|
|
1950
|
-
if (
|
|
1951
|
-
const r = n.matches(
|
|
1952
|
-
!r && o && (n.querySelector(
|
|
2137
|
+
if (p(n) || n instanceof HTMLScriptElement || n instanceof HTMLStyleElement || n.tagName === "NOSCRIPT" || n instanceof HTMLElement && n.hidden || n.matches('a[href^="#"]')) continue;
|
|
2138
|
+
const r = n.matches(Z), o = (i = n.textContent) == null ? void 0 : i.trim();
|
|
2139
|
+
!r && o && (n.querySelector(Z) || a.push({
|
|
1953
2140
|
ruleId: "region",
|
|
1954
|
-
selector:
|
|
1955
|
-
html:
|
|
2141
|
+
selector: d(n),
|
|
2142
|
+
html: u(n),
|
|
1956
2143
|
impact: "moderate",
|
|
1957
2144
|
message: "Content is not contained within a landmark region."
|
|
1958
2145
|
}));
|
|
1959
2146
|
}
|
|
1960
2147
|
return a;
|
|
1961
2148
|
}
|
|
1962
|
-
},
|
|
2149
|
+
}, jt = {
|
|
1963
2150
|
id: "list",
|
|
1964
2151
|
selector: "ul, ol",
|
|
1965
2152
|
check: { type: "child-invalid", allowedChildren: ["li", "script", "template"] },
|
|
@@ -1970,7 +2157,7 @@ const ut = {
|
|
|
1970
2157
|
level: "A",
|
|
1971
2158
|
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.",
|
|
1972
2159
|
prompt: "Explain how to restructure this element within the list properly."
|
|
1973
|
-
},
|
|
2160
|
+
}, Pt = k(jt), Vt = {
|
|
1974
2161
|
id: "dlitem",
|
|
1975
2162
|
wcag: ["1.3.1"],
|
|
1976
2163
|
level: "A",
|
|
@@ -1982,14 +2169,14 @@ const ut = {
|
|
|
1982
2169
|
for (const e of t.querySelectorAll("dt, dd"))
|
|
1983
2170
|
(!e.parentElement || e.parentElement.tagName.toLowerCase() !== "dl") && a.push({
|
|
1984
2171
|
ruleId: "dlitem",
|
|
1985
|
-
selector:
|
|
1986
|
-
html:
|
|
2172
|
+
selector: d(e),
|
|
2173
|
+
html: u(e),
|
|
1987
2174
|
impact: "serious",
|
|
1988
2175
|
message: `<${e.tagName.toLowerCase()}> is not contained in a <dl>.`
|
|
1989
2176
|
});
|
|
1990
2177
|
return a;
|
|
1991
2178
|
}
|
|
1992
|
-
},
|
|
2179
|
+
}, zt = {
|
|
1993
2180
|
id: "definition-list",
|
|
1994
2181
|
selector: "dl",
|
|
1995
2182
|
check: { type: "child-invalid", allowedChildren: ["dt", "dd", "div", "script", "template"] },
|
|
@@ -2000,7 +2187,7 @@ const ut = {
|
|
|
2000
2187
|
level: "A",
|
|
2001
2188
|
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.",
|
|
2002
2189
|
prompt: "Explain whether to move this element outside the <dl> or convert it to dt/dd."
|
|
2003
|
-
},
|
|
2190
|
+
}, Ut = k(zt), Gt = {
|
|
2004
2191
|
id: "document-title",
|
|
2005
2192
|
wcag: ["2.4.2"],
|
|
2006
2193
|
level: "A",
|
|
@@ -2018,7 +2205,7 @@ const ut = {
|
|
|
2018
2205
|
message: a ? "Document <title> element is empty." : "Document is missing a <title> element."
|
|
2019
2206
|
}] : [];
|
|
2020
2207
|
}
|
|
2021
|
-
},
|
|
2208
|
+
}, Xt = {
|
|
2022
2209
|
id: "bypass",
|
|
2023
2210
|
wcag: ["2.4.1"],
|
|
2024
2211
|
level: "A",
|
|
@@ -2045,7 +2232,7 @@ const ut = {
|
|
|
2045
2232
|
message: "Page has no mechanism to bypass repeated content. Add a <main> landmark or skip link."
|
|
2046
2233
|
}];
|
|
2047
2234
|
}
|
|
2048
|
-
},
|
|
2235
|
+
}, Yt = {
|
|
2049
2236
|
id: "page-has-heading-one",
|
|
2050
2237
|
wcag: [],
|
|
2051
2238
|
level: "A",
|
|
@@ -2055,10 +2242,10 @@ const ut = {
|
|
|
2055
2242
|
prompt: "Suggest appropriate h1 text based on the page's visible content.",
|
|
2056
2243
|
run(t) {
|
|
2057
2244
|
const a = t.querySelector("h1");
|
|
2058
|
-
if (a &&
|
|
2245
|
+
if (a && v(a)) return [];
|
|
2059
2246
|
const e = t.querySelectorAll('[role="heading"][aria-level="1"]');
|
|
2060
2247
|
for (const i of e)
|
|
2061
|
-
if (
|
|
2248
|
+
if (v(i)) return [];
|
|
2062
2249
|
return [{
|
|
2063
2250
|
ruleId: "page-has-heading-one",
|
|
2064
2251
|
selector: "html",
|
|
@@ -2067,7 +2254,7 @@ const ut = {
|
|
|
2067
2254
|
message: "Page does not contain a level-one heading."
|
|
2068
2255
|
}];
|
|
2069
2256
|
}
|
|
2070
|
-
},
|
|
2257
|
+
}, Kt = {
|
|
2071
2258
|
id: "frame-title",
|
|
2072
2259
|
wcag: ["4.1.2"],
|
|
2073
2260
|
level: "A",
|
|
@@ -2077,18 +2264,18 @@ const ut = {
|
|
|
2077
2264
|
run(t) {
|
|
2078
2265
|
const a = [];
|
|
2079
2266
|
for (const e of t.querySelectorAll("iframe, frame")) {
|
|
2080
|
-
if (
|
|
2081
|
-
|
|
2267
|
+
if (p(e)) continue;
|
|
2268
|
+
v(e) || a.push({
|
|
2082
2269
|
ruleId: "frame-title",
|
|
2083
|
-
selector:
|
|
2084
|
-
html:
|
|
2270
|
+
selector: d(e),
|
|
2271
|
+
html: u(e),
|
|
2085
2272
|
impact: "serious",
|
|
2086
2273
|
message: "Frame is missing an accessible name. Add a title attribute."
|
|
2087
2274
|
});
|
|
2088
2275
|
}
|
|
2089
2276
|
return a;
|
|
2090
2277
|
}
|
|
2091
|
-
},
|
|
2278
|
+
}, Qt = {
|
|
2092
2279
|
id: "frame-title-unique",
|
|
2093
2280
|
wcag: ["4.1.2"],
|
|
2094
2281
|
level: "A",
|
|
@@ -2100,13 +2287,13 @@ const ut = {
|
|
|
2100
2287
|
var n;
|
|
2101
2288
|
const a = [], e = Array.from(t.querySelectorAll("iframe[title], frame[title]")), i = /* @__PURE__ */ new Map();
|
|
2102
2289
|
for (const r of e) {
|
|
2103
|
-
if (
|
|
2290
|
+
if (p(r)) continue;
|
|
2104
2291
|
const o = r.getAttribute("width"), s = r.getAttribute("height");
|
|
2105
2292
|
if (o === "0" || s === "0" || r instanceof HTMLElement && r.style.display === "none" || r instanceof HTMLElement && r.style.visibility === "hidden") continue;
|
|
2106
|
-
const
|
|
2107
|
-
if (
|
|
2108
|
-
const h = i.get(
|
|
2109
|
-
h.push(r), i.set(
|
|
2293
|
+
const c = (n = r.getAttribute("title")) == null ? void 0 : n.trim().toLowerCase();
|
|
2294
|
+
if (c) {
|
|
2295
|
+
const h = i.get(c) || [];
|
|
2296
|
+
h.push(r), i.set(c, h);
|
|
2110
2297
|
}
|
|
2111
2298
|
}
|
|
2112
2299
|
for (const [, r] of i)
|
|
@@ -2114,14 +2301,14 @@ const ut = {
|
|
|
2114
2301
|
for (const o of r.slice(1))
|
|
2115
2302
|
a.push({
|
|
2116
2303
|
ruleId: "frame-title-unique",
|
|
2117
|
-
selector:
|
|
2118
|
-
html:
|
|
2304
|
+
selector: d(o),
|
|
2305
|
+
html: u(o),
|
|
2119
2306
|
impact: "moderate",
|
|
2120
2307
|
message: "Frame title is not unique. Use a distinct title for each frame."
|
|
2121
2308
|
});
|
|
2122
2309
|
return a;
|
|
2123
2310
|
}
|
|
2124
|
-
},
|
|
2311
|
+
}, Jt = {
|
|
2125
2312
|
id: "empty-heading",
|
|
2126
2313
|
wcag: [],
|
|
2127
2314
|
level: "A",
|
|
@@ -2132,16 +2319,16 @@ const ut = {
|
|
|
2132
2319
|
run(t) {
|
|
2133
2320
|
const a = [], e = t.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"]');
|
|
2134
2321
|
for (const i of e)
|
|
2135
|
-
|
|
2322
|
+
p(i) || v(i) || a.push({
|
|
2136
2323
|
ruleId: "empty-heading",
|
|
2137
|
-
selector:
|
|
2138
|
-
html:
|
|
2324
|
+
selector: d(i),
|
|
2325
|
+
html: u(i),
|
|
2139
2326
|
impact: "minor",
|
|
2140
2327
|
message: "Heading is empty. Add text content or remove the heading element."
|
|
2141
2328
|
});
|
|
2142
2329
|
return a;
|
|
2143
2330
|
}
|
|
2144
|
-
},
|
|
2331
|
+
}, Zt = {
|
|
2145
2332
|
id: "meta-viewport",
|
|
2146
2333
|
wcag: ["1.4.4"],
|
|
2147
2334
|
level: "AA",
|
|
@@ -2155,25 +2342,25 @@ const ut = {
|
|
|
2155
2342
|
const i = ((r = e.getAttribute("content")) == null ? void 0 : r.toLowerCase()) || "";
|
|
2156
2343
|
(/user-scalable\s*=\s*no/i.test(i) || /user-scalable\s*=\s*0/i.test(i)) && a.push({
|
|
2157
2344
|
ruleId: "meta-viewport",
|
|
2158
|
-
selector:
|
|
2159
|
-
html:
|
|
2345
|
+
selector: d(e),
|
|
2346
|
+
html: u(e),
|
|
2160
2347
|
impact: "critical",
|
|
2161
2348
|
message: "Viewport disables user scaling. Remove user-scalable=no."
|
|
2162
2349
|
});
|
|
2163
|
-
const n = i.match(/maximum-scale\s*=\s*([\d.]
|
|
2350
|
+
const n = i.match(/maximum-scale\s*=\s*([\d.]+|yes)/i);
|
|
2164
2351
|
if (n) {
|
|
2165
|
-
const o =
|
|
2166
|
-
|
|
2352
|
+
const o = n[1], s = o.toLowerCase() === "yes" ? 1 : parseFloat(o);
|
|
2353
|
+
s < 2 && a.push({
|
|
2167
2354
|
ruleId: "meta-viewport",
|
|
2168
|
-
selector:
|
|
2169
|
-
html:
|
|
2355
|
+
selector: d(e),
|
|
2356
|
+
html: u(e),
|
|
2170
2357
|
impact: "critical",
|
|
2171
|
-
message: `Viewport maximum-scale=${
|
|
2358
|
+
message: `Viewport maximum-scale=${s} restricts zooming. Set to at least 2 or remove.`
|
|
2172
2359
|
});
|
|
2173
2360
|
}
|
|
2174
2361
|
return a;
|
|
2175
2362
|
}
|
|
2176
|
-
},
|
|
2363
|
+
}, ea = {
|
|
2177
2364
|
id: "meta-refresh",
|
|
2178
2365
|
wcag: ["2.2.1", "2.2.4", "3.2.5"],
|
|
2179
2366
|
level: "A",
|
|
@@ -2181,34 +2368,30 @@ const ut = {
|
|
|
2181
2368
|
guidance: "Automatic page refreshes or redirects can disorient users, especially those using screen readers or with cognitive disabilities. They may lose their place or not have time to read content. If a redirect is needed, use a server-side redirect (HTTP 301/302) instead. For timed refreshes, provide user controls.",
|
|
2182
2369
|
prompt: "Explain why meta refresh is problematic and suggest server-side alternatives.",
|
|
2183
2370
|
run(t) {
|
|
2184
|
-
const a
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
html: l(e),
|
|
2205
|
-
impact: "critical",
|
|
2206
|
-
message: `Page auto-refreshes after ${r} seconds. Provide user control over refresh.`
|
|
2207
|
-
});
|
|
2371
|
+
for (const a of t.querySelectorAll('meta[http-equiv="refresh"]')) {
|
|
2372
|
+
const e = a.getAttribute("content") || "", i = e.match(/^(\d+)/);
|
|
2373
|
+
if (!i) continue;
|
|
2374
|
+
const n = parseInt(i[1], 10);
|
|
2375
|
+
if (/^\d+\s*[;,]\s*url\s*=/i.test(e) || /^\d+\s*[;,]\s*['"]?\s*https?:/i.test(e))
|
|
2376
|
+
return n > 0 && n <= 72e3 ? [{
|
|
2377
|
+
ruleId: "meta-refresh",
|
|
2378
|
+
selector: d(a),
|
|
2379
|
+
html: u(a),
|
|
2380
|
+
impact: "critical",
|
|
2381
|
+
message: `Page redirects after ${n} seconds without warning. Use server-side redirect.`
|
|
2382
|
+
}] : [];
|
|
2383
|
+
if (n > 0 && n <= 72e3)
|
|
2384
|
+
return [{
|
|
2385
|
+
ruleId: "meta-refresh",
|
|
2386
|
+
selector: d(a),
|
|
2387
|
+
html: u(a),
|
|
2388
|
+
impact: "critical",
|
|
2389
|
+
message: `Page auto-refreshes after ${n} seconds. Provide user control over refresh.`
|
|
2390
|
+
}];
|
|
2208
2391
|
}
|
|
2209
|
-
return
|
|
2392
|
+
return [];
|
|
2210
2393
|
}
|
|
2211
|
-
},
|
|
2394
|
+
}, ta = {
|
|
2212
2395
|
id: "blink",
|
|
2213
2396
|
selector: "blink",
|
|
2214
2397
|
check: { type: "selector-exists" },
|
|
@@ -2219,7 +2402,7 @@ const ut = {
|
|
|
2219
2402
|
level: "A",
|
|
2220
2403
|
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.",
|
|
2221
2404
|
prompt: "Suggest static alternatives to the blinking effect."
|
|
2222
|
-
},
|
|
2405
|
+
}, aa = k(ta), ia = {
|
|
2223
2406
|
id: "marquee",
|
|
2224
2407
|
selector: "marquee",
|
|
2225
2408
|
check: { type: "selector-exists" },
|
|
@@ -2230,7 +2413,7 @@ const ut = {
|
|
|
2230
2413
|
level: "A",
|
|
2231
2414
|
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.",
|
|
2232
2415
|
prompt: "Suggest static alternatives or accessible carousel patterns."
|
|
2233
|
-
},
|
|
2416
|
+
}, na = k(ia), ra = {
|
|
2234
2417
|
id: "p-as-heading",
|
|
2235
2418
|
wcag: [],
|
|
2236
2419
|
level: "A",
|
|
@@ -2242,14 +2425,14 @@ const ut = {
|
|
|
2242
2425
|
var e, i;
|
|
2243
2426
|
const a = [];
|
|
2244
2427
|
for (const n of t.querySelectorAll("p")) {
|
|
2245
|
-
if (
|
|
2246
|
-
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),
|
|
2247
|
-
if ((o && s || o && h) &&
|
|
2428
|
+
if (p(n)) continue;
|
|
2429
|
+
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), c = ((e = n.className) == null ? void 0 : e.toLowerCase()) || "", h = /\bh[1-6]\b|\bheading\b/.test(c), l = ((i = n.textContent) == null ? void 0 : i.trim()) || "", m = l.length > 0 && l.length < 50, g = !l.match(/[.!?,;:]$/);
|
|
2430
|
+
if ((o && s || o && h) && m && g) {
|
|
2248
2431
|
const w = n.nextElementSibling;
|
|
2249
2432
|
w && (w.tagName === "P" || w.tagName === "DIV" || w.tagName === "UL") && a.push({
|
|
2250
2433
|
ruleId: "p-as-heading",
|
|
2251
|
-
selector:
|
|
2252
|
-
html:
|
|
2434
|
+
selector: d(n),
|
|
2435
|
+
html: u(n),
|
|
2253
2436
|
impact: "serious",
|
|
2254
2437
|
message: "Paragraph appears to be styled as a heading. Use an h1-h6 element instead."
|
|
2255
2438
|
});
|
|
@@ -2257,7 +2440,7 @@ const ut = {
|
|
|
2257
2440
|
}
|
|
2258
2441
|
return a;
|
|
2259
2442
|
}
|
|
2260
|
-
},
|
|
2443
|
+
}, oa = {
|
|
2261
2444
|
id: "aria-roles",
|
|
2262
2445
|
wcag: ["4.1.2"],
|
|
2263
2446
|
level: "A",
|
|
@@ -2267,22 +2450,18 @@ const ut = {
|
|
|
2267
2450
|
run(t) {
|
|
2268
2451
|
const a = [];
|
|
2269
2452
|
for (const e of t.querySelectorAll("[role]")) {
|
|
2270
|
-
const r = e.getAttribute("role").replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "").split(/\s+/);
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
message: `Invalid ARIA role "${o}".`
|
|
2279
|
-
});
|
|
2280
|
-
break;
|
|
2281
|
-
}
|
|
2453
|
+
const r = e.getAttribute("role").replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "").split(/\s+/).filter(Boolean);
|
|
2454
|
+
!r.some((s) => ye(s)) && r.length > 0 && a.push({
|
|
2455
|
+
ruleId: "aria-roles",
|
|
2456
|
+
selector: d(e),
|
|
2457
|
+
html: u(e),
|
|
2458
|
+
impact: "critical",
|
|
2459
|
+
message: `Invalid ARIA role "${r[0]}".`
|
|
2460
|
+
});
|
|
2282
2461
|
}
|
|
2283
2462
|
return a;
|
|
2284
2463
|
}
|
|
2285
|
-
},
|
|
2464
|
+
}, sa = {
|
|
2286
2465
|
id: "aria-valid-attr",
|
|
2287
2466
|
wcag: ["4.1.2"],
|
|
2288
2467
|
level: "A",
|
|
@@ -2290,9 +2469,9 @@ const ut = {
|
|
|
2290
2469
|
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+).",
|
|
2291
2470
|
prompt: "Identify the misspelled attribute and provide the correct spelling.",
|
|
2292
2471
|
run(t) {
|
|
2293
|
-
return
|
|
2472
|
+
return V(t).validAttr;
|
|
2294
2473
|
}
|
|
2295
|
-
},
|
|
2474
|
+
}, la = {
|
|
2296
2475
|
id: "aria-valid-attr-value",
|
|
2297
2476
|
wcag: ["4.1.2"],
|
|
2298
2477
|
level: "A",
|
|
@@ -2300,16 +2479,15 @@ const ut = {
|
|
|
2300
2479
|
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.",
|
|
2301
2480
|
prompt: "Show the invalid value and list the valid values for this specific attribute.",
|
|
2302
2481
|
run(t) {
|
|
2303
|
-
return
|
|
2482
|
+
return V(t).validAttrValue;
|
|
2304
2483
|
}
|
|
2305
|
-
},
|
|
2484
|
+
}, ca = {
|
|
2306
2485
|
checkbox: ["aria-checked"],
|
|
2307
2486
|
combobox: ["aria-expanded"],
|
|
2308
2487
|
heading: ["aria-level"],
|
|
2309
2488
|
menuitemcheckbox: ["aria-checked"],
|
|
2310
2489
|
menuitemradio: ["aria-checked"],
|
|
2311
2490
|
meter: ["aria-valuenow"],
|
|
2312
|
-
option: ["aria-selected"],
|
|
2313
2491
|
radio: ["aria-checked"],
|
|
2314
2492
|
scrollbar: ["aria-controls", "aria-valuenow"],
|
|
2315
2493
|
separator: ["aria-valuenow"],
|
|
@@ -2317,7 +2495,7 @@ const ut = {
|
|
|
2317
2495
|
slider: ["aria-valuenow"],
|
|
2318
2496
|
spinbutton: ["aria-valuenow"],
|
|
2319
2497
|
switch: ["aria-checked"]
|
|
2320
|
-
},
|
|
2498
|
+
}, ua = {
|
|
2321
2499
|
id: "aria-required-attr",
|
|
2322
2500
|
wcag: ["4.1.2"],
|
|
2323
2501
|
level: "A",
|
|
@@ -2327,7 +2505,8 @@ const ut = {
|
|
|
2327
2505
|
run(t) {
|
|
2328
2506
|
const a = [];
|
|
2329
2507
|
for (const e of t.querySelectorAll("[role]")) {
|
|
2330
|
-
|
|
2508
|
+
if (p(e) || e instanceof HTMLElement && e.style.display === "none") continue;
|
|
2509
|
+
const i = e.getAttribute("role").trim().toLowerCase(), n = ca[i];
|
|
2331
2510
|
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))) {
|
|
2332
2511
|
if (i === "separator") {
|
|
2333
2512
|
const r = e.getAttribute("tabindex");
|
|
@@ -2338,8 +2517,8 @@ const ut = {
|
|
|
2338
2517
|
if (!e.hasAttribute(r)) {
|
|
2339
2518
|
a.push({
|
|
2340
2519
|
ruleId: "aria-required-attr",
|
|
2341
|
-
selector:
|
|
2342
|
-
html:
|
|
2520
|
+
selector: d(e),
|
|
2521
|
+
html: u(e),
|
|
2343
2522
|
impact: "critical",
|
|
2344
2523
|
message: `Role "${i}" requires attribute "${r}".`
|
|
2345
2524
|
});
|
|
@@ -2351,24 +2530,24 @@ const ut = {
|
|
|
2351
2530
|
return a;
|
|
2352
2531
|
}
|
|
2353
2532
|
};
|
|
2354
|
-
function
|
|
2533
|
+
function da(t) {
|
|
2355
2534
|
var r, o, s;
|
|
2356
2535
|
const a = [], e = t.className;
|
|
2357
2536
|
e && typeof e == "string" && e.trim() && a.push(`Classes: ${e.trim().slice(0, 100)}`);
|
|
2358
2537
|
const i = t.closest("form");
|
|
2359
2538
|
if (i) {
|
|
2360
|
-
const
|
|
2361
|
-
|
|
2539
|
+
const c = i.getAttribute("aria-label") || ((o = (r = i.querySelector("legend")) == null ? void 0 : r.textContent) == null ? void 0 : o.trim());
|
|
2540
|
+
c && a.push(`Form: ${c.slice(0, 60)}`);
|
|
2362
2541
|
}
|
|
2363
2542
|
const n = t.parentElement;
|
|
2364
2543
|
if (n) {
|
|
2365
|
-
const
|
|
2366
|
-
(s =
|
|
2544
|
+
const c = n.closest("h1, h2, h3, h4, h5, h6") || n.querySelector("h1, h2, h3, h4, h5, h6");
|
|
2545
|
+
(s = c == null ? void 0 : c.textContent) != null && s.trim() && a.push(`Nearby heading: ${c.textContent.trim().slice(0, 60)}`);
|
|
2367
2546
|
}
|
|
2368
2547
|
return a.length > 0 ? a.join(`
|
|
2369
2548
|
`) : void 0;
|
|
2370
2549
|
}
|
|
2371
|
-
const
|
|
2550
|
+
const ma = {
|
|
2372
2551
|
id: "button-name",
|
|
2373
2552
|
wcag: ["4.1.2"],
|
|
2374
2553
|
level: "A",
|
|
@@ -2378,19 +2557,21 @@ const Kt = {
|
|
|
2378
2557
|
run(t) {
|
|
2379
2558
|
const a = [];
|
|
2380
2559
|
for (const e of t.querySelectorAll('button, [role="button"]')) {
|
|
2381
|
-
if (
|
|
2382
|
-
|
|
2560
|
+
if (p(e)) continue;
|
|
2561
|
+
const i = e.getAttribute("role");
|
|
2562
|
+
if ((i === "none" || i === "presentation") && !(e.matches('button:not([disabled]), [tabindex]:not([tabindex="-1"])') || e.tagName.toLowerCase() === "button" && !e.disabled) || e.getRootNode() instanceof ShadowRoot) continue;
|
|
2563
|
+
v(e) || a.push({
|
|
2383
2564
|
ruleId: "button-name",
|
|
2384
|
-
selector:
|
|
2385
|
-
html:
|
|
2565
|
+
selector: d(e),
|
|
2566
|
+
html: u(e),
|
|
2386
2567
|
impact: "critical",
|
|
2387
2568
|
message: "Button has no discernible text.",
|
|
2388
|
-
context:
|
|
2569
|
+
context: da(e)
|
|
2389
2570
|
});
|
|
2390
2571
|
}
|
|
2391
2572
|
return a;
|
|
2392
2573
|
}
|
|
2393
|
-
},
|
|
2574
|
+
}, ha = {
|
|
2394
2575
|
alert: /* @__PURE__ */ new Set(["aria-atomic", "aria-busy", "aria-live", "aria-relevant"]),
|
|
2395
2576
|
alertdialog: /* @__PURE__ */ new Set(["aria-describedby", "aria-modal"]),
|
|
2396
2577
|
application: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-disabled", "aria-errormessage", "aria-expanded", "aria-haspopup", "aria-invalid"]),
|
|
@@ -2462,7 +2643,7 @@ const Kt = {
|
|
|
2462
2643
|
tree: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-disabled", "aria-errormessage", "aria-invalid", "aria-multiselectable", "aria-orientation", "aria-required"]),
|
|
2463
2644
|
treegrid: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-colcount", "aria-disabled", "aria-errormessage", "aria-invalid", "aria-multiselectable", "aria-orientation", "aria-readonly", "aria-required", "aria-rowcount"]),
|
|
2464
2645
|
treeitem: /* @__PURE__ */ new Set(["aria-checked", "aria-disabled", "aria-expanded", "aria-haspopup", "aria-level", "aria-posinset", "aria-selected", "aria-setsize"])
|
|
2465
|
-
},
|
|
2646
|
+
}, pa = /* @__PURE__ */ new Set([
|
|
2466
2647
|
"aria-atomic",
|
|
2467
2648
|
"aria-busy",
|
|
2468
2649
|
"aria-controls",
|
|
@@ -2486,7 +2667,7 @@ const Kt = {
|
|
|
2486
2667
|
"aria-roledescription",
|
|
2487
2668
|
"aria-braillelabel",
|
|
2488
2669
|
"aria-brailleroledescription"
|
|
2489
|
-
]),
|
|
2670
|
+
]), ga = {
|
|
2490
2671
|
id: "aria-allowed-attr",
|
|
2491
2672
|
wcag: ["4.1.2"],
|
|
2492
2673
|
level: "A",
|
|
@@ -2496,23 +2677,23 @@ const Kt = {
|
|
|
2496
2677
|
run(t) {
|
|
2497
2678
|
const a = [];
|
|
2498
2679
|
for (const e of t.querySelectorAll("[role], [aria-*]")) {
|
|
2499
|
-
if (
|
|
2500
|
-
const i =
|
|
2680
|
+
if (p(e)) continue;
|
|
2681
|
+
const i = C(e);
|
|
2501
2682
|
if (!i) continue;
|
|
2502
|
-
const n =
|
|
2683
|
+
const n = ha[i];
|
|
2503
2684
|
if (n)
|
|
2504
2685
|
for (const r of e.attributes)
|
|
2505
|
-
r.name.startsWith("aria-") && (
|
|
2686
|
+
r.name.startsWith("aria-") && (pa.has(r.name) || n.has(r.name) || a.push({
|
|
2506
2687
|
ruleId: "aria-allowed-attr",
|
|
2507
|
-
selector:
|
|
2508
|
-
html:
|
|
2688
|
+
selector: d(e),
|
|
2689
|
+
html: u(e),
|
|
2509
2690
|
impact: "critical",
|
|
2510
2691
|
message: `ARIA attribute "${r.name}" is not allowed on role "${i}".`
|
|
2511
2692
|
}));
|
|
2512
2693
|
}
|
|
2513
2694
|
return a;
|
|
2514
2695
|
}
|
|
2515
|
-
},
|
|
2696
|
+
}, ba = /* @__PURE__ */ new Set([
|
|
2516
2697
|
"base",
|
|
2517
2698
|
"col",
|
|
2518
2699
|
"colgroup",
|
|
@@ -2634,10 +2815,10 @@ const Kt = {
|
|
|
2634
2815
|
video: /* @__PURE__ */ new Set(["application"]),
|
|
2635
2816
|
wbr: /* @__PURE__ */ new Set(["none", "presentation"])
|
|
2636
2817
|
};
|
|
2637
|
-
function
|
|
2818
|
+
function fa(t) {
|
|
2638
2819
|
var e;
|
|
2639
2820
|
const a = t.tagName.toLowerCase();
|
|
2640
|
-
if (
|
|
2821
|
+
if (ba.has(a))
|
|
2641
2822
|
return "none";
|
|
2642
2823
|
if (a === "a" && t.hasAttribute("href"))
|
|
2643
2824
|
return I["a[href]"];
|
|
@@ -2649,7 +2830,7 @@ function ea(t) {
|
|
|
2649
2830
|
}
|
|
2650
2831
|
return I[a] || "any";
|
|
2651
2832
|
}
|
|
2652
|
-
const
|
|
2833
|
+
const va = {
|
|
2653
2834
|
id: "aria-allowed-role",
|
|
2654
2835
|
wcag: ["4.1.2"],
|
|
2655
2836
|
level: "A",
|
|
@@ -2660,29 +2841,29 @@ const ta = {
|
|
|
2660
2841
|
var e;
|
|
2661
2842
|
const a = [];
|
|
2662
2843
|
for (const i of t.querySelectorAll("[role]")) {
|
|
2663
|
-
if (
|
|
2844
|
+
if (p(i)) continue;
|
|
2664
2845
|
const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
|
|
2665
2846
|
if (!n) continue;
|
|
2666
|
-
const r =
|
|
2847
|
+
const r = le(i);
|
|
2667
2848
|
if (r && n === r) continue;
|
|
2668
|
-
const o =
|
|
2849
|
+
const o = fa(i);
|
|
2669
2850
|
o === "none" ? a.push({
|
|
2670
2851
|
ruleId: "aria-allowed-role",
|
|
2671
|
-
selector:
|
|
2672
|
-
html:
|
|
2852
|
+
selector: d(i),
|
|
2853
|
+
html: u(i),
|
|
2673
2854
|
impact: "minor",
|
|
2674
2855
|
message: `Element <${i.tagName.toLowerCase()}> should not have an explicit role.`
|
|
2675
2856
|
}) : o !== "any" && !o.has(n) && a.push({
|
|
2676
2857
|
ruleId: "aria-allowed-role",
|
|
2677
|
-
selector:
|
|
2678
|
-
html:
|
|
2858
|
+
selector: d(i),
|
|
2859
|
+
html: u(i),
|
|
2679
2860
|
impact: "minor",
|
|
2680
2861
|
message: `Role "${n}" is not allowed on element <${i.tagName.toLowerCase()}>.`
|
|
2681
2862
|
});
|
|
2682
2863
|
}
|
|
2683
2864
|
return a;
|
|
2684
2865
|
}
|
|
2685
|
-
},
|
|
2866
|
+
}, ee = {
|
|
2686
2867
|
// Each array is an OR group - at least one of each inner array must be present
|
|
2687
2868
|
combobox: [["listbox", "tree", "grid", "dialog", "textbox"]],
|
|
2688
2869
|
// Must own/contain one of these
|
|
@@ -2699,7 +2880,7 @@ const ta = {
|
|
|
2699
2880
|
tablist: [["tab"]],
|
|
2700
2881
|
tree: [["treeitem", "group"]],
|
|
2701
2882
|
treegrid: [["row", "rowgroup"]]
|
|
2702
|
-
},
|
|
2883
|
+
}, te = {
|
|
2703
2884
|
caption: ["figure", "table", "grid", "treegrid"],
|
|
2704
2885
|
// cell/gridcell/columnheader/rowheader must be in a row
|
|
2705
2886
|
// but we skip checking native td/th since they're handled by HTML semantics
|
|
@@ -2713,25 +2894,25 @@ const ta = {
|
|
|
2713
2894
|
tab: ["tablist"],
|
|
2714
2895
|
treeitem: ["tree", "group"]
|
|
2715
2896
|
};
|
|
2716
|
-
function
|
|
2897
|
+
function wa(t, a) {
|
|
2717
2898
|
var r;
|
|
2718
2899
|
const e = ((r = t.getAttribute("aria-owns")) == null ? void 0 : r.split(/\s+/)) || [], i = t.ownerDocument, n = /* @__PURE__ */ new Set();
|
|
2719
2900
|
for (const o of t.querySelectorAll("*")) {
|
|
2720
|
-
const s =
|
|
2721
|
-
s && !
|
|
2901
|
+
const s = C(o);
|
|
2902
|
+
s && !p(o) && n.add(s);
|
|
2722
2903
|
}
|
|
2723
2904
|
for (const o of e) {
|
|
2724
2905
|
const s = i.getElementById(o);
|
|
2725
2906
|
if (s) {
|
|
2726
|
-
const
|
|
2727
|
-
|
|
2907
|
+
const c = C(s);
|
|
2908
|
+
c && !p(s) && n.add(c);
|
|
2728
2909
|
}
|
|
2729
2910
|
}
|
|
2730
2911
|
for (const o of a)
|
|
2731
|
-
if (!o.some((
|
|
2912
|
+
if (!o.some((c) => n.has(c))) return !1;
|
|
2732
2913
|
return !0;
|
|
2733
2914
|
}
|
|
2734
|
-
const
|
|
2915
|
+
const ya = {
|
|
2735
2916
|
id: "aria-required-children",
|
|
2736
2917
|
wcag: ["4.1.2"],
|
|
2737
2918
|
level: "A",
|
|
@@ -2742,16 +2923,16 @@ const ia = {
|
|
|
2742
2923
|
var e;
|
|
2743
2924
|
const a = [];
|
|
2744
2925
|
for (const i of t.querySelectorAll("[role]")) {
|
|
2745
|
-
if (
|
|
2926
|
+
if (p(i)) continue;
|
|
2746
2927
|
const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
|
|
2747
|
-
if (!n || !(n in
|
|
2748
|
-
const r =
|
|
2749
|
-
if (!
|
|
2928
|
+
if (!n || !(n in ee)) continue;
|
|
2929
|
+
const r = ee[n];
|
|
2930
|
+
if (!wa(i, r)) {
|
|
2750
2931
|
const o = r.map((s) => s.join(" or ")).join(", ");
|
|
2751
2932
|
a.push({
|
|
2752
2933
|
ruleId: "aria-required-children",
|
|
2753
|
-
selector:
|
|
2754
|
-
html:
|
|
2934
|
+
selector: d(i),
|
|
2935
|
+
html: u(i),
|
|
2755
2936
|
impact: "critical",
|
|
2756
2937
|
message: `Role "${n}" requires children with role: ${o}.`
|
|
2757
2938
|
});
|
|
@@ -2759,7 +2940,7 @@ const ia = {
|
|
|
2759
2940
|
}
|
|
2760
2941
|
return a;
|
|
2761
2942
|
}
|
|
2762
|
-
},
|
|
2943
|
+
}, Aa = {
|
|
2763
2944
|
id: "aria-required-parent",
|
|
2764
2945
|
wcag: ["4.1.2"],
|
|
2765
2946
|
level: "A",
|
|
@@ -2770,14 +2951,14 @@ const ia = {
|
|
|
2770
2951
|
var e;
|
|
2771
2952
|
const a = [];
|
|
2772
2953
|
for (const i of t.querySelectorAll("[role]")) {
|
|
2773
|
-
if (
|
|
2954
|
+
if (p(i)) continue;
|
|
2774
2955
|
const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
|
|
2775
|
-
if (!n || !(n in
|
|
2776
|
-
const r =
|
|
2956
|
+
if (!n || !(n in te)) continue;
|
|
2957
|
+
const r = te[n];
|
|
2777
2958
|
let o = i.parentElement, s = !1;
|
|
2778
2959
|
for (; o && o !== t.documentElement; ) {
|
|
2779
|
-
const
|
|
2780
|
-
if (
|
|
2960
|
+
const c = C(o);
|
|
2961
|
+
if (c && r.includes(c)) {
|
|
2781
2962
|
s = !0;
|
|
2782
2963
|
break;
|
|
2783
2964
|
}
|
|
@@ -2785,15 +2966,15 @@ const ia = {
|
|
|
2785
2966
|
}
|
|
2786
2967
|
s || a.push({
|
|
2787
2968
|
ruleId: "aria-required-parent",
|
|
2788
|
-
selector:
|
|
2789
|
-
html:
|
|
2969
|
+
selector: d(i),
|
|
2970
|
+
html: u(i),
|
|
2790
2971
|
impact: "critical",
|
|
2791
2972
|
message: `Role "${n}" must be contained within: ${r.join(", ")}.`
|
|
2792
2973
|
});
|
|
2793
2974
|
}
|
|
2794
2975
|
return a;
|
|
2795
2976
|
}
|
|
2796
|
-
},
|
|
2977
|
+
}, ae = [
|
|
2797
2978
|
"a[href]",
|
|
2798
2979
|
"button:not([disabled])",
|
|
2799
2980
|
'input:not([disabled]):not([type="hidden"])',
|
|
@@ -2809,7 +2990,7 @@ const ia = {
|
|
|
2809
2990
|
"embed",
|
|
2810
2991
|
"area[href]"
|
|
2811
2992
|
].join(", ");
|
|
2812
|
-
function
|
|
2993
|
+
function Sa(t) {
|
|
2813
2994
|
let a = t;
|
|
2814
2995
|
const e = t.ownerDocument, i = e.defaultView;
|
|
2815
2996
|
for (; a && a !== e.body; ) {
|
|
@@ -2822,7 +3003,7 @@ function oa(t) {
|
|
|
2822
3003
|
}
|
|
2823
3004
|
return !0;
|
|
2824
3005
|
}
|
|
2825
|
-
const
|
|
3006
|
+
const xa = {
|
|
2826
3007
|
id: "aria-hidden-body",
|
|
2827
3008
|
selector: 'body[aria-hidden="true"]',
|
|
2828
3009
|
check: { type: "selector-exists" },
|
|
@@ -2834,7 +3015,7 @@ const sa = {
|
|
|
2834
3015
|
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.",
|
|
2835
3016
|
prompt: "Instruct to remove aria-hidden='true' from the body element.",
|
|
2836
3017
|
skipAriaHidden: !1
|
|
2837
|
-
},
|
|
3018
|
+
}, ka = k(xa), Ia = {
|
|
2838
3019
|
id: "aria-hidden-focus",
|
|
2839
3020
|
wcag: ["4.1.2"],
|
|
2840
3021
|
level: "A",
|
|
@@ -2845,14 +3026,15 @@ const sa = {
|
|
|
2845
3026
|
const a = [];
|
|
2846
3027
|
for (const e of t.querySelectorAll('[aria-hidden="true"]')) {
|
|
2847
3028
|
if (e === t.body) continue;
|
|
2848
|
-
const i = e.querySelectorAll(
|
|
3029
|
+
const i = [...e.querySelectorAll(ae)];
|
|
3030
|
+
e.matches(ae) && i.push(e);
|
|
2849
3031
|
for (const n of i)
|
|
2850
3032
|
if (n instanceof HTMLElement) {
|
|
2851
|
-
if (n.getAttribute("tabindex") === "-1" || n.disabled || n instanceof HTMLInputElement && n.type === "hidden" || !
|
|
3033
|
+
if (n.getAttribute("tabindex") === "-1" || n.disabled || n instanceof HTMLInputElement && n.type === "hidden" || !Sa(n)) continue;
|
|
2852
3034
|
a.push({
|
|
2853
3035
|
ruleId: "aria-hidden-focus",
|
|
2854
|
-
selector:
|
|
2855
|
-
html:
|
|
3036
|
+
selector: d(n),
|
|
3037
|
+
html: u(n),
|
|
2856
3038
|
impact: "serious",
|
|
2857
3039
|
message: "Focusable element is inside an aria-hidden region."
|
|
2858
3040
|
});
|
|
@@ -2860,7 +3042,7 @@ const sa = {
|
|
|
2860
3042
|
}
|
|
2861
3043
|
return a;
|
|
2862
3044
|
}
|
|
2863
|
-
},
|
|
3045
|
+
}, Ea = {
|
|
2864
3046
|
id: "aria-command-name",
|
|
2865
3047
|
wcag: ["4.1.2"],
|
|
2866
3048
|
level: "A",
|
|
@@ -2871,14 +3053,14 @@ const sa = {
|
|
|
2871
3053
|
var e;
|
|
2872
3054
|
const a = [];
|
|
2873
3055
|
for (const i of t.querySelectorAll('[role="button"], [role="link"], [role="menuitem"]')) {
|
|
2874
|
-
if (
|
|
2875
|
-
if (!
|
|
3056
|
+
if (p(i) || i.tagName.toLowerCase() === "button" || i.tagName.toLowerCase() === "a") continue;
|
|
3057
|
+
if (!v(i)) {
|
|
2876
3058
|
const r = i.querySelector("img[alt]");
|
|
2877
3059
|
if ((e = r == null ? void 0 : r.getAttribute("alt")) != null && e.trim()) continue;
|
|
2878
3060
|
a.push({
|
|
2879
3061
|
ruleId: "aria-command-name",
|
|
2880
|
-
selector:
|
|
2881
|
-
html:
|
|
3062
|
+
selector: d(i),
|
|
3063
|
+
html: u(i),
|
|
2882
3064
|
impact: "serious",
|
|
2883
3065
|
message: "ARIA command has no accessible name."
|
|
2884
3066
|
});
|
|
@@ -2886,7 +3068,7 @@ const sa = {
|
|
|
2886
3068
|
}
|
|
2887
3069
|
return a;
|
|
2888
3070
|
}
|
|
2889
|
-
},
|
|
3071
|
+
}, Ta = {
|
|
2890
3072
|
id: "aria-input-field-name",
|
|
2891
3073
|
wcag: ["4.1.2"],
|
|
2892
3074
|
level: "A",
|
|
@@ -2896,18 +3078,18 @@ const sa = {
|
|
|
2896
3078
|
run(t) {
|
|
2897
3079
|
const a = [], e = '[role="combobox"], [role="listbox"], [role="searchbox"], [role="slider"], [role="spinbutton"], [role="textbox"]';
|
|
2898
3080
|
for (const i of t.querySelectorAll(e)) {
|
|
2899
|
-
if (
|
|
2900
|
-
|
|
3081
|
+
if (p(i) || i.matches("input, select, textarea")) continue;
|
|
3082
|
+
v(i) || a.push({
|
|
2901
3083
|
ruleId: "aria-input-field-name",
|
|
2902
|
-
selector:
|
|
2903
|
-
html:
|
|
3084
|
+
selector: d(i),
|
|
3085
|
+
html: u(i),
|
|
2904
3086
|
impact: "serious",
|
|
2905
3087
|
message: "ARIA input field has no accessible name."
|
|
2906
3088
|
});
|
|
2907
3089
|
}
|
|
2908
3090
|
return a;
|
|
2909
3091
|
}
|
|
2910
|
-
},
|
|
3092
|
+
}, La = {
|
|
2911
3093
|
id: "aria-toggle-field-name",
|
|
2912
3094
|
wcag: ["4.1.2"],
|
|
2913
3095
|
level: "A",
|
|
@@ -2917,18 +3099,18 @@ const sa = {
|
|
|
2917
3099
|
run(t) {
|
|
2918
3100
|
const a = [], e = '[role="checkbox"], [role="switch"], [role="radio"], [role="menuitemcheckbox"], [role="menuitemradio"]';
|
|
2919
3101
|
for (const i of t.querySelectorAll(e)) {
|
|
2920
|
-
if (
|
|
2921
|
-
|
|
3102
|
+
if (p(i) || i.matches('input[type="checkbox"], input[type="radio"]')) continue;
|
|
3103
|
+
v(i) || a.push({
|
|
2922
3104
|
ruleId: "aria-toggle-field-name",
|
|
2923
|
-
selector:
|
|
2924
|
-
html:
|
|
3105
|
+
selector: d(i),
|
|
3106
|
+
html: u(i),
|
|
2925
3107
|
impact: "serious",
|
|
2926
3108
|
message: "ARIA toggle field has no accessible name."
|
|
2927
3109
|
});
|
|
2928
3110
|
}
|
|
2929
3111
|
return a;
|
|
2930
3112
|
}
|
|
2931
|
-
},
|
|
3113
|
+
}, Ca = {
|
|
2932
3114
|
id: "aria-meter-name",
|
|
2933
3115
|
wcag: ["4.1.2"],
|
|
2934
3116
|
level: "A",
|
|
@@ -2938,18 +3120,18 @@ const sa = {
|
|
|
2938
3120
|
run(t) {
|
|
2939
3121
|
const a = [];
|
|
2940
3122
|
for (const e of t.querySelectorAll('[role="meter"], meter')) {
|
|
2941
|
-
if (
|
|
2942
|
-
|
|
3123
|
+
if (p(e)) continue;
|
|
3124
|
+
v(e) || a.push({
|
|
2943
3125
|
ruleId: "aria-meter-name",
|
|
2944
|
-
selector:
|
|
2945
|
-
html:
|
|
3126
|
+
selector: d(e),
|
|
3127
|
+
html: u(e),
|
|
2946
3128
|
impact: "serious",
|
|
2947
3129
|
message: "Meter has no accessible name."
|
|
2948
3130
|
});
|
|
2949
3131
|
}
|
|
2950
3132
|
return a;
|
|
2951
3133
|
}
|
|
2952
|
-
},
|
|
3134
|
+
}, qa = {
|
|
2953
3135
|
id: "aria-progressbar-name",
|
|
2954
3136
|
wcag: ["4.1.2"],
|
|
2955
3137
|
level: "A",
|
|
@@ -2959,18 +3141,18 @@ const sa = {
|
|
|
2959
3141
|
run(t) {
|
|
2960
3142
|
const a = [];
|
|
2961
3143
|
for (const e of t.querySelectorAll('[role="progressbar"], progress')) {
|
|
2962
|
-
if (
|
|
2963
|
-
|
|
3144
|
+
if (p(e)) continue;
|
|
3145
|
+
v(e) || a.push({
|
|
2964
3146
|
ruleId: "aria-progressbar-name",
|
|
2965
|
-
selector:
|
|
2966
|
-
html:
|
|
3147
|
+
selector: d(e),
|
|
3148
|
+
html: u(e),
|
|
2967
3149
|
impact: "serious",
|
|
2968
3150
|
message: "Progressbar has no accessible name."
|
|
2969
3151
|
});
|
|
2970
3152
|
}
|
|
2971
3153
|
return a;
|
|
2972
3154
|
}
|
|
2973
|
-
},
|
|
3155
|
+
}, Ra = {
|
|
2974
3156
|
id: "aria-dialog-name",
|
|
2975
3157
|
wcag: ["4.1.2"],
|
|
2976
3158
|
level: "A",
|
|
@@ -2980,18 +3162,18 @@ const sa = {
|
|
|
2980
3162
|
run(t) {
|
|
2981
3163
|
const a = [];
|
|
2982
3164
|
for (const e of t.querySelectorAll('[role="dialog"], [role="alertdialog"], dialog')) {
|
|
2983
|
-
if (
|
|
2984
|
-
|
|
3165
|
+
if (p(e)) continue;
|
|
3166
|
+
v(e) || a.push({
|
|
2985
3167
|
ruleId: "aria-dialog-name",
|
|
2986
|
-
selector:
|
|
2987
|
-
html:
|
|
3168
|
+
selector: d(e),
|
|
3169
|
+
html: u(e),
|
|
2988
3170
|
impact: "serious",
|
|
2989
3171
|
message: "Dialog has no accessible name."
|
|
2990
3172
|
});
|
|
2991
3173
|
}
|
|
2992
3174
|
return a;
|
|
2993
3175
|
}
|
|
2994
|
-
},
|
|
3176
|
+
}, Na = {
|
|
2995
3177
|
id: "aria-tooltip-name",
|
|
2996
3178
|
wcag: ["4.1.2"],
|
|
2997
3179
|
level: "A",
|
|
@@ -3001,18 +3183,18 @@ const sa = {
|
|
|
3001
3183
|
run(t) {
|
|
3002
3184
|
const a = [];
|
|
3003
3185
|
for (const e of t.querySelectorAll('[role="tooltip"]')) {
|
|
3004
|
-
if (
|
|
3005
|
-
|
|
3186
|
+
if (p(e)) continue;
|
|
3187
|
+
v(e) || a.push({
|
|
3006
3188
|
ruleId: "aria-tooltip-name",
|
|
3007
|
-
selector:
|
|
3008
|
-
html:
|
|
3189
|
+
selector: d(e),
|
|
3190
|
+
html: u(e),
|
|
3009
3191
|
impact: "serious",
|
|
3010
3192
|
message: "Tooltip has no accessible name."
|
|
3011
3193
|
});
|
|
3012
3194
|
}
|
|
3013
3195
|
return a;
|
|
3014
3196
|
}
|
|
3015
|
-
},
|
|
3197
|
+
}, Ma = {
|
|
3016
3198
|
id: "aria-treeitem-name",
|
|
3017
3199
|
wcag: ["4.1.2"],
|
|
3018
3200
|
level: "A",
|
|
@@ -3022,18 +3204,18 @@ const sa = {
|
|
|
3022
3204
|
run(t) {
|
|
3023
3205
|
const a = [];
|
|
3024
3206
|
for (const e of t.querySelectorAll('[role="treeitem"]')) {
|
|
3025
|
-
if (
|
|
3026
|
-
|
|
3207
|
+
if (p(e)) continue;
|
|
3208
|
+
v(e) || a.push({
|
|
3027
3209
|
ruleId: "aria-treeitem-name",
|
|
3028
|
-
selector:
|
|
3029
|
-
html:
|
|
3210
|
+
selector: d(e),
|
|
3211
|
+
html: u(e),
|
|
3030
3212
|
impact: "serious",
|
|
3031
3213
|
message: "Treeitem has no accessible name."
|
|
3032
3214
|
});
|
|
3033
3215
|
}
|
|
3034
3216
|
return a;
|
|
3035
3217
|
}
|
|
3036
|
-
},
|
|
3218
|
+
}, $a = {
|
|
3037
3219
|
id: "aria-prohibited-attr",
|
|
3038
3220
|
wcag: ["4.1.2"],
|
|
3039
3221
|
level: "A",
|
|
@@ -3041,16 +3223,16 @@ const sa = {
|
|
|
3041
3223
|
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.",
|
|
3042
3224
|
prompt: "Identify the prohibited attribute and recommend removing it from this element.",
|
|
3043
3225
|
run(t) {
|
|
3044
|
-
return
|
|
3226
|
+
return V(t).prohibitedAttr;
|
|
3045
3227
|
}
|
|
3046
|
-
},
|
|
3228
|
+
}, Ha = [
|
|
3047
3229
|
"a[href]",
|
|
3048
3230
|
"button:not([disabled])",
|
|
3049
3231
|
'input:not([disabled]):not([type="hidden"])',
|
|
3050
3232
|
"select:not([disabled])",
|
|
3051
3233
|
"textarea:not([disabled])",
|
|
3052
3234
|
'[tabindex]:not([tabindex="-1"])'
|
|
3053
|
-
].join(", "),
|
|
3235
|
+
].join(", "), Da = [
|
|
3054
3236
|
"aria-atomic",
|
|
3055
3237
|
"aria-busy",
|
|
3056
3238
|
"aria-controls",
|
|
@@ -3064,7 +3246,18 @@ const sa = {
|
|
|
3064
3246
|
"aria-live",
|
|
3065
3247
|
"aria-owns",
|
|
3066
3248
|
"aria-relevant"
|
|
3067
|
-
]
|
|
3249
|
+
];
|
|
3250
|
+
function ie(t) {
|
|
3251
|
+
const a = [];
|
|
3252
|
+
t.matches(Ha) && a.push("element is focusable");
|
|
3253
|
+
for (const e of Da)
|
|
3254
|
+
if (t.hasAttribute(e)) {
|
|
3255
|
+
a.push(`has ${e}`);
|
|
3256
|
+
break;
|
|
3257
|
+
}
|
|
3258
|
+
return (t.hasAttribute("aria-label") || t.hasAttribute("aria-labelledby")) && a.push("has accessible name"), a;
|
|
3259
|
+
}
|
|
3260
|
+
const Oa = {
|
|
3068
3261
|
id: "presentation-role-conflict",
|
|
3069
3262
|
wcag: ["4.1.2"],
|
|
3070
3263
|
level: "A",
|
|
@@ -3074,25 +3267,30 @@ const sa = {
|
|
|
3074
3267
|
run(t) {
|
|
3075
3268
|
const a = [];
|
|
3076
3269
|
for (const e of t.querySelectorAll('[role="presentation"], [role="none"]')) {
|
|
3077
|
-
if (
|
|
3078
|
-
const i =
|
|
3079
|
-
|
|
3080
|
-
for (const n of ya)
|
|
3081
|
-
if (e.hasAttribute(n)) {
|
|
3082
|
-
i.push(`has ${n}`);
|
|
3083
|
-
break;
|
|
3084
|
-
}
|
|
3085
|
-
(e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby")) && i.push("has accessible name"), i.length > 0 && a.push({
|
|
3270
|
+
if (p(e)) continue;
|
|
3271
|
+
const i = ie(e);
|
|
3272
|
+
i.length > 0 && a.push({
|
|
3086
3273
|
ruleId: "presentation-role-conflict",
|
|
3087
|
-
selector:
|
|
3088
|
-
html:
|
|
3274
|
+
selector: d(e),
|
|
3275
|
+
html: u(e),
|
|
3089
3276
|
impact: "serious",
|
|
3090
3277
|
message: `Presentation role conflicts with: ${i.join(", ")}. The role will be ignored.`
|
|
3091
3278
|
});
|
|
3092
3279
|
}
|
|
3280
|
+
for (const e of t.querySelectorAll('img[alt=""]')) {
|
|
3281
|
+
if (p(e) || e.hasAttribute("role")) continue;
|
|
3282
|
+
const i = ie(e);
|
|
3283
|
+
i.length > 0 && a.push({
|
|
3284
|
+
ruleId: "presentation-role-conflict",
|
|
3285
|
+
selector: d(e),
|
|
3286
|
+
html: u(e),
|
|
3287
|
+
impact: "serious",
|
|
3288
|
+
message: `Element with implicit presentation role (alt="") conflicts with: ${i.join(", ")}. The decorative role will be ignored.`
|
|
3289
|
+
});
|
|
3290
|
+
}
|
|
3093
3291
|
return a;
|
|
3094
3292
|
}
|
|
3095
|
-
},
|
|
3293
|
+
}, Ba = {
|
|
3096
3294
|
id: "summary-name",
|
|
3097
3295
|
wcag: ["4.1.2"],
|
|
3098
3296
|
level: "A",
|
|
@@ -3101,12 +3299,12 @@ const sa = {
|
|
|
3101
3299
|
prompt: "Based on the surrounding context or details content, suggest text to add inside the <summary> element.",
|
|
3102
3300
|
run(t) {
|
|
3103
3301
|
const a = [];
|
|
3104
|
-
for (const e of t.querySelectorAll("summary")) {
|
|
3105
|
-
if (
|
|
3106
|
-
|
|
3302
|
+
for (const e of t.querySelectorAll("details > summary:first-of-type")) {
|
|
3303
|
+
if (p(e)) continue;
|
|
3304
|
+
v(e) || a.push({
|
|
3107
3305
|
ruleId: "summary-name",
|
|
3108
|
-
selector:
|
|
3109
|
-
html:
|
|
3306
|
+
selector: d(e),
|
|
3307
|
+
html: u(e),
|
|
3110
3308
|
impact: "serious",
|
|
3111
3309
|
message: "<summary> element has no accessible name. Add descriptive text."
|
|
3112
3310
|
});
|
|
@@ -3114,7 +3312,7 @@ const sa = {
|
|
|
3114
3312
|
return a;
|
|
3115
3313
|
}
|
|
3116
3314
|
};
|
|
3117
|
-
function
|
|
3315
|
+
function Wa(t) {
|
|
3118
3316
|
var n, r;
|
|
3119
3317
|
const a = [], e = t.getAttribute("href");
|
|
3120
3318
|
e && a.push(`href: ${e}`);
|
|
@@ -3131,7 +3329,7 @@ function xa(t) {
|
|
|
3131
3329
|
return a.length > 0 ? a.join(`
|
|
3132
3330
|
`) : void 0;
|
|
3133
3331
|
}
|
|
3134
|
-
const
|
|
3332
|
+
const _a = {
|
|
3135
3333
|
id: "link-name",
|
|
3136
3334
|
wcag: ["2.4.4", "4.1.2"],
|
|
3137
3335
|
level: "A",
|
|
@@ -3140,20 +3338,20 @@ const ka = {
|
|
|
3140
3338
|
prompt: "Based on the href or surrounding context, suggest descriptive link text or an aria-label.",
|
|
3141
3339
|
run(t) {
|
|
3142
3340
|
const a = [];
|
|
3143
|
-
for (const e of t.querySelectorAll('a[href], [role="link"]')) {
|
|
3144
|
-
if (
|
|
3145
|
-
|
|
3341
|
+
for (const e of t.querySelectorAll('a[href], area[href], [role="link"]')) {
|
|
3342
|
+
if (p(e)) continue;
|
|
3343
|
+
v(e) || a.push({
|
|
3146
3344
|
ruleId: "link-name",
|
|
3147
|
-
selector:
|
|
3148
|
-
html:
|
|
3345
|
+
selector: d(e),
|
|
3346
|
+
html: u(e),
|
|
3149
3347
|
impact: "serious",
|
|
3150
3348
|
message: "Link has no discernible text.",
|
|
3151
|
-
context:
|
|
3349
|
+
context: Wa(e)
|
|
3152
3350
|
});
|
|
3153
3351
|
}
|
|
3154
3352
|
return a;
|
|
3155
3353
|
}
|
|
3156
|
-
},
|
|
3354
|
+
}, Fa = {
|
|
3157
3355
|
id: "skip-link",
|
|
3158
3356
|
wcag: ["2.4.1"],
|
|
3159
3357
|
level: "A",
|
|
@@ -3171,15 +3369,105 @@ const ka = {
|
|
|
3171
3369
|
const s = n.slice(1);
|
|
3172
3370
|
t.getElementById(s) || a.push({
|
|
3173
3371
|
ruleId: "skip-link",
|
|
3174
|
-
selector:
|
|
3175
|
-
html:
|
|
3372
|
+
selector: d(i),
|
|
3373
|
+
html: u(i),
|
|
3176
3374
|
impact: "moderate",
|
|
3177
3375
|
message: `Skip link points to "#${s}" which does not exist on the page.`
|
|
3178
3376
|
});
|
|
3179
3377
|
}
|
|
3180
3378
|
return a;
|
|
3181
3379
|
}
|
|
3182
|
-
},
|
|
3380
|
+
}, ja = /* @__PURE__ */ new Set([
|
|
3381
|
+
"block",
|
|
3382
|
+
"flex",
|
|
3383
|
+
"grid",
|
|
3384
|
+
"table",
|
|
3385
|
+
"table-cell",
|
|
3386
|
+
"list-item",
|
|
3387
|
+
"flow-root"
|
|
3388
|
+
]), Pa = /* @__PURE__ */ new Set([
|
|
3389
|
+
"inline",
|
|
3390
|
+
"inline-block",
|
|
3391
|
+
"inline-flex",
|
|
3392
|
+
"inline-grid"
|
|
3393
|
+
]);
|
|
3394
|
+
function Va(t) {
|
|
3395
|
+
let a = t.parentElement;
|
|
3396
|
+
for (; a; ) {
|
|
3397
|
+
const e = A(a).display;
|
|
3398
|
+
if (ja.has(e) && za(a))
|
|
3399
|
+
return a;
|
|
3400
|
+
a = a.parentElement;
|
|
3401
|
+
}
|
|
3402
|
+
return null;
|
|
3403
|
+
}
|
|
3404
|
+
function za(t) {
|
|
3405
|
+
const a = t.ownerDocument.createTreeWalker(
|
|
3406
|
+
t,
|
|
3407
|
+
NodeFilter.SHOW_TEXT
|
|
3408
|
+
);
|
|
3409
|
+
let e;
|
|
3410
|
+
for (; e = a.nextNode(); ) {
|
|
3411
|
+
if (!e.data.trim()) continue;
|
|
3412
|
+
let i = e.parentElement, n = !1;
|
|
3413
|
+
for (; i && i !== t; ) {
|
|
3414
|
+
if (i.tagName === "A") {
|
|
3415
|
+
n = !0;
|
|
3416
|
+
break;
|
|
3417
|
+
}
|
|
3418
|
+
i = i.parentElement;
|
|
3419
|
+
}
|
|
3420
|
+
if (!n) return !0;
|
|
3421
|
+
}
|
|
3422
|
+
return !1;
|
|
3423
|
+
}
|
|
3424
|
+
function Ua(t, a) {
|
|
3425
|
+
const e = t.ownerDocument.createTreeWalker(
|
|
3426
|
+
t,
|
|
3427
|
+
NodeFilter.SHOW_TEXT
|
|
3428
|
+
);
|
|
3429
|
+
let i;
|
|
3430
|
+
for (; i = e.nextNode(); ) {
|
|
3431
|
+
if (!i.data.trim()) continue;
|
|
3432
|
+
let n = i.parentElement, r = !1, o = n;
|
|
3433
|
+
for (; o && o !== t; ) {
|
|
3434
|
+
if (o.tagName === "A") {
|
|
3435
|
+
r = !0;
|
|
3436
|
+
break;
|
|
3437
|
+
}
|
|
3438
|
+
o = o.parentElement;
|
|
3439
|
+
}
|
|
3440
|
+
if (!r && n)
|
|
3441
|
+
return R(A(n).color);
|
|
3442
|
+
}
|
|
3443
|
+
return null;
|
|
3444
|
+
}
|
|
3445
|
+
function Ga(t, a) {
|
|
3446
|
+
const e = t.textDecorationLine || t.textDecoration || "", i = a.textDecorationLine || a.textDecoration || "";
|
|
3447
|
+
if ((e.includes("underline") || e.includes("line-through")) && e !== i)
|
|
3448
|
+
return !0;
|
|
3449
|
+
const n = parseFloat(t.borderBottomWidth) || 0, r = t.borderBottomStyle || "";
|
|
3450
|
+
if (n > 0 && r !== "none" && r !== "hidden")
|
|
3451
|
+
return !0;
|
|
3452
|
+
const o = parseFloat(t.outlineWidth) || 0, s = t.outlineStyle || "";
|
|
3453
|
+
if (o > 0 && s !== "none")
|
|
3454
|
+
return !0;
|
|
3455
|
+
const c = t.backgroundImage || "";
|
|
3456
|
+
if (c && c !== "none" && c !== "initial")
|
|
3457
|
+
return !0;
|
|
3458
|
+
const h = ne(t.fontWeight), l = ne(a.fontWeight);
|
|
3459
|
+
if (Math.abs(h - l) >= 300 || t.fontStyle !== a.fontStyle)
|
|
3460
|
+
return !0;
|
|
3461
|
+
const m = parseFloat(t.fontSize) || 16, g = parseFloat(a.fontSize) || 16;
|
|
3462
|
+
return g > 0 && m / g >= 1.2;
|
|
3463
|
+
}
|
|
3464
|
+
function ne(t) {
|
|
3465
|
+
return t === "bold" ? 700 : t === "normal" ? 400 : parseInt(t) || 400;
|
|
3466
|
+
}
|
|
3467
|
+
function re(t, a, e) {
|
|
3468
|
+
return "#" + [t, a, e].map((i) => i.toString(16).padStart(2, "0")).join("");
|
|
3469
|
+
}
|
|
3470
|
+
const Xa = {
|
|
3183
3471
|
id: "link-in-text-block",
|
|
3184
3472
|
wcag: ["1.4.1"],
|
|
3185
3473
|
level: "A",
|
|
@@ -3189,24 +3477,30 @@ const ka = {
|
|
|
3189
3477
|
run(t) {
|
|
3190
3478
|
const a = [];
|
|
3191
3479
|
for (const e of t.querySelectorAll("a[href]")) {
|
|
3192
|
-
if (
|
|
3193
|
-
const i = e.
|
|
3194
|
-
if (!
|
|
3195
|
-
const
|
|
3196
|
-
if (
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3480
|
+
if (p(e) || !y(e).trim()) continue;
|
|
3481
|
+
const i = A(e), n = i.display || "inline";
|
|
3482
|
+
if (!Pa.has(n)) continue;
|
|
3483
|
+
const r = Va(e);
|
|
3484
|
+
if (!r) continue;
|
|
3485
|
+
const o = A(r);
|
|
3486
|
+
if (Ga(i, o)) continue;
|
|
3487
|
+
const s = R(i.color), c = Ua(r);
|
|
3488
|
+
if (!s || !c) continue;
|
|
3489
|
+
const h = q(...s), l = q(...c), m = ce(h, l);
|
|
3490
|
+
if (m >= 3) continue;
|
|
3491
|
+
const g = re(...s), b = re(...c), f = `link color: ${g} rgb(${s.join(", ")}), surrounding text: ${b} rgb(${c.join(", ")}), ratio: ${m.toFixed(2)}:1`;
|
|
3492
|
+
a.push({
|
|
3493
|
+
ruleId: "link-in-text-block",
|
|
3494
|
+
selector: d(e),
|
|
3495
|
+
html: u(e),
|
|
3496
|
+
impact: "serious",
|
|
3497
|
+
message: "Link in text block is not visually distinguishable from surrounding text. Add an underline, border, or ensure 3:1 color contrast with surrounding text.",
|
|
3498
|
+
context: f
|
|
3499
|
+
});
|
|
3206
3500
|
}
|
|
3207
3501
|
return a;
|
|
3208
3502
|
}
|
|
3209
|
-
},
|
|
3503
|
+
}, Ya = {
|
|
3210
3504
|
id: "html-has-lang",
|
|
3211
3505
|
wcag: ["3.1.1"],
|
|
3212
3506
|
level: "A",
|
|
@@ -3216,15 +3510,32 @@ const ka = {
|
|
|
3216
3510
|
run(t) {
|
|
3217
3511
|
var e;
|
|
3218
3512
|
const a = t.documentElement;
|
|
3513
|
+
if (a.tagName.toLowerCase() !== "html") return [];
|
|
3514
|
+
if (!t.doctype && t.body) {
|
|
3515
|
+
const i = t.body.children;
|
|
3516
|
+
if (i.length > 0 && Array.from(i).every(
|
|
3517
|
+
(n) => n.tagName.toLowerCase() === "svg" || n.tagName.toLowerCase() === "math"
|
|
3518
|
+
)) return [];
|
|
3519
|
+
}
|
|
3219
3520
|
return (e = a.getAttribute("lang")) != null && e.trim() ? [] : [{
|
|
3220
3521
|
ruleId: "html-has-lang",
|
|
3221
|
-
selector:
|
|
3222
|
-
html:
|
|
3522
|
+
selector: d(a),
|
|
3523
|
+
html: u(a),
|
|
3223
3524
|
impact: "serious",
|
|
3224
3525
|
message: "<html> element missing lang attribute."
|
|
3225
3526
|
}];
|
|
3226
3527
|
}
|
|
3227
|
-
},
|
|
3528
|
+
}, Ka = new Set(
|
|
3529
|
+
"aa ab ae af ak am an ar as av ay az ba be bg bh bi bm bn bo br bs ca ce ch co cr cs cu cv cy da de dv dz ee el en eo es et eu fa ff fi fj fo fr fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id ie ig ii ik io is it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mr ms mt my na nb nd ne ng nl nn no nr nv ny oc oj om or os pa pi pl ps pt qu rm rn ro ru rw sa sc sd se sg si sk sl sm sn so sq sr ss st su sv sw ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zu".split(" ")
|
|
3530
|
+
), Qa = new Set(
|
|
3531
|
+
"aar abk afr aka amh ara arg asm ava ave aym aze bak bam bel ben bih bis bod bos bre bul cat ces cha che chu chv cor cos cre cym dan deu div dzo ell eng epo est eus ewe fao fas fij fin fra fry ful gla gle glg glv grn guj hat hau hbs heb her hin hmo hrv hun hye ibo iii iku ile ina ind ipk isl ita jav jpn kal kan kas kat kau kaz khm kik kin kir kom kon kor kua kur lao lat lav lim lin lit ltz lub lug mah mal mar mkd mlg mlt mon mri msa mya nau nav nbl nde ndo nep nld nno nob nor nya oci oji ori orm oss pan pli pol por pus que roh ron run rus sag san sin slk slv sme smo sna snd som sot spa sqi srd srp ssw sun swa swe tah tam tat tel tgk tgl tha tir ton tsn tso tuk tur twi uig ukr urd uzb ven vie vol wln wol xho yid yor zha zho zul".split(" ")
|
|
3532
|
+
), Ja = /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i;
|
|
3533
|
+
function ue(t) {
|
|
3534
|
+
if (!Ja.test(t)) return !1;
|
|
3535
|
+
const a = t.split("-")[0].toLowerCase();
|
|
3536
|
+
return a.length === 2 ? Ka.has(a) : a.length === 3 ? !Qa.has(a) : !1;
|
|
3537
|
+
}
|
|
3538
|
+
const Za = {
|
|
3228
3539
|
id: "html-lang-valid",
|
|
3229
3540
|
wcag: ["3.1.1"],
|
|
3230
3541
|
level: "A",
|
|
@@ -3234,15 +3545,48 @@ const ka = {
|
|
|
3234
3545
|
run(t) {
|
|
3235
3546
|
var e;
|
|
3236
3547
|
const a = (e = t.documentElement.getAttribute("lang")) == null ? void 0 : e.trim();
|
|
3237
|
-
return a && !
|
|
3548
|
+
return a && !ue(a) ? [{
|
|
3238
3549
|
ruleId: "html-lang-valid",
|
|
3239
3550
|
selector: "html",
|
|
3240
|
-
html:
|
|
3551
|
+
html: u(t.documentElement),
|
|
3241
3552
|
impact: "serious",
|
|
3242
3553
|
message: `Invalid lang attribute value "${a}".`
|
|
3243
3554
|
}] : [];
|
|
3244
3555
|
}
|
|
3245
|
-
}
|
|
3556
|
+
};
|
|
3557
|
+
function oe(t) {
|
|
3558
|
+
var i;
|
|
3559
|
+
const a = t.ownerDocument.createTreeWalker(t, NodeFilter.SHOW_TEXT);
|
|
3560
|
+
let e;
|
|
3561
|
+
for (; e = a.nextNode(); ) {
|
|
3562
|
+
if (!e.data.trim()) continue;
|
|
3563
|
+
const n = e.parentElement;
|
|
3564
|
+
if (!n || n instanceof HTMLElement && (n.hidden || n.style.display === "none")) continue;
|
|
3565
|
+
let r = n, o = !1;
|
|
3566
|
+
for (; r && r !== t; ) {
|
|
3567
|
+
if (r.hasAttribute("lang")) {
|
|
3568
|
+
o = !0;
|
|
3569
|
+
break;
|
|
3570
|
+
}
|
|
3571
|
+
r = r.parentElement;
|
|
3572
|
+
}
|
|
3573
|
+
if (!o) return !0;
|
|
3574
|
+
}
|
|
3575
|
+
for (const n of t.querySelectorAll("img[alt]")) {
|
|
3576
|
+
if (!((i = n.getAttribute("alt")) == null ? void 0 : i.trim())) continue;
|
|
3577
|
+
let o = n.parentElement, s = !1;
|
|
3578
|
+
for (; o && o !== t; ) {
|
|
3579
|
+
if (o.hasAttribute("lang")) {
|
|
3580
|
+
s = !0;
|
|
3581
|
+
break;
|
|
3582
|
+
}
|
|
3583
|
+
o = o.parentElement;
|
|
3584
|
+
}
|
|
3585
|
+
if (!s) return !0;
|
|
3586
|
+
}
|
|
3587
|
+
return !1;
|
|
3588
|
+
}
|
|
3589
|
+
const ei = {
|
|
3246
3590
|
id: "valid-lang",
|
|
3247
3591
|
wcag: ["3.1.2"],
|
|
3248
3592
|
level: "AA",
|
|
@@ -3250,22 +3594,31 @@ const ka = {
|
|
|
3250
3594
|
guidance: "When content in a different language appears within a page (e.g., a French quote in an English document), wrap it with a lang attribute to ensure correct pronunciation. The lang value must be a valid BCP 47 tag. Common codes: en, es, fr, de, zh, ja, pt, ar, ru.",
|
|
3251
3595
|
prompt: "Identify the content's language and suggest the correct BCP 47 tag.",
|
|
3252
3596
|
run(t) {
|
|
3253
|
-
var e;
|
|
3254
3597
|
const a = [];
|
|
3255
|
-
for (const
|
|
3256
|
-
if (
|
|
3257
|
-
const
|
|
3258
|
-
|
|
3598
|
+
for (const e of t.querySelectorAll("[lang]")) {
|
|
3599
|
+
if (p(e) || e === t.documentElement) continue;
|
|
3600
|
+
const i = e.getAttribute("lang"), n = i == null ? void 0 : i.trim();
|
|
3601
|
+
if (i && !n) {
|
|
3602
|
+
oe(e) && a.push({
|
|
3603
|
+
ruleId: "valid-lang",
|
|
3604
|
+
selector: d(e),
|
|
3605
|
+
html: u(e),
|
|
3606
|
+
impact: "serious",
|
|
3607
|
+
message: "Empty lang attribute value."
|
|
3608
|
+
});
|
|
3609
|
+
continue;
|
|
3610
|
+
}
|
|
3611
|
+
n && oe(e) && (ue(n) || a.push({
|
|
3259
3612
|
ruleId: "valid-lang",
|
|
3260
|
-
selector:
|
|
3261
|
-
html:
|
|
3613
|
+
selector: d(e),
|
|
3614
|
+
html: u(e),
|
|
3262
3615
|
impact: "serious",
|
|
3263
3616
|
message: `Invalid lang attribute value "${n}".`
|
|
3264
|
-
});
|
|
3617
|
+
}));
|
|
3265
3618
|
}
|
|
3266
3619
|
return a;
|
|
3267
3620
|
}
|
|
3268
|
-
},
|
|
3621
|
+
}, ti = {
|
|
3269
3622
|
id: "html-xml-lang-mismatch",
|
|
3270
3623
|
wcag: ["3.1.1"],
|
|
3271
3624
|
level: "A",
|
|
@@ -3281,14 +3634,14 @@ const ka = {
|
|
|
3281
3634
|
return [{
|
|
3282
3635
|
ruleId: "html-xml-lang-mismatch",
|
|
3283
3636
|
selector: "html",
|
|
3284
|
-
html:
|
|
3637
|
+
html: u(a),
|
|
3285
3638
|
impact: "moderate",
|
|
3286
3639
|
message: `lang="${e}" and xml:lang="${i}" do not match.`
|
|
3287
3640
|
}];
|
|
3288
3641
|
}
|
|
3289
3642
|
return [];
|
|
3290
3643
|
}
|
|
3291
|
-
},
|
|
3644
|
+
}, ai = {
|
|
3292
3645
|
id: "td-headers-attr",
|
|
3293
3646
|
wcag: ["1.3.1"],
|
|
3294
3647
|
level: "A",
|
|
@@ -3298,25 +3651,36 @@ const ka = {
|
|
|
3298
3651
|
run(t) {
|
|
3299
3652
|
const a = [];
|
|
3300
3653
|
for (const e of t.querySelectorAll("td[headers]")) {
|
|
3301
|
-
if (
|
|
3654
|
+
if (p(e)) continue;
|
|
3302
3655
|
const i = e.closest("table");
|
|
3303
3656
|
if (!i) continue;
|
|
3304
|
-
const n = e.getAttribute("headers").split(/\s+/);
|
|
3305
|
-
for (const
|
|
3306
|
-
if (
|
|
3657
|
+
const n = e.getAttribute("id"), r = e.getAttribute("headers").split(/\s+/);
|
|
3658
|
+
for (const o of r) {
|
|
3659
|
+
if (o === n) {
|
|
3660
|
+
a.push({
|
|
3661
|
+
ruleId: "td-headers-attr",
|
|
3662
|
+
selector: d(e),
|
|
3663
|
+
html: u(e),
|
|
3664
|
+
impact: "serious",
|
|
3665
|
+
message: `Headers attribute references the cell itself ("${o}").`
|
|
3666
|
+
});
|
|
3667
|
+
break;
|
|
3668
|
+
}
|
|
3669
|
+
if (!i.querySelector(`th#${CSS.escape(o)}, td#${CSS.escape(o)}`)) {
|
|
3307
3670
|
a.push({
|
|
3308
3671
|
ruleId: "td-headers-attr",
|
|
3309
|
-
selector:
|
|
3310
|
-
html:
|
|
3672
|
+
selector: d(e),
|
|
3673
|
+
html: u(e),
|
|
3311
3674
|
impact: "serious",
|
|
3312
|
-
message: `Headers attribute references non-existent ID "${
|
|
3675
|
+
message: `Headers attribute references non-existent ID "${o}".`
|
|
3313
3676
|
});
|
|
3314
3677
|
break;
|
|
3315
3678
|
}
|
|
3679
|
+
}
|
|
3316
3680
|
}
|
|
3317
3681
|
return a;
|
|
3318
3682
|
}
|
|
3319
|
-
},
|
|
3683
|
+
}, ii = {
|
|
3320
3684
|
id: "th-has-data-cells",
|
|
3321
3685
|
wcag: ["1.3.1"],
|
|
3322
3686
|
level: "A",
|
|
@@ -3326,19 +3690,19 @@ const ka = {
|
|
|
3326
3690
|
run(t) {
|
|
3327
3691
|
const a = [];
|
|
3328
3692
|
for (const e of t.querySelectorAll("table")) {
|
|
3329
|
-
if (
|
|
3693
|
+
if (p(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none") continue;
|
|
3330
3694
|
const i = e.querySelectorAll("th"), n = e.querySelectorAll("td");
|
|
3331
3695
|
i.length > 0 && n.length === 0 && a.push({
|
|
3332
3696
|
ruleId: "th-has-data-cells",
|
|
3333
|
-
selector:
|
|
3334
|
-
html:
|
|
3697
|
+
selector: d(e),
|
|
3698
|
+
html: u(e),
|
|
3335
3699
|
impact: "serious",
|
|
3336
3700
|
message: "Table has header cells but no data cells."
|
|
3337
3701
|
});
|
|
3338
3702
|
}
|
|
3339
3703
|
return a;
|
|
3340
3704
|
}
|
|
3341
|
-
},
|
|
3705
|
+
}, ni = {
|
|
3342
3706
|
id: "td-has-header",
|
|
3343
3707
|
wcag: ["1.3.1"],
|
|
3344
3708
|
level: "A",
|
|
@@ -3349,39 +3713,39 @@ const ka = {
|
|
|
3349
3713
|
var e, i;
|
|
3350
3714
|
const a = [];
|
|
3351
3715
|
for (const n of t.querySelectorAll("table")) {
|
|
3352
|
-
if (
|
|
3716
|
+
if (p(n) || n.getAttribute("role") === "presentation" || n.getAttribute("role") === "none") continue;
|
|
3353
3717
|
const r = n.querySelectorAll("tr"), o = r.length;
|
|
3354
3718
|
let s = 0;
|
|
3355
|
-
for (const
|
|
3356
|
-
const g =
|
|
3357
|
-
let
|
|
3358
|
-
for (const
|
|
3359
|
-
|
|
3360
|
-
s = Math.max(s,
|
|
3719
|
+
for (const m of r) {
|
|
3720
|
+
const g = m.querySelectorAll("td, th");
|
|
3721
|
+
let b = 0;
|
|
3722
|
+
for (const f of g)
|
|
3723
|
+
b += parseInt(f.getAttribute("colspan") || "1", 10);
|
|
3724
|
+
s = Math.max(s, b);
|
|
3361
3725
|
}
|
|
3362
3726
|
if (o <= 3 && s <= 3) continue;
|
|
3363
|
-
const
|
|
3364
|
-
if (
|
|
3365
|
-
for (const
|
|
3366
|
-
if (m
|
|
3367
|
-
const g =
|
|
3727
|
+
const c = n.querySelector("th") !== null, h = n.querySelector("th[scope]") !== null, l = n.querySelector("td[headers]") !== null;
|
|
3728
|
+
if (c)
|
|
3729
|
+
for (const m of n.querySelectorAll("td")) {
|
|
3730
|
+
if (p(m) || m.hasAttribute("headers")) continue;
|
|
3731
|
+
const g = m.closest("tr");
|
|
3368
3732
|
if (!g) continue;
|
|
3369
|
-
const
|
|
3733
|
+
const b = g.querySelector("th") !== null, f = Array.from(g.children).indexOf(m);
|
|
3370
3734
|
let w = !1;
|
|
3371
|
-
const
|
|
3372
|
-
if (
|
|
3373
|
-
const
|
|
3374
|
-
|
|
3735
|
+
const L = n.querySelector("thead");
|
|
3736
|
+
if (L) {
|
|
3737
|
+
const S = L.querySelector("tr");
|
|
3738
|
+
S && ((e = S.querySelectorAll("th, td")[f]) == null ? void 0 : e.tagName.toLowerCase()) === "th" && (w = !0);
|
|
3375
3739
|
}
|
|
3376
3740
|
if (!w) {
|
|
3377
|
-
const
|
|
3378
|
-
|
|
3741
|
+
const S = n.querySelector("tbody > tr, tr");
|
|
3742
|
+
S && ((i = S.querySelectorAll("th, td")[f]) == null ? void 0 : i.tagName.toLowerCase()) === "th" && (w = !0);
|
|
3379
3743
|
}
|
|
3380
|
-
if (!
|
|
3744
|
+
if (!b && !w && !h && !l) {
|
|
3381
3745
|
a.push({
|
|
3382
3746
|
ruleId: "td-has-header",
|
|
3383
|
-
selector:
|
|
3384
|
-
html:
|
|
3747
|
+
selector: d(m),
|
|
3748
|
+
html: u(m),
|
|
3385
3749
|
impact: "serious",
|
|
3386
3750
|
message: "Data cell has no associated header. Add th elements with scope, or headers attribute."
|
|
3387
3751
|
});
|
|
@@ -3391,7 +3755,7 @@ const ka = {
|
|
|
3391
3755
|
}
|
|
3392
3756
|
return a;
|
|
3393
3757
|
}
|
|
3394
|
-
},
|
|
3758
|
+
}, ri = {
|
|
3395
3759
|
id: "scope-attr-valid",
|
|
3396
3760
|
wcag: ["1.3.1"],
|
|
3397
3761
|
level: "A",
|
|
@@ -3402,19 +3766,19 @@ const ka = {
|
|
|
3402
3766
|
var i;
|
|
3403
3767
|
const a = [], e = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
|
|
3404
3768
|
for (const n of t.querySelectorAll("th[scope]")) {
|
|
3405
|
-
if (
|
|
3769
|
+
if (p(n)) continue;
|
|
3406
3770
|
const r = (i = n.getAttribute("scope")) == null ? void 0 : i.toLowerCase();
|
|
3407
3771
|
r && !e.has(r) && a.push({
|
|
3408
3772
|
ruleId: "scope-attr-valid",
|
|
3409
|
-
selector:
|
|
3410
|
-
html:
|
|
3773
|
+
selector: d(n),
|
|
3774
|
+
html: u(n),
|
|
3411
3775
|
impact: "moderate",
|
|
3412
3776
|
message: `Invalid scope value "${r}". Use row, col, rowgroup, or colgroup.`
|
|
3413
3777
|
});
|
|
3414
3778
|
}
|
|
3415
3779
|
return a;
|
|
3416
3780
|
}
|
|
3417
|
-
},
|
|
3781
|
+
}, oi = {
|
|
3418
3782
|
id: "empty-table-header",
|
|
3419
3783
|
wcag: [],
|
|
3420
3784
|
level: "A",
|
|
@@ -3425,19 +3789,19 @@ const ka = {
|
|
|
3425
3789
|
run(t) {
|
|
3426
3790
|
const a = [];
|
|
3427
3791
|
for (const e of t.querySelectorAll("th")) {
|
|
3428
|
-
if (
|
|
3792
|
+
if (p(e)) continue;
|
|
3429
3793
|
const i = e.closest("table");
|
|
3430
|
-
(i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" ||
|
|
3794
|
+
(i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" || v(e) || a.push({
|
|
3431
3795
|
ruleId: "empty-table-header",
|
|
3432
|
-
selector:
|
|
3433
|
-
html:
|
|
3796
|
+
selector: d(e),
|
|
3797
|
+
html: u(e),
|
|
3434
3798
|
impact: "minor",
|
|
3435
3799
|
message: "Table header cell is empty. Add text or use aria-label."
|
|
3436
3800
|
});
|
|
3437
3801
|
}
|
|
3438
3802
|
return a;
|
|
3439
3803
|
}
|
|
3440
|
-
},
|
|
3804
|
+
}, H = ["aria-labelledby", "aria-describedby", "aria-controls", "aria-owns", "aria-flowto"], si = {
|
|
3441
3805
|
id: "duplicate-id-aria",
|
|
3442
3806
|
wcag: ["4.1.2"],
|
|
3443
3807
|
level: "A",
|
|
@@ -3447,7 +3811,7 @@ const ka = {
|
|
|
3447
3811
|
run(t) {
|
|
3448
3812
|
const a = [], e = /* @__PURE__ */ new Set();
|
|
3449
3813
|
for (const n of t.querySelectorAll("[aria-labelledby], [aria-describedby], [aria-controls], [aria-owns], [aria-flowto]"))
|
|
3450
|
-
for (const r of
|
|
3814
|
+
for (const r of H) {
|
|
3451
3815
|
const o = n.getAttribute(r);
|
|
3452
3816
|
o && o.split(/\s+/).forEach((s) => e.add(s));
|
|
3453
3817
|
}
|
|
@@ -3461,31 +3825,31 @@ const ka = {
|
|
|
3461
3825
|
for (const [n, r] of i) {
|
|
3462
3826
|
if (r <= 1) continue;
|
|
3463
3827
|
const o = t.querySelectorAll(`#${CSS.escape(n)}`), s = t.querySelector(
|
|
3464
|
-
|
|
3465
|
-
),
|
|
3828
|
+
H.map((l) => `[${l}~="${CSS.escape(n)}"]`).join(", ")
|
|
3829
|
+
), c = t.querySelector(`label[for="${CSS.escape(n)}"]`);
|
|
3466
3830
|
let h;
|
|
3467
3831
|
if (s) {
|
|
3468
|
-
const
|
|
3469
|
-
(
|
|
3832
|
+
const l = H.find(
|
|
3833
|
+
(m) => {
|
|
3470
3834
|
var g;
|
|
3471
|
-
return (g = s.getAttribute(
|
|
3835
|
+
return (g = s.getAttribute(m)) == null ? void 0 : g.split(/\s+/).includes(n);
|
|
3472
3836
|
}
|
|
3473
3837
|
);
|
|
3474
|
-
|
|
3475
|
-
} else
|
|
3838
|
+
l && (h = l);
|
|
3839
|
+
} else c && (h = "label[for]");
|
|
3476
3840
|
a.push({
|
|
3477
3841
|
ruleId: "duplicate-id-aria",
|
|
3478
|
-
selector:
|
|
3479
|
-
html:
|
|
3842
|
+
selector: d(o[1]),
|
|
3843
|
+
html: u(o[1]),
|
|
3480
3844
|
impact: "critical",
|
|
3481
3845
|
message: `Duplicate ID "${n}" referenced by ${h ?? "an accessibility attribute"}.`,
|
|
3482
|
-
context: `First element: ${
|
|
3846
|
+
context: `First element: ${u(o[0])}${h ? `
|
|
3483
3847
|
Referenced by: ${h}` : ""}`
|
|
3484
3848
|
});
|
|
3485
3849
|
}
|
|
3486
3850
|
return a;
|
|
3487
3851
|
}
|
|
3488
|
-
},
|
|
3852
|
+
}, li = {
|
|
3489
3853
|
id: "video-caption",
|
|
3490
3854
|
wcag: ["1.2.2"],
|
|
3491
3855
|
level: "A",
|
|
@@ -3495,18 +3859,18 @@ Referenced by: ${h}` : ""}`
|
|
|
3495
3859
|
run(t) {
|
|
3496
3860
|
const a = [];
|
|
3497
3861
|
for (const e of t.querySelectorAll("video")) {
|
|
3498
|
-
if (
|
|
3862
|
+
if (p(e) || e.hasAttribute("muted") || e.hasAttribute("autoplay")) continue;
|
|
3499
3863
|
e.querySelector('track[kind="captions"], track[kind="subtitles"]') || a.push({
|
|
3500
3864
|
ruleId: "video-caption",
|
|
3501
|
-
selector:
|
|
3502
|
-
html:
|
|
3865
|
+
selector: d(e),
|
|
3866
|
+
html: u(e),
|
|
3503
3867
|
impact: "critical",
|
|
3504
3868
|
message: "Video element has no captions track."
|
|
3505
3869
|
});
|
|
3506
3870
|
}
|
|
3507
3871
|
return a;
|
|
3508
3872
|
}
|
|
3509
|
-
},
|
|
3873
|
+
}, ci = {
|
|
3510
3874
|
id: "audio-caption",
|
|
3511
3875
|
wcag: ["1.2.1"],
|
|
3512
3876
|
level: "A",
|
|
@@ -3516,19 +3880,19 @@ Referenced by: ${h}` : ""}`
|
|
|
3516
3880
|
run(t) {
|
|
3517
3881
|
const a = [];
|
|
3518
3882
|
for (const e of t.querySelectorAll("audio")) {
|
|
3519
|
-
if (
|
|
3883
|
+
if (p(e) || e.querySelector('track[kind="captions"], track[kind="descriptions"]') || e.hasAttribute("aria-describedby")) continue;
|
|
3520
3884
|
const n = e.parentElement;
|
|
3521
3885
|
n && n.querySelector('a[href*="transcript"], a[href*="text"]') || a.push({
|
|
3522
3886
|
ruleId: "audio-caption",
|
|
3523
|
-
selector:
|
|
3524
|
-
html:
|
|
3887
|
+
selector: d(e),
|
|
3888
|
+
html: u(e),
|
|
3525
3889
|
impact: "critical",
|
|
3526
3890
|
message: "Audio element has no transcript or text alternative. Add a transcript or track element."
|
|
3527
3891
|
});
|
|
3528
3892
|
}
|
|
3529
3893
|
return a;
|
|
3530
3894
|
}
|
|
3531
|
-
},
|
|
3895
|
+
}, ui = /* @__PURE__ */ new Set([
|
|
3532
3896
|
"SCRIPT",
|
|
3533
3897
|
"STYLE",
|
|
3534
3898
|
"NOSCRIPT",
|
|
@@ -3544,13 +3908,13 @@ Referenced by: ${h}` : ""}`
|
|
|
3544
3908
|
"BR",
|
|
3545
3909
|
"HR"
|
|
3546
3910
|
]);
|
|
3547
|
-
function
|
|
3911
|
+
function se([t, a, e]) {
|
|
3548
3912
|
return "#" + [t, a, e].map((i) => i.toString(16).padStart(2, "0")).join("");
|
|
3549
3913
|
}
|
|
3550
|
-
function
|
|
3914
|
+
function di(t) {
|
|
3551
3915
|
return t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement || t instanceof HTMLButtonElement ? t.disabled : !!t.closest("fieldset[disabled]");
|
|
3552
3916
|
}
|
|
3553
|
-
function
|
|
3917
|
+
function mi(t) {
|
|
3554
3918
|
const a = t.clip;
|
|
3555
3919
|
if (a && a.startsWith("rect(")) {
|
|
3556
3920
|
const i = a.match(/[\d.]+/g);
|
|
@@ -3564,17 +3928,17 @@ function _a(t) {
|
|
|
3564
3928
|
}
|
|
3565
3929
|
return !1;
|
|
3566
3930
|
}
|
|
3567
|
-
function
|
|
3568
|
-
if (
|
|
3931
|
+
function hi(t) {
|
|
3932
|
+
if (p(t)) return !0;
|
|
3569
3933
|
let a = t;
|
|
3570
3934
|
for (; a; ) {
|
|
3571
|
-
const e =
|
|
3572
|
-
if (e.display === "none" || e.visibility === "hidden" ||
|
|
3935
|
+
const e = A(a);
|
|
3936
|
+
if (e.display === "none" || e.visibility === "hidden" || mi(e)) return !0;
|
|
3573
3937
|
a = a.parentElement;
|
|
3574
3938
|
}
|
|
3575
3939
|
return !1;
|
|
3576
3940
|
}
|
|
3577
|
-
const
|
|
3941
|
+
const pi = {
|
|
3578
3942
|
id: "color-contrast",
|
|
3579
3943
|
wcag: ["1.4.3"],
|
|
3580
3944
|
level: "AA",
|
|
@@ -3589,138 +3953,138 @@ const Va = {
|
|
|
3589
3953
|
for (; r = i.nextNode(); ) {
|
|
3590
3954
|
if (!r.textContent || !r.textContent.trim()) continue;
|
|
3591
3955
|
const o = r.parentElement;
|
|
3592
|
-
if (!o || n.has(o) || (n.add(o),
|
|
3593
|
-
const s =
|
|
3956
|
+
if (!o || n.has(o) || (n.add(o), ui.has(o.tagName)) || di(o) || hi(o)) continue;
|
|
3957
|
+
const s = A(o);
|
|
3594
3958
|
if (parseFloat(s.opacity) === 0) continue;
|
|
3595
|
-
const
|
|
3596
|
-
if (!
|
|
3959
|
+
const c = R(s.color);
|
|
3960
|
+
if (!c) continue;
|
|
3597
3961
|
const h = s.color.match(/rgba\(.+?,\s*([\d.]+)\s*\)/);
|
|
3598
|
-
if (h && parseFloat(h[1]) === 0 ||
|
|
3599
|
-
const
|
|
3600
|
-
if (!
|
|
3601
|
-
const
|
|
3602
|
-
if (
|
|
3603
|
-
const w = Math.round(
|
|
3962
|
+
if (h && parseFloat(h[1]) === 0 || Oe(o)) continue;
|
|
3963
|
+
const l = $e(o);
|
|
3964
|
+
if (!l) continue;
|
|
3965
|
+
const m = q(c[0], c[1], c[2]), g = q(l[0], l[1], l[2]), b = ce(m, g), f = We(o) ? 3 : 4.5;
|
|
3966
|
+
if (b < f) {
|
|
3967
|
+
const w = Math.round(b * 100) / 100, L = se(c), S = se(l);
|
|
3604
3968
|
a.push({
|
|
3605
3969
|
ruleId: "color-contrast",
|
|
3606
|
-
selector:
|
|
3607
|
-
html:
|
|
3970
|
+
selector: d(o),
|
|
3971
|
+
html: u(o),
|
|
3608
3972
|
impact: "serious",
|
|
3609
|
-
message: `Insufficient color contrast ratio of ${w}:1 (required ${
|
|
3610
|
-
context: `foreground: ${
|
|
3973
|
+
message: `Insufficient color contrast ratio of ${w}:1 (required ${f}:1).`,
|
|
3974
|
+
context: `foreground: ${L} rgb(${c.join(", ")}), background: ${S} rgb(${l.join(", ")}), ratio: ${w}:1, required: ${f}:1`
|
|
3611
3975
|
});
|
|
3612
3976
|
}
|
|
3613
3977
|
}
|
|
3614
3978
|
return a;
|
|
3615
3979
|
}
|
|
3616
|
-
},
|
|
3980
|
+
}, de = [
|
|
3617
3981
|
// Document Structure
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3982
|
+
Gt,
|
|
3983
|
+
Xt,
|
|
3984
|
+
Yt,
|
|
3985
|
+
Kt,
|
|
3986
|
+
Qt,
|
|
3987
|
+
Zt,
|
|
3988
|
+
ea,
|
|
3989
|
+
aa,
|
|
3990
|
+
na,
|
|
3627
3991
|
// Images
|
|
3628
|
-
$e,
|
|
3629
|
-
He,
|
|
3630
|
-
De,
|
|
3631
|
-
Oe,
|
|
3632
|
-
Be,
|
|
3633
|
-
Fe,
|
|
3634
3992
|
_e,
|
|
3993
|
+
je,
|
|
3635
3994
|
Pe,
|
|
3636
|
-
|
|
3637
|
-
|
|
3995
|
+
Ve,
|
|
3996
|
+
Ue,
|
|
3638
3997
|
Ge,
|
|
3639
|
-
Xe,
|
|
3640
|
-
Ke,
|
|
3641
3998
|
Ye,
|
|
3642
|
-
|
|
3643
|
-
Ze,
|
|
3999
|
+
Ke,
|
|
3644
4000
|
et,
|
|
3645
|
-
//
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
pt,
|
|
3651
|
-
// Structure
|
|
3652
|
-
ht,
|
|
3653
|
-
Ht,
|
|
3654
|
-
Pt,
|
|
4001
|
+
// Forms
|
|
4002
|
+
rt,
|
|
4003
|
+
ot,
|
|
4004
|
+
st,
|
|
4005
|
+
lt,
|
|
3655
4006
|
gt,
|
|
3656
4007
|
bt,
|
|
3657
4008
|
ft,
|
|
3658
|
-
|
|
4009
|
+
// Keyboard
|
|
3659
4010
|
wt,
|
|
3660
|
-
yt,
|
|
3661
4011
|
At,
|
|
3662
|
-
|
|
3663
|
-
xt,
|
|
3664
|
-
kt,
|
|
3665
|
-
qt,
|
|
4012
|
+
Lt,
|
|
3666
4013
|
Ct,
|
|
3667
|
-
|
|
3668
|
-
//
|
|
4014
|
+
qt,
|
|
4015
|
+
// Structure
|
|
4016
|
+
Rt,
|
|
4017
|
+
Jt,
|
|
4018
|
+
ra,
|
|
4019
|
+
Nt,
|
|
4020
|
+
Mt,
|
|
4021
|
+
$t,
|
|
4022
|
+
Ht,
|
|
4023
|
+
Dt,
|
|
4024
|
+
Ot,
|
|
4025
|
+
Bt,
|
|
4026
|
+
Wt,
|
|
4027
|
+
_t,
|
|
4028
|
+
Ft,
|
|
4029
|
+
Pt,
|
|
3669
4030
|
Vt,
|
|
3670
4031
|
Ut,
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
ta,
|
|
3675
|
-
ia,
|
|
3676
|
-
na,
|
|
4032
|
+
// ARIA
|
|
4033
|
+
oa,
|
|
4034
|
+
sa,
|
|
3677
4035
|
la,
|
|
3678
|
-
ca,
|
|
3679
|
-
da,
|
|
3680
4036
|
ua,
|
|
3681
|
-
ma,
|
|
3682
|
-
pa,
|
|
3683
|
-
ha,
|
|
3684
4037
|
ga,
|
|
3685
|
-
ba,
|
|
3686
|
-
fa,
|
|
3687
4038
|
va,
|
|
4039
|
+
ya,
|
|
3688
4040
|
Aa,
|
|
3689
|
-
Kt,
|
|
3690
|
-
Sa,
|
|
3691
|
-
// Links
|
|
3692
4041
|
ka,
|
|
3693
4042
|
Ia,
|
|
3694
|
-
qa,
|
|
3695
|
-
// Language
|
|
3696
|
-
Ca,
|
|
3697
|
-
Ta,
|
|
3698
4043
|
Ea,
|
|
4044
|
+
Ta,
|
|
3699
4045
|
La,
|
|
3700
|
-
|
|
4046
|
+
Ca,
|
|
4047
|
+
qa,
|
|
3701
4048
|
Ra,
|
|
3702
4049
|
Na,
|
|
3703
4050
|
Ma,
|
|
3704
4051
|
$a,
|
|
3705
|
-
|
|
4052
|
+
Oa,
|
|
4053
|
+
ma,
|
|
4054
|
+
Ba,
|
|
4055
|
+
// Links
|
|
4056
|
+
_a,
|
|
4057
|
+
Fa,
|
|
4058
|
+
Xa,
|
|
4059
|
+
// Language
|
|
4060
|
+
Ya,
|
|
4061
|
+
Za,
|
|
4062
|
+
ei,
|
|
4063
|
+
ti,
|
|
4064
|
+
// Tables
|
|
4065
|
+
ai,
|
|
4066
|
+
ii,
|
|
4067
|
+
ni,
|
|
4068
|
+
ri,
|
|
4069
|
+
oi,
|
|
3706
4070
|
// Parsing
|
|
3707
|
-
|
|
4071
|
+
si,
|
|
3708
4072
|
// Media
|
|
3709
|
-
|
|
3710
|
-
|
|
4073
|
+
li,
|
|
4074
|
+
ci,
|
|
3711
4075
|
// Color
|
|
3712
|
-
|
|
4076
|
+
pi
|
|
3713
4077
|
];
|
|
3714
|
-
let
|
|
3715
|
-
function
|
|
3716
|
-
t.additionalRules && (
|
|
4078
|
+
let z = [], me = /* @__PURE__ */ new Set();
|
|
4079
|
+
function vi(t) {
|
|
4080
|
+
t.additionalRules && (z = t.additionalRules), t.disabledRules && (me = new Set(t.disabledRules));
|
|
3717
4081
|
}
|
|
3718
|
-
function
|
|
3719
|
-
return
|
|
4082
|
+
function he() {
|
|
4083
|
+
return de.filter((a) => !me.has(a.id)).concat(z);
|
|
3720
4084
|
}
|
|
3721
|
-
function
|
|
3722
|
-
|
|
3723
|
-
const a =
|
|
4085
|
+
function wi(t) {
|
|
4086
|
+
pe();
|
|
4087
|
+
const a = he(), e = [];
|
|
3724
4088
|
let i = 0;
|
|
3725
4089
|
return {
|
|
3726
4090
|
processChunk(n) {
|
|
@@ -3739,13 +4103,13 @@ function Xa(t) {
|
|
|
3739
4103
|
}
|
|
3740
4104
|
};
|
|
3741
4105
|
}
|
|
3742
|
-
function
|
|
3743
|
-
|
|
4106
|
+
function pe() {
|
|
4107
|
+
Ae(), be(), fe(), Me(), Ne(), xe();
|
|
3744
4108
|
}
|
|
3745
|
-
function
|
|
4109
|
+
function yi(t) {
|
|
3746
4110
|
var i;
|
|
3747
|
-
|
|
3748
|
-
const a =
|
|
4111
|
+
pe();
|
|
4112
|
+
const a = he(), e = [];
|
|
3749
4113
|
for (const n of a)
|
|
3750
4114
|
try {
|
|
3751
4115
|
e.push(...n.run(t));
|
|
@@ -3758,32 +4122,32 @@ function Ka(t) {
|
|
|
3758
4122
|
ruleCount: a.length
|
|
3759
4123
|
};
|
|
3760
4124
|
}
|
|
3761
|
-
const
|
|
3762
|
-
function
|
|
3763
|
-
const a =
|
|
3764
|
-
return a ||
|
|
4125
|
+
const gi = new Map(de.map((t) => [t.id, t]));
|
|
4126
|
+
function Ai(t) {
|
|
4127
|
+
const a = gi.get(t);
|
|
4128
|
+
return a || z.find((e) => e.id === t);
|
|
3765
4129
|
}
|
|
3766
4130
|
export {
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
4131
|
+
pe as clearAllCaches,
|
|
4132
|
+
Ne as clearAriaAttrAuditCache,
|
|
4133
|
+
Ae as clearAriaHiddenCache,
|
|
4134
|
+
Me as clearColorCaches,
|
|
4135
|
+
be as clearComputedRoleCache,
|
|
3772
4136
|
k as compileDeclarativeRule,
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
4137
|
+
vi as configureRules,
|
|
4138
|
+
wi as createChunkedAudit,
|
|
4139
|
+
v as getAccessibleName,
|
|
3776
4140
|
y as getAccessibleTextContent,
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
4141
|
+
he as getActiveRules,
|
|
4142
|
+
C as getComputedRole,
|
|
4143
|
+
u as getHtmlSnippet,
|
|
4144
|
+
le as getImplicitRole,
|
|
4145
|
+
Ai as getRuleById,
|
|
4146
|
+
d as getSelector,
|
|
4147
|
+
p as isAriaHidden,
|
|
4148
|
+
ye as isValidRole,
|
|
4149
|
+
bi as querySelectorShadowAware,
|
|
4150
|
+
de as rules,
|
|
4151
|
+
yi as runAudit,
|
|
4152
|
+
fi as validateDeclarativeRule
|
|
3789
4153
|
};
|