@accesslint/core 0.1.3 → 0.2.2

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