@accesslint/core 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +4 -4
- package/dist/index.iife.js +2 -2
- package/dist/index.js +103 -88
- package/dist/rules/aria/aria-allowed-attr.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -133,7 +133,7 @@ function $e(e) {
|
|
|
133
133
|
return null;
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
-
function
|
|
136
|
+
function W(e) {
|
|
137
137
|
var n;
|
|
138
138
|
const a = K.get(e);
|
|
139
139
|
if (a !== void 0) return a;
|
|
@@ -310,7 +310,7 @@ const ut = /* @__PURE__ */ new Set([
|
|
|
310
310
|
"aria-relevant",
|
|
311
311
|
"aria-roledescription"
|
|
312
312
|
]);
|
|
313
|
-
function
|
|
313
|
+
function E(e) {
|
|
314
314
|
let a = e;
|
|
315
315
|
for (; a; ) {
|
|
316
316
|
if (He(a)) return !0;
|
|
@@ -493,7 +493,7 @@ function p(e) {
|
|
|
493
493
|
const n = t.map((o, s) => (s === 0 ? "" : o.delimiter) + o.selector).join("");
|
|
494
494
|
return te.set(e, n), n;
|
|
495
495
|
}
|
|
496
|
-
function
|
|
496
|
+
function Wn(e) {
|
|
497
497
|
const a = [], t = [];
|
|
498
498
|
let i = e;
|
|
499
499
|
for (; i; ) {
|
|
@@ -909,7 +909,7 @@ function C(e) {
|
|
|
909
909
|
);
|
|
910
910
|
return r ? [parseInt(r[1]), parseInt(r[2]), parseInt(r[3])] : null;
|
|
911
911
|
}
|
|
912
|
-
function
|
|
912
|
+
function U(e) {
|
|
913
913
|
const a = e.match(/rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*([\d.]+)\s*\)/);
|
|
914
914
|
if (a) return parseFloat(a[1]);
|
|
915
915
|
const t = e.match(/rgba?\([^)]+\/\s*([\d.]+%?)\s*\)/);
|
|
@@ -957,7 +957,7 @@ function St(e) {
|
|
|
957
957
|
t = t.parentElement;
|
|
958
958
|
continue;
|
|
959
959
|
}
|
|
960
|
-
const s =
|
|
960
|
+
const s = U(o);
|
|
961
961
|
if (s < 0.01) {
|
|
962
962
|
t = t.parentElement;
|
|
963
963
|
continue;
|
|
@@ -1002,15 +1002,15 @@ function It(e, a = [255, 255, 255]) {
|
|
|
1002
1002
|
}
|
|
1003
1003
|
return t;
|
|
1004
1004
|
}
|
|
1005
|
-
const
|
|
1006
|
-
function
|
|
1005
|
+
const Et = /* @__PURE__ */ new Set(["IMG", "PICTURE", "VIDEO", "SVG"]);
|
|
1006
|
+
function qt(e) {
|
|
1007
1007
|
const a = ne.get(e);
|
|
1008
1008
|
if (a !== void 0) return a;
|
|
1009
1009
|
const t = Rt(e);
|
|
1010
1010
|
return ne.set(e, t), t;
|
|
1011
1011
|
}
|
|
1012
1012
|
function Lt(e) {
|
|
1013
|
-
return
|
|
1013
|
+
return Et.has(e.tagName) ? !0 : !!e.querySelector("img, picture, video, svg");
|
|
1014
1014
|
}
|
|
1015
1015
|
function Rt(e) {
|
|
1016
1016
|
let a = e, t = !1;
|
|
@@ -1087,7 +1087,7 @@ function $t(e) {
|
|
|
1087
1087
|
const r = getComputedStyle(a, n), o = r.content;
|
|
1088
1088
|
if (!o || o === "none" || o === "normal" || o === '""') continue;
|
|
1089
1089
|
const s = r.backgroundColor;
|
|
1090
|
-
if (s && !we(s) &&
|
|
1090
|
+
if (s && !we(s) && U(s) >= 0.1) return !0;
|
|
1091
1091
|
const l = r.backgroundImage;
|
|
1092
1092
|
if (l && l !== "none" && l !== "initial") return !0;
|
|
1093
1093
|
const d = r.position;
|
|
@@ -1098,13 +1098,13 @@ function $t(e) {
|
|
|
1098
1098
|
} catch {
|
|
1099
1099
|
}
|
|
1100
1100
|
const i = x(a).backgroundColor;
|
|
1101
|
-
if (i && !we(i) &&
|
|
1101
|
+
if (i && !we(i) && U(i) >= 1) break;
|
|
1102
1102
|
a = a.parentElement;
|
|
1103
1103
|
}
|
|
1104
1104
|
return !1;
|
|
1105
1105
|
}
|
|
1106
1106
|
const G = /* @__PURE__ */ new Map();
|
|
1107
|
-
function
|
|
1107
|
+
function Un(e, a) {
|
|
1108
1108
|
G.set(e, a), re.delete(e);
|
|
1109
1109
|
}
|
|
1110
1110
|
function Ht(e, a) {
|
|
@@ -1193,7 +1193,7 @@ const jt = {
|
|
|
1193
1193
|
fixability: "contextual",
|
|
1194
1194
|
browserHint: "Screenshot the image to describe its visual content for alt text.",
|
|
1195
1195
|
description: `Images must have alternate text. Add an alt attribute to <img> elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.`,
|
|
1196
|
-
guidance: "Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.",
|
|
1196
|
+
guidance: "Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead. When an image is inside a link or button that already has text, use alt='' if the image is decorative in that context, or write alt text that complements (not duplicates) the existing text.",
|
|
1197
1197
|
run(e) {
|
|
1198
1198
|
const a = [];
|
|
1199
1199
|
for (const t of e.querySelectorAll("img")) {
|
|
@@ -1229,14 +1229,14 @@ const jt = {
|
|
|
1229
1229
|
return a;
|
|
1230
1230
|
}
|
|
1231
1231
|
};
|
|
1232
|
-
function
|
|
1232
|
+
function Wt(e) {
|
|
1233
1233
|
var i;
|
|
1234
1234
|
const a = Pe(e);
|
|
1235
1235
|
if (a) return a;
|
|
1236
1236
|
const t = e.querySelector("title");
|
|
1237
1237
|
return (i = t == null ? void 0 : t.textContent) != null && i.trim() ? t.textContent.trim() : "";
|
|
1238
1238
|
}
|
|
1239
|
-
const
|
|
1239
|
+
const Ut = {
|
|
1240
1240
|
id: "text-alternatives/svg-img-alt",
|
|
1241
1241
|
category: "text-alternatives",
|
|
1242
1242
|
actRuleIds: ["7d6734"],
|
|
@@ -1250,7 +1250,7 @@ const Wt = {
|
|
|
1250
1250
|
const a = [], t = 'svg[role="img"], [role="graphics-document"], [role="graphics-symbol"]';
|
|
1251
1251
|
for (const i of e.querySelectorAll(t)) {
|
|
1252
1252
|
if (h(i)) continue;
|
|
1253
|
-
if (!
|
|
1253
|
+
if (!Wt(i)) {
|
|
1254
1254
|
const r = i.getAttribute("role");
|
|
1255
1255
|
a.push({
|
|
1256
1256
|
ruleId: "text-alternatives/svg-img-alt",
|
|
@@ -1441,7 +1441,7 @@ const Wt = {
|
|
|
1441
1441
|
run(e) {
|
|
1442
1442
|
const a = [];
|
|
1443
1443
|
for (const t of e.querySelectorAll("video")) {
|
|
1444
|
-
if (h(t) ||
|
|
1444
|
+
if (h(t) || E(t) || t.hasAttribute("muted") || t.hasAttribute("autoplay")) continue;
|
|
1445
1445
|
t.querySelector('track[kind="captions"], track[kind="subtitles"]') || a.push({
|
|
1446
1446
|
ruleId: "time-based-media/video-captions",
|
|
1447
1447
|
selector: p(t),
|
|
@@ -1465,7 +1465,7 @@ const Wt = {
|
|
|
1465
1465
|
run(e) {
|
|
1466
1466
|
const a = [];
|
|
1467
1467
|
for (const t of e.querySelectorAll("audio")) {
|
|
1468
|
-
if (h(t) ||
|
|
1468
|
+
if (h(t) || E(t) || t.querySelector('track[kind="captions"], track[kind="descriptions"]') || t.hasAttribute("aria-describedby")) continue;
|
|
1469
1469
|
const n = t.parentElement;
|
|
1470
1470
|
n && n.querySelector('a[href*="transcript"], a[href*="text"]') || a.push({
|
|
1471
1471
|
ruleId: "time-based-media/audio-transcript",
|
|
@@ -1564,7 +1564,7 @@ const na = {
|
|
|
1564
1564
|
run(e) {
|
|
1565
1565
|
const a = [];
|
|
1566
1566
|
for (const t of e.querySelectorAll("[autocomplete]")) {
|
|
1567
|
-
if (h(t) ||
|
|
1567
|
+
if (h(t) || E(t) || t.disabled || t.getAttribute("aria-disabled") === "true") continue;
|
|
1568
1568
|
const i = t.getAttribute("autocomplete").trim();
|
|
1569
1569
|
i && (ia(i) || a.push({
|
|
1570
1570
|
ruleId: "adaptable/autocomplete-valid",
|
|
@@ -2007,14 +2007,14 @@ function fa(e, a) {
|
|
|
2007
2007
|
for (const s of e.querySelectorAll("*")) {
|
|
2008
2008
|
if (h(s)) continue;
|
|
2009
2009
|
r = !0;
|
|
2010
|
-
const l =
|
|
2010
|
+
const l = W(s);
|
|
2011
2011
|
l && n.add(l);
|
|
2012
2012
|
}
|
|
2013
2013
|
for (const s of t) {
|
|
2014
2014
|
const l = i.getElementById(s);
|
|
2015
2015
|
if (l && !h(l)) {
|
|
2016
2016
|
r = !0;
|
|
2017
|
-
const d =
|
|
2017
|
+
const d = W(l);
|
|
2018
2018
|
d && n.add(d);
|
|
2019
2019
|
}
|
|
2020
2020
|
}
|
|
@@ -2091,7 +2091,7 @@ const va = {
|
|
|
2091
2091
|
const r = Se[n];
|
|
2092
2092
|
let o = i.parentElement, s = !1;
|
|
2093
2093
|
for (; o && o !== e.documentElement; ) {
|
|
2094
|
-
const l =
|
|
2094
|
+
const l = W(o);
|
|
2095
2095
|
if (l && r.includes(l)) {
|
|
2096
2096
|
s = !0;
|
|
2097
2097
|
break;
|
|
@@ -2294,7 +2294,7 @@ const ka = {
|
|
|
2294
2294
|
}
|
|
2295
2295
|
return a;
|
|
2296
2296
|
}
|
|
2297
|
-
},
|
|
2297
|
+
}, Ea = {
|
|
2298
2298
|
id: "distinguishable/meta-viewport",
|
|
2299
2299
|
category: "distinguishable",
|
|
2300
2300
|
actRuleIds: ["b4f0c3"],
|
|
@@ -2340,7 +2340,7 @@ const ka = {
|
|
|
2340
2340
|
function ce(e) {
|
|
2341
2341
|
return e.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
2342
2342
|
}
|
|
2343
|
-
function
|
|
2343
|
+
function We(e, a) {
|
|
2344
2344
|
const t = e.getAttribute("style");
|
|
2345
2345
|
if (!t) return null;
|
|
2346
2346
|
const i = new RegExp(
|
|
@@ -2387,7 +2387,7 @@ function Ue(e, a) {
|
|
|
2387
2387
|
}
|
|
2388
2388
|
return null;
|
|
2389
2389
|
}
|
|
2390
|
-
function
|
|
2390
|
+
function Ue(e, a, t, i) {
|
|
2391
2391
|
function n(r) {
|
|
2392
2392
|
var o;
|
|
2393
2393
|
if (r !== e) {
|
|
@@ -2409,7 +2409,7 @@ function We(e, a, t, i) {
|
|
|
2409
2409
|
}
|
|
2410
2410
|
return n(e);
|
|
2411
2411
|
}
|
|
2412
|
-
function
|
|
2412
|
+
function qa(e) {
|
|
2413
2413
|
var a;
|
|
2414
2414
|
for (const t of e.childNodes)
|
|
2415
2415
|
if (t.nodeType === 3 && ((a = t.textContent) != null && a.trim()))
|
|
@@ -2431,7 +2431,7 @@ function Ve(e) {
|
|
|
2431
2431
|
return !1;
|
|
2432
2432
|
}
|
|
2433
2433
|
function de(e, a) {
|
|
2434
|
-
if (
|
|
2434
|
+
if (qa(e)) return !0;
|
|
2435
2435
|
for (const t of e.children) {
|
|
2436
2436
|
const i = t.getAttribute("style") || "";
|
|
2437
2437
|
if (!new RegExp(
|
|
@@ -2446,10 +2446,10 @@ function Be(e, a, t, i) {
|
|
|
2446
2446
|
const n = [];
|
|
2447
2447
|
for (const r of e.querySelectorAll("[style]")) {
|
|
2448
2448
|
if (h(r) || !Oe(r) || Ve(r) || !de(r, t)) continue;
|
|
2449
|
-
const o =
|
|
2449
|
+
const o = We(r, t);
|
|
2450
2450
|
if (!o) continue;
|
|
2451
2451
|
let s = !1;
|
|
2452
|
-
if (o.em !== null ? s = o.em < i : o.px !== null && (s =
|
|
2452
|
+
if (o.em !== null ? s = o.em < i : o.px !== null && (s = Ue(r, t, o.px, i)), s) {
|
|
2453
2453
|
const l = o.em !== null ? `${o.em}${t === "line-height" ? "" : "em"}` : `${o.px}px`;
|
|
2454
2454
|
n.push({
|
|
2455
2455
|
ruleId: a,
|
|
@@ -2503,10 +2503,10 @@ const Ra = {
|
|
|
2503
2503
|
const r = parseFloat(x(t).lineHeight);
|
|
2504
2504
|
if (r > 0 && t.scrollHeight <= r * 1.5) continue;
|
|
2505
2505
|
}
|
|
2506
|
-
const i =
|
|
2506
|
+
const i = We(t, "line-height");
|
|
2507
2507
|
if (!i) continue;
|
|
2508
2508
|
let n = !1;
|
|
2509
|
-
if (i.em !== null ? n = i.em < 1.5 : i.px !== null && (n =
|
|
2509
|
+
if (i.em !== null ? n = i.em < 1.5 : i.px !== null && (n = Ue(t, "line-height", i.px, 1.5)), n) {
|
|
2510
2510
|
const r = i.em !== null ? `${i.em}` : `${i.px}px`;
|
|
2511
2511
|
a.push({
|
|
2512
2512
|
ruleId: "distinguishable/line-height",
|
|
@@ -2567,7 +2567,7 @@ function $a(e) {
|
|
|
2567
2567
|
const o = i.match(new RegExp("\\p{L}{3,}", "gu"));
|
|
2568
2568
|
return !n || !o || o.length < 2 ? null : { block: a, textColor: n };
|
|
2569
2569
|
}
|
|
2570
|
-
function
|
|
2570
|
+
function Ee(e, a) {
|
|
2571
2571
|
const t = e.textDecorationLine || e.textDecoration || "";
|
|
2572
2572
|
return (t.includes("underline") || t.includes("line-through")) && t !== a;
|
|
2573
2573
|
}
|
|
@@ -2599,13 +2599,13 @@ const Da = {
|
|
|
2599
2599
|
const n = $a(t);
|
|
2600
2600
|
if (!n) continue;
|
|
2601
2601
|
const r = x(n.block), o = r.textDecorationLine || r.textDecoration || "";
|
|
2602
|
-
if (
|
|
2602
|
+
if (Ee(i, o) || (parseFloat(i.borderBottomWidth) || 0) > 0 && i.borderBottomStyle !== "none" && i.borderBottomStyle !== "hidden" || Math.abs(V(i.fontWeight) - V(r.fontWeight)) >= 300 || i.fontStyle !== r.fontStyle) continue;
|
|
2603
2603
|
const l = parseFloat(i.fontSize) || 16, d = parseFloat(r.fontSize) || 16;
|
|
2604
2604
|
if (d > 0 && l / d >= 1.2) continue;
|
|
2605
2605
|
let c = !1;
|
|
2606
2606
|
for (const y of t.querySelectorAll("*")) {
|
|
2607
2607
|
const A = x(y);
|
|
2608
|
-
if (
|
|
2608
|
+
if (Ee(A, o) || Math.abs(V(A.fontWeight) - V(r.fontWeight)) >= 300) {
|
|
2609
2609
|
c = !0;
|
|
2610
2610
|
break;
|
|
2611
2611
|
}
|
|
@@ -2671,7 +2671,7 @@ function za(e) {
|
|
|
2671
2671
|
function ja(e) {
|
|
2672
2672
|
return e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement || e instanceof HTMLButtonElement ? e.disabled : !!(e.closest("fieldset[disabled]") || e.getAttribute("aria-disabled") === "true");
|
|
2673
2673
|
}
|
|
2674
|
-
function
|
|
2674
|
+
function Wa(e, a) {
|
|
2675
2675
|
if (e.tagName !== "LABEL") return !1;
|
|
2676
2676
|
const t = e, i = t.htmlFor;
|
|
2677
2677
|
if (i) {
|
|
@@ -2683,7 +2683,7 @@ function Ua(e, a) {
|
|
|
2683
2683
|
const r = t.id;
|
|
2684
2684
|
return !!(r && a.querySelector(`[aria-labelledby~="${r}"][aria-disabled="true"]`));
|
|
2685
2685
|
}
|
|
2686
|
-
function
|
|
2686
|
+
function Ua(e) {
|
|
2687
2687
|
return e.closest("select") !== null;
|
|
2688
2688
|
}
|
|
2689
2689
|
function Oa(e) {
|
|
@@ -2708,10 +2708,10 @@ function _a(e) {
|
|
|
2708
2708
|
const a = parseFloat(e);
|
|
2709
2709
|
return isNaN(a) ? NaN : e.trim().endsWith("%") ? a / 100 : a;
|
|
2710
2710
|
}
|
|
2711
|
-
const
|
|
2711
|
+
const qe = /([a-z-]+)\(([^)]*)\)/g;
|
|
2712
2712
|
function Le(e) {
|
|
2713
2713
|
let a, t = !1;
|
|
2714
|
-
for (
|
|
2714
|
+
for (qe.lastIndex = 0; a = qe.exec(e); ) {
|
|
2715
2715
|
t = !0;
|
|
2716
2716
|
const i = Ba[a[1]];
|
|
2717
2717
|
if (i === void 0 || _a(a[2]) !== i) return !1;
|
|
@@ -2742,7 +2742,7 @@ function Ya(e) {
|
|
|
2742
2742
|
a = a.parentElement;
|
|
2743
2743
|
continue;
|
|
2744
2744
|
}
|
|
2745
|
-
if (
|
|
2745
|
+
if (U(n) < 0.01) {
|
|
2746
2746
|
a = a.parentElement;
|
|
2747
2747
|
continue;
|
|
2748
2748
|
}
|
|
@@ -2787,7 +2787,7 @@ function _e(e, a, t) {
|
|
|
2787
2787
|
const l = s.parentElement;
|
|
2788
2788
|
if (!l || o.has(l) || (o.add(l), Pa.has(l.tagName))) continue;
|
|
2789
2789
|
const d = l.tagName;
|
|
2790
|
-
if (d === "BODY" || d === "HTML" ||
|
|
2790
|
+
if (d === "BODY" || d === "HTML" || Ua(l) || ja(l) || Wa(l, e) || Va(l) || za(l)) continue;
|
|
2791
2791
|
const c = x(l);
|
|
2792
2792
|
if (parseFloat(c.opacity) === 0) continue;
|
|
2793
2793
|
const u = Mt(l);
|
|
@@ -2797,15 +2797,15 @@ function _e(e, a, t) {
|
|
|
2797
2797
|
if (b && b !== "none" && b !== "initial" && (g = Tt(b), !g) || Ga(l) || $t(l)) continue;
|
|
2798
2798
|
const f = C(c.color);
|
|
2799
2799
|
if (!f) continue;
|
|
2800
|
-
const v =
|
|
2801
|
-
if (v === 0 ||
|
|
2800
|
+
const v = U(c.color);
|
|
2801
|
+
if (v === 0 || qt(l)) continue;
|
|
2802
2802
|
const y = t === "AAA" ? xe(l) ? 4.5 : 7 : xe(l) ? 3 : 4.5;
|
|
2803
2803
|
let A = ye(l);
|
|
2804
2804
|
if (!A) {
|
|
2805
2805
|
if (g) continue;
|
|
2806
|
-
const
|
|
2807
|
-
if (
|
|
2808
|
-
const O =
|
|
2806
|
+
const q = Ya(l);
|
|
2807
|
+
if (q) {
|
|
2808
|
+
const O = q.gradientEl.parentElement ? ye(q.gradientEl.parentElement) : null, H = Xa(
|
|
2809
2809
|
l,
|
|
2810
2810
|
f,
|
|
2811
2811
|
v,
|
|
@@ -2813,7 +2813,7 @@ function _e(e, a, t) {
|
|
|
2813
2813
|
y,
|
|
2814
2814
|
a,
|
|
2815
2815
|
t,
|
|
2816
|
-
|
|
2816
|
+
q.bgImage,
|
|
2817
2817
|
O ?? [255, 255, 255]
|
|
2818
2818
|
);
|
|
2819
2819
|
H && i.push(H);
|
|
@@ -2824,14 +2824,14 @@ function _e(e, a, t) {
|
|
|
2824
2824
|
v < 1 && (S = R(f, A, v)), u < 1 && (S = R(S, A, u));
|
|
2825
2825
|
const nt = I(S[0], S[1], S[2]), rt = I(A[0], A[1], A[2]), be = g ? Nt(S, A, g) : $(nt, rt);
|
|
2826
2826
|
if (be < y) {
|
|
2827
|
-
const
|
|
2827
|
+
const q = Math.round(be * 100) / 100, O = _(S), H = _(A);
|
|
2828
2828
|
i.push({
|
|
2829
2829
|
ruleId: a,
|
|
2830
2830
|
selector: p(l),
|
|
2831
2831
|
html: m(l),
|
|
2832
2832
|
impact: "serious",
|
|
2833
|
-
message: `Insufficient${t === "AAA" ? " enhanced" : ""} color contrast ratio of ${
|
|
2834
|
-
context: `foreground: ${O} rgb(${S.join(", ")}), background: ${H} rgb(${A.join(", ")}), ratio: ${
|
|
2833
|
+
message: `Insufficient${t === "AAA" ? " enhanced" : ""} color contrast ratio of ${q}:1 (required ${y}:1).`,
|
|
2834
|
+
context: `foreground: ${O} rgb(${S.join(", ")}), background: ${H} rgb(${A.join(", ")}), ratio: ${q}:1, required: ${y}:1`,
|
|
2835
2835
|
fix: { type: "suggest", suggestion: `Change the text color or background color so the contrast ratio meets ${y}:1. Current foreground is ${O}, background is ${H}.` }
|
|
2836
2836
|
});
|
|
2837
2837
|
}
|
|
@@ -3484,7 +3484,7 @@ const bi = {
|
|
|
3484
3484
|
return a;
|
|
3485
3485
|
}
|
|
3486
3486
|
};
|
|
3487
|
-
function
|
|
3487
|
+
function Ei(e) {
|
|
3488
3488
|
var n, r;
|
|
3489
3489
|
const a = [], t = e.getAttribute("href");
|
|
3490
3490
|
t && a.push(`href: ${t}`);
|
|
@@ -3501,7 +3501,7 @@ function qi(e) {
|
|
|
3501
3501
|
return a.length > 0 ? a.join(`
|
|
3502
3502
|
`) : void 0;
|
|
3503
3503
|
}
|
|
3504
|
-
const
|
|
3504
|
+
const qi = {
|
|
3505
3505
|
id: "navigable/link-name",
|
|
3506
3506
|
category: "navigable",
|
|
3507
3507
|
actRuleIds: ["c487ae"],
|
|
@@ -3514,14 +3514,14 @@ const Ei = {
|
|
|
3514
3514
|
run(e) {
|
|
3515
3515
|
const a = [];
|
|
3516
3516
|
for (const t of e.querySelectorAll('a[href], area[href], [role="link"]')) {
|
|
3517
|
-
if (h(t) ||
|
|
3517
|
+
if (h(t) || E(t) || t.getRootNode() instanceof ShadowRoot) continue;
|
|
3518
3518
|
w(t) || a.push({
|
|
3519
3519
|
ruleId: "navigable/link-name",
|
|
3520
3520
|
selector: p(t),
|
|
3521
3521
|
html: m(t),
|
|
3522
3522
|
impact: "serious",
|
|
3523
3523
|
message: "Link has no discernible text.",
|
|
3524
|
-
context:
|
|
3524
|
+
context: Ei(t),
|
|
3525
3525
|
fix: { type: "add-text-content" }
|
|
3526
3526
|
});
|
|
3527
3527
|
}
|
|
@@ -3761,13 +3761,13 @@ const Ei = {
|
|
|
3761
3761
|
}
|
|
3762
3762
|
}, ji = new Set(
|
|
3763
3763
|
"aa ab ae af ak am an ar as av ay az ba be bg bh bi bm bn bo br bs ca ce ch co cr cs cu cv cy da de dv dz ee el en eo es et eu fa ff fi fj fo fr fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id ie ig ii ik io is it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mr ms mt my na nb nd ne ng nl nn no nr nv ny oc oj om or os pa pi pl ps pt qu rm rn ro ru rw sa sc sd se sg si sk sl sm sn so sq sr ss st su sv sw ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zu".split(" ")
|
|
3764
|
-
),
|
|
3764
|
+
), Wi = new Set(
|
|
3765
3765
|
"aar abk afr aka amh ara arg asm ava ave aym aze bak bam bel ben bih bis bod bos bre bul cat ces cha che chu chv cor cos cre cym dan deu div dzo ell eng epo est eus ewe fao fas fij fin fra fry ful gla gle glg glv grn guj hat hau hbs heb her hin hmo hrv hun hye ibo iii iku ile ina ind ipk isl ita jav jpn kal kan kas kat kau kaz khm kik kin kir kom kon kor kua kur lao lat lav lim lin lit ltz lub lug mah mal mar mkd mlg mlt mon mri msa mya nau nav nbl nde ndo nep nld nno nob nor nya oci oji ori orm oss pan pli pol por pus que roh ron run rus sag san sin slk slv sme smo sna snd som sot spa sqi srd srp ssw sun swa swe tah tam tat tel tgk tgl tha tir ton tsn tso tuk tur twi uig ukr urd uzb ven vie vol wln wol xho yid yor zha zho zul".split(" ")
|
|
3766
|
-
),
|
|
3766
|
+
), Ui = /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i;
|
|
3767
3767
|
function Ke(e) {
|
|
3768
|
-
if (!
|
|
3768
|
+
if (!Ui.test(e)) return !1;
|
|
3769
3769
|
const a = e.split("-")[0].toLowerCase();
|
|
3770
|
-
return a.length === 2 ? ji.has(a) : a.length === 3 ? !
|
|
3770
|
+
return a.length === 2 ? ji.has(a) : a.length === 3 ? !Wi.has(a) : !1;
|
|
3771
3771
|
}
|
|
3772
3772
|
function Ce(e) {
|
|
3773
3773
|
var i;
|
|
@@ -4034,7 +4034,7 @@ const en = {
|
|
|
4034
4034
|
var i;
|
|
4035
4035
|
const a = [], t = e.querySelectorAll(`${Qe}, ${Ji}`);
|
|
4036
4036
|
for (const n of t) {
|
|
4037
|
-
if (h(n) ||
|
|
4037
|
+
if (h(n) || E(n)) continue;
|
|
4038
4038
|
const r = (i = n.getAttribute("role")) == null ? void 0 : i.trim().toLowerCase();
|
|
4039
4039
|
if (r === "presentation" || r === "none") continue;
|
|
4040
4040
|
if (!Zi(n)) {
|
|
@@ -4107,7 +4107,7 @@ const en = {
|
|
|
4107
4107
|
for (const n of e.querySelectorAll(
|
|
4108
4108
|
'input[type="submit"], input[type="button"], input[type="reset"]'
|
|
4109
4109
|
)) {
|
|
4110
|
-
if (h(n) ||
|
|
4110
|
+
if (h(n) || E(n)) continue;
|
|
4111
4111
|
const r = (t = n.getAttribute("value")) == null ? void 0 : t.trim(), o = (i = n.getAttribute("type")) == null ? void 0 : i.toLowerCase(), s = (o === "submit" || o === "reset") && !n.hasAttribute("value");
|
|
4112
4112
|
!r && !s && !w(n) && a.push({
|
|
4113
4113
|
ruleId: "labels-and-names/input-button-name",
|
|
@@ -4221,7 +4221,7 @@ const nn = {
|
|
|
4221
4221
|
var t;
|
|
4222
4222
|
const a = [];
|
|
4223
4223
|
for (const i of e.querySelectorAll('[role="button"], [role="link"], [role="menuitem"]')) {
|
|
4224
|
-
if (h(i) ||
|
|
4224
|
+
if (h(i) || E(i) || se(i)) continue;
|
|
4225
4225
|
const n = i.getAttribute("role");
|
|
4226
4226
|
if ((i.tagName.toLowerCase() === "button" || i.tagName.toLowerCase() === "a") && n !== "menuitem") continue;
|
|
4227
4227
|
if (!w(i)) {
|
|
@@ -4254,7 +4254,7 @@ function M(e) {
|
|
|
4254
4254
|
var i;
|
|
4255
4255
|
const t = [];
|
|
4256
4256
|
for (const n of a.querySelectorAll(e.selector)) {
|
|
4257
|
-
if (h(n) || e.checkComputedHidden &&
|
|
4257
|
+
if (h(n) || e.checkComputedHidden && E(n) || e.checkShadowDOM && se(n)) continue;
|
|
4258
4258
|
if (e.roleSet) {
|
|
4259
4259
|
const o = (i = n.getAttribute("role")) == null ? void 0 : i.trim().toLowerCase();
|
|
4260
4260
|
if (!o || !e.roleSet.has(o)) continue;
|
|
@@ -4366,7 +4366,7 @@ const hn = {
|
|
|
4366
4366
|
run(e) {
|
|
4367
4367
|
const a = [];
|
|
4368
4368
|
for (const t of e.querySelectorAll('button, [role="button"]')) {
|
|
4369
|
-
if (h(t) ||
|
|
4369
|
+
if (h(t) || E(t)) continue;
|
|
4370
4370
|
const i = t.getAttribute("role");
|
|
4371
4371
|
if ((i === "none" || i === "presentation") && !(t.matches('button:not([disabled]), [tabindex]:not([tabindex="-1"])') || t.tagName.toLowerCase() === "button" && !t.disabled) || se(t)) continue;
|
|
4372
4372
|
w(t) || a.push({
|
|
@@ -4642,30 +4642,45 @@ Referenced by: ${d}` : ""}`,
|
|
|
4642
4642
|
description: "ARIA attributes must be allowed for the element's role.",
|
|
4643
4643
|
guidance: "Each ARIA role supports specific attributes. Using unsupported attributes creates confusion for assistive technologies. Check the ARIA specification for which attributes are valid for each role, or remove the attribute if it's not needed.",
|
|
4644
4644
|
run(e) {
|
|
4645
|
-
const a = []
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4645
|
+
const a = [], t = new Set(e.querySelectorAll("[role]")), i = e.createTreeWalker(
|
|
4646
|
+
e.body || e.documentElement,
|
|
4647
|
+
1
|
|
4648
|
+
/* NodeFilter.SHOW_ELEMENT */
|
|
4649
|
+
);
|
|
4650
|
+
let n = i.currentNode;
|
|
4651
|
+
for (; n; ) {
|
|
4652
|
+
if (n instanceof Element) {
|
|
4653
|
+
for (const r of n.attributes)
|
|
4654
|
+
if (r.name.startsWith("aria-")) {
|
|
4655
|
+
t.add(n);
|
|
4656
|
+
break;
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
n = i.nextNode();
|
|
4660
|
+
}
|
|
4661
|
+
for (const r of t) {
|
|
4662
|
+
if (h(r)) continue;
|
|
4663
|
+
const o = W(r);
|
|
4664
|
+
if (!o) continue;
|
|
4665
|
+
const s = Sn[o];
|
|
4666
|
+
if (s)
|
|
4667
|
+
for (const l of r.attributes) {
|
|
4668
|
+
if (!l.name.startsWith("aria-") || ut.has(l.name) || s.has(l.name)) continue;
|
|
4669
|
+
const d = s.size > 0 ? [...s].join(", ") : "none (only global ARIA attributes)";
|
|
4655
4670
|
a.push({
|
|
4656
4671
|
ruleId: "aria/aria-allowed-attr",
|
|
4657
|
-
selector: p(
|
|
4658
|
-
html: m(
|
|
4672
|
+
selector: p(r),
|
|
4673
|
+
html: m(r),
|
|
4659
4674
|
impact: "critical",
|
|
4660
|
-
message: `ARIA attribute "${
|
|
4661
|
-
context: `Attribute: ${
|
|
4662
|
-
fix: { type: "remove-attribute", attribute:
|
|
4675
|
+
message: `ARIA attribute "${l.name}" is not allowed on role "${o}".`,
|
|
4676
|
+
context: `Attribute: ${l.name}="${l.value}", role: ${o}, allowed role-specific attributes: ${d}`,
|
|
4677
|
+
fix: { type: "remove-attribute", attribute: l.name }
|
|
4663
4678
|
});
|
|
4664
4679
|
}
|
|
4665
4680
|
}
|
|
4666
4681
|
return a;
|
|
4667
4682
|
}
|
|
4668
|
-
},
|
|
4683
|
+
}, En = /* @__PURE__ */ new Set([
|
|
4669
4684
|
"base",
|
|
4670
4685
|
"col",
|
|
4671
4686
|
"colgroup",
|
|
@@ -4787,10 +4802,10 @@ Referenced by: ${d}` : ""}`,
|
|
|
4787
4802
|
video: /* @__PURE__ */ new Set(["application"]),
|
|
4788
4803
|
wbr: /* @__PURE__ */ new Set(["none", "presentation"])
|
|
4789
4804
|
};
|
|
4790
|
-
function
|
|
4805
|
+
function qn(e) {
|
|
4791
4806
|
var t;
|
|
4792
4807
|
const a = e.tagName.toLowerCase();
|
|
4793
|
-
if (
|
|
4808
|
+
if (En.has(a))
|
|
4794
4809
|
return "none";
|
|
4795
4810
|
if (a === "a" && e.hasAttribute("href"))
|
|
4796
4811
|
return D["a[href]"];
|
|
@@ -4819,7 +4834,7 @@ const Ln = {
|
|
|
4819
4834
|
if (!n) continue;
|
|
4820
4835
|
const r = $e(i);
|
|
4821
4836
|
if (r && n === r) continue;
|
|
4822
|
-
const o =
|
|
4837
|
+
const o = qn(i);
|
|
4823
4838
|
o === "none" ? a.push({
|
|
4824
4839
|
ruleId: "aria/aria-allowed-role",
|
|
4825
4840
|
selector: p(i),
|
|
@@ -5031,7 +5046,7 @@ const Pn = {
|
|
|
5031
5046
|
const a = [];
|
|
5032
5047
|
for (const t of e.querySelectorAll("*")) {
|
|
5033
5048
|
if (h(t)) continue;
|
|
5034
|
-
const i =
|
|
5049
|
+
const i = W(t);
|
|
5035
5050
|
if (!(!i || !Fn.has(i))) {
|
|
5036
5051
|
for (const n of t.querySelectorAll(j))
|
|
5037
5052
|
if (n !== t && !n.disabled) {
|
|
@@ -5051,7 +5066,7 @@ const Pn = {
|
|
|
5051
5066
|
}, Ze = [
|
|
5052
5067
|
// Text Alternatives
|
|
5053
5068
|
jt,
|
|
5054
|
-
|
|
5069
|
+
Ut,
|
|
5055
5070
|
Ot,
|
|
5056
5071
|
Vt,
|
|
5057
5072
|
_t,
|
|
@@ -5076,7 +5091,7 @@ const Pn = {
|
|
|
5076
5091
|
Sa,
|
|
5077
5092
|
Ia,
|
|
5078
5093
|
// Distinguishable
|
|
5079
|
-
|
|
5094
|
+
Ea,
|
|
5080
5095
|
Ra,
|
|
5081
5096
|
Ca,
|
|
5082
5097
|
Ta,
|
|
@@ -5103,7 +5118,7 @@ const Pn = {
|
|
|
5103
5118
|
ki,
|
|
5104
5119
|
Si,
|
|
5105
5120
|
Ii,
|
|
5106
|
-
|
|
5121
|
+
qi,
|
|
5107
5122
|
Li,
|
|
5108
5123
|
// Landmarks
|
|
5109
5124
|
Ri,
|
|
@@ -5244,7 +5259,7 @@ const Xn = {
|
|
|
5244
5259
|
"enough-time/meta-refresh": { description: "Meta refresh must not redirect or refresh automatically.", guidance: "Automatic page refreshes or redirects can disorient users, especially those using screen readers or with cognitive disabilities. They may lose their place or not have time to read content. If a redirect is needed, use a server-side redirect (HTTP 301/302) instead. For timed refreshes, provide user controls.", messages: { "Page redirects after {0} seconds without warning. Use server-side redirect.": "Page redirects after {0} seconds without warning. Use server-side redirect.", "Page auto-refreshes after {0} seconds. Provide user control over refresh.": "Page auto-refreshes after {0} seconds. Provide user control over refresh." } },
|
|
5245
5260
|
"enough-time/blink": { description: "The <blink> element must not be used.", 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.", messages: { "The <blink> element causes accessibility issues. Remove it entirely.": "The <blink> element causes accessibility issues. Remove it entirely." } },
|
|
5246
5261
|
"enough-time/marquee": { description: "The <marquee> element must not be used.", 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.", messages: { "The <marquee> element causes accessibility issues. Replace with static content.": "The <marquee> element causes accessibility issues. Replace with static content." } },
|
|
5247
|
-
"text-alternatives/img-alt": { description: `Images must have alternate text. Add an alt attribute to <img> elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.`, guidance: "Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.", messages: { 'Image has whitespace-only alt text. Use alt="" for decorative images or provide descriptive text.': 'Image has whitespace-only alt text. Use alt="" for decorative images or provide descriptive text.', "Image element missing alt attribute.": "Image element missing alt attribute.", 'Element with role="img" has no accessible name. Add aria-label or aria-labelledby.': 'Element with role="img" has no accessible name. Add aria-label or aria-labelledby.' } },
|
|
5262
|
+
"text-alternatives/img-alt": { description: `Images must have alternate text. Add an alt attribute to <img> elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.`, guidance: "Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead. When an image is inside a link or button that already has text, use alt='' if the image is decorative in that context, or write alt text that complements (not duplicates) the existing text.", messages: { 'Image has whitespace-only alt text. Use alt="" for decorative images or provide descriptive text.': 'Image has whitespace-only alt text. Use alt="" for decorative images or provide descriptive text.', "Image element missing alt attribute.": "Image element missing alt attribute.", 'Element with role="img" has no accessible name. Add aria-label or aria-labelledby.': 'Element with role="img" has no accessible name. Add aria-label or aria-labelledby.' } },
|
|
5248
5263
|
"text-alternatives/svg-img-alt": { description: "SVG elements with an img, graphics-document, or graphics-symbol role must have an accessible name via a <title> element, aria-label, or aria-labelledby.", guidance: "Inline SVGs with role='img' need accessible names. Add a <title> element as the first child of the SVG (screen readers will announce it), or use aria-label on the SVG element. For complex SVGs, use aria-labelledby referencing both a <title> and <desc> element. Decorative SVGs should use aria-hidden='true' instead.", messages: { "{0} with role='{1}' has no accessible name.": "{0} with role='{1}' has no accessible name." } },
|
|
5249
5264
|
"text-alternatives/input-image-alt": { description: 'Image inputs (<input type="image">) must have alternate text describing the button action.', guidance: "Image buttons (<input type='image'>) act as submit buttons with a custom image. Add alt text via alt, aria-label, or aria-labelledby that describes the action (e.g. alt='Search' or alt='Submit order'), not the image itself. Without it, screen readers announce only 'image' or the filename, giving no clue what the button does.", messages: { "Image input missing alt text.": "Image input missing alt text." } },
|
|
5250
5265
|
"text-alternatives/image-redundant-alt": { description: "Image alt text should not duplicate adjacent link or button text. When alt text repeats surrounding text, screen reader users hear the same information twice.", guidance: "When an image is inside a link or button that also has text, make the alt text complementary rather than identical. If the image is purely decorative in that context, use alt='' to avoid repetition.", messages: { 'Alt text "{0}" duplicates surrounding {1} text.': 'Alt text "{0}" duplicates surrounding {1} text.' } },
|
|
@@ -5434,7 +5449,7 @@ export {
|
|
|
5434
5449
|
w as getAccessibleName,
|
|
5435
5450
|
k as getAccessibleTextContent,
|
|
5436
5451
|
pe as getActiveRules,
|
|
5437
|
-
|
|
5452
|
+
W as getComputedRole,
|
|
5438
5453
|
m as getHtmlSnippet,
|
|
5439
5454
|
$e as getImplicitRole,
|
|
5440
5455
|
Yn as getRuleById,
|
|
@@ -5443,8 +5458,8 @@ export {
|
|
|
5443
5458
|
dt as isValidRole,
|
|
5444
5459
|
Xn as localeEn,
|
|
5445
5460
|
Jn as localeEs,
|
|
5446
|
-
|
|
5447
|
-
|
|
5461
|
+
Wn as querySelectorShadowAware,
|
|
5462
|
+
Un as registerLocale,
|
|
5448
5463
|
Ze as rules,
|
|
5449
5464
|
_n as runAudit,
|
|
5450
5465
|
ze as translateViolations,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aria-allowed-attr.d.ts","sourceRoot":"","sources":["../../../src/rules/aria/aria-allowed-attr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAgFrC,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"aria-allowed-attr.d.ts","sourceRoot":"","sources":["../../../src/rules/aria/aria-allowed-attr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAgFrC,eAAO,MAAM,eAAe,EAAE,IA0D7B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@accesslint/core",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Pure accessibility rule engine — WCAG audit with zero browser dependencies",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"build": "vite build --config vite.lib.config.ts && vite build --config vite.iife.config.ts && tsc -p tsconfig.lib.json",
|
|
22
22
|
"test": "vitest run",
|
|
23
23
|
"test:coverage": "vitest run --coverage",
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
"test:memory": "vitest run --config vite.memory.config.ts",
|
|
26
26
|
"act:download": "scripts/download-act-fixtures.sh && npx tsx src/act/download-fixtures.ts",
|
|
27
27
|
"test:act": "vitest run src/act/act.test.ts",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
"@playwright/test": "^1.58.2",
|
|
44
44
|
"@vitest/coverage-v8": "^3.2.4",
|
|
45
45
|
"happy-dom": "^20.4.0",
|