test-a11y-js 0.5.5 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/{chunk-SC53YK5A.mjs → chunk-JFZXPUZY.mjs} +1185 -57
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1185 -57
- package/dist/index.mjs +1 -1
- package/dist/linter/eslint-plugin/index.js +1185 -57
- package/dist/linter/eslint-plugin/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -11075,9 +11075,9 @@ var require_CSSStyleRule = __commonJS({
|
|
|
11075
11075
|
return text;
|
|
11076
11076
|
},
|
|
11077
11077
|
set: function(cssText) {
|
|
11078
|
-
var
|
|
11079
|
-
this.style =
|
|
11080
|
-
this.selectorText =
|
|
11078
|
+
var rule14 = CSSOM.CSSStyleRule.parse(cssText);
|
|
11079
|
+
this.style = rule14.style;
|
|
11080
|
+
this.selectorText = rule14.selectorText;
|
|
11081
11081
|
}
|
|
11082
11082
|
});
|
|
11083
11083
|
CSSOM.CSSStyleRule.parse = function(ruleText) {
|
|
@@ -11215,11 +11215,11 @@ var require_CSSStyleSheet = __commonJS({
|
|
|
11215
11215
|
};
|
|
11216
11216
|
CSSOM.CSSStyleSheet.prototype = new CSSOM.StyleSheet();
|
|
11217
11217
|
CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
|
|
11218
|
-
CSSOM.CSSStyleSheet.prototype.insertRule = function(
|
|
11218
|
+
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule14, index) {
|
|
11219
11219
|
if (index < 0 || index > this.cssRules.length) {
|
|
11220
11220
|
throw new RangeError("INDEX_SIZE_ERR");
|
|
11221
11221
|
}
|
|
11222
|
-
var cssRule = CSSOM.parse(
|
|
11222
|
+
var cssRule = CSSOM.parse(rule14).cssRules[0];
|
|
11223
11223
|
cssRule.parentStyleSheet = this;
|
|
11224
11224
|
this.cssRules.splice(index, 0, cssRule);
|
|
11225
11225
|
return index;
|
|
@@ -11414,11 +11414,11 @@ var require_CSSGroupingRule = __commonJS({
|
|
|
11414
11414
|
};
|
|
11415
11415
|
CSSOM.CSSGroupingRule.prototype = new CSSOM.CSSRule();
|
|
11416
11416
|
CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
11417
|
-
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(
|
|
11417
|
+
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(rule14, index) {
|
|
11418
11418
|
if (index < 0 || index > this.cssRules.length) {
|
|
11419
11419
|
throw new RangeError("INDEX_SIZE_ERR");
|
|
11420
11420
|
}
|
|
11421
|
-
var cssRule = CSSOM.parse(
|
|
11421
|
+
var cssRule = CSSOM.parse(rule14).cssRules[0];
|
|
11422
11422
|
cssRule.parentRule = this;
|
|
11423
11423
|
this.cssRules.splice(index, 0, cssRule);
|
|
11424
11424
|
return index;
|
|
@@ -12618,9 +12618,9 @@ var require_clone = __commonJS({
|
|
|
12618
12618
|
return cloned;
|
|
12619
12619
|
}
|
|
12620
12620
|
for (var i = 0, rulesLength = rules.length; i < rulesLength; i++) {
|
|
12621
|
-
var
|
|
12622
|
-
var ruleClone = cloned.cssRules[i] = new
|
|
12623
|
-
var style =
|
|
12621
|
+
var rule14 = rules[i];
|
|
12622
|
+
var ruleClone = cloned.cssRules[i] = new rule14.constructor();
|
|
12623
|
+
var style = rule14.style;
|
|
12624
12624
|
if (style) {
|
|
12625
12625
|
var styleClone = ruleClone.style = new CSSOM.CSSStyleDeclaration();
|
|
12626
12626
|
for (var j = 0, styleLength = style.length; j < styleLength; j++) {
|
|
@@ -12630,23 +12630,23 @@ var require_clone = __commonJS({
|
|
|
12630
12630
|
}
|
|
12631
12631
|
styleClone.length = style.length;
|
|
12632
12632
|
}
|
|
12633
|
-
if (
|
|
12634
|
-
ruleClone.keyText =
|
|
12633
|
+
if (rule14.hasOwnProperty("keyText")) {
|
|
12634
|
+
ruleClone.keyText = rule14.keyText;
|
|
12635
12635
|
}
|
|
12636
|
-
if (
|
|
12637
|
-
ruleClone.selectorText =
|
|
12636
|
+
if (rule14.hasOwnProperty("selectorText")) {
|
|
12637
|
+
ruleClone.selectorText = rule14.selectorText;
|
|
12638
12638
|
}
|
|
12639
|
-
if (
|
|
12640
|
-
ruleClone.mediaText =
|
|
12639
|
+
if (rule14.hasOwnProperty("mediaText")) {
|
|
12640
|
+
ruleClone.mediaText = rule14.mediaText;
|
|
12641
12641
|
}
|
|
12642
|
-
if (
|
|
12643
|
-
ruleClone.conditionText =
|
|
12642
|
+
if (rule14.hasOwnProperty("conditionText")) {
|
|
12643
|
+
ruleClone.conditionText = rule14.conditionText;
|
|
12644
12644
|
}
|
|
12645
|
-
if (
|
|
12646
|
-
ruleClone.layerName =
|
|
12645
|
+
if (rule14.hasOwnProperty("layerName")) {
|
|
12646
|
+
ruleClone.layerName = rule14.layerName;
|
|
12647
12647
|
}
|
|
12648
|
-
if (
|
|
12649
|
-
ruleClone.cssRules = clone(
|
|
12648
|
+
if (rule14.hasOwnProperty("cssRules")) {
|
|
12649
|
+
ruleClone.cssRules = clone(rule14).cssRules;
|
|
12650
12650
|
}
|
|
12651
12651
|
}
|
|
12652
12652
|
return cloned;
|
|
@@ -28132,9 +28132,9 @@ var require_CSSStyleRule2 = __commonJS({
|
|
|
28132
28132
|
return text;
|
|
28133
28133
|
},
|
|
28134
28134
|
set: function(cssText) {
|
|
28135
|
-
var
|
|
28136
|
-
this.style =
|
|
28137
|
-
this.selectorText =
|
|
28135
|
+
var rule14 = CSSOM.CSSStyleRule.parse(cssText);
|
|
28136
|
+
this.style = rule14.style;
|
|
28137
|
+
this.selectorText = rule14.selectorText;
|
|
28138
28138
|
}
|
|
28139
28139
|
});
|
|
28140
28140
|
CSSOM.CSSStyleRule.parse = function(ruleText) {
|
|
@@ -28272,11 +28272,11 @@ var require_CSSStyleSheet2 = __commonJS({
|
|
|
28272
28272
|
};
|
|
28273
28273
|
CSSOM.CSSStyleSheet.prototype = new CSSOM.StyleSheet();
|
|
28274
28274
|
CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
|
|
28275
|
-
CSSOM.CSSStyleSheet.prototype.insertRule = function(
|
|
28275
|
+
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule14, index) {
|
|
28276
28276
|
if (index < 0 || index > this.cssRules.length) {
|
|
28277
28277
|
throw new RangeError("INDEX_SIZE_ERR");
|
|
28278
28278
|
}
|
|
28279
|
-
var cssRule = CSSOM.parse(
|
|
28279
|
+
var cssRule = CSSOM.parse(rule14).cssRules[0];
|
|
28280
28280
|
cssRule.parentStyleSheet = this;
|
|
28281
28281
|
this.cssRules.splice(index, 0, cssRule);
|
|
28282
28282
|
return index;
|
|
@@ -28471,11 +28471,11 @@ var require_CSSGroupingRule2 = __commonJS({
|
|
|
28471
28471
|
};
|
|
28472
28472
|
CSSOM.CSSGroupingRule.prototype = new CSSOM.CSSRule();
|
|
28473
28473
|
CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
28474
|
-
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(
|
|
28474
|
+
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(rule14, index) {
|
|
28475
28475
|
if (index < 0 || index > this.cssRules.length) {
|
|
28476
28476
|
throw new RangeError("INDEX_SIZE_ERR");
|
|
28477
28477
|
}
|
|
28478
|
-
var cssRule = CSSOM.parse(
|
|
28478
|
+
var cssRule = CSSOM.parse(rule14).cssRules[0];
|
|
28479
28479
|
cssRule.parentRule = this;
|
|
28480
28480
|
this.cssRules.splice(index, 0, cssRule);
|
|
28481
28481
|
return index;
|
|
@@ -29509,9 +29509,9 @@ var require_clone2 = __commonJS({
|
|
|
29509
29509
|
return cloned;
|
|
29510
29510
|
}
|
|
29511
29511
|
for (var i = 0, rulesLength = rules.length; i < rulesLength; i++) {
|
|
29512
|
-
var
|
|
29513
|
-
var ruleClone = cloned.cssRules[i] = new
|
|
29514
|
-
var style =
|
|
29512
|
+
var rule14 = rules[i];
|
|
29513
|
+
var ruleClone = cloned.cssRules[i] = new rule14.constructor();
|
|
29514
|
+
var style = rule14.style;
|
|
29515
29515
|
if (style) {
|
|
29516
29516
|
var styleClone = ruleClone.style = new CSSOM.CSSStyleDeclaration();
|
|
29517
29517
|
for (var j = 0, styleLength = style.length; j < styleLength; j++) {
|
|
@@ -29521,20 +29521,20 @@ var require_clone2 = __commonJS({
|
|
|
29521
29521
|
}
|
|
29522
29522
|
styleClone.length = style.length;
|
|
29523
29523
|
}
|
|
29524
|
-
if (
|
|
29525
|
-
ruleClone.keyText =
|
|
29524
|
+
if (rule14.hasOwnProperty("keyText")) {
|
|
29525
|
+
ruleClone.keyText = rule14.keyText;
|
|
29526
29526
|
}
|
|
29527
|
-
if (
|
|
29528
|
-
ruleClone.selectorText =
|
|
29527
|
+
if (rule14.hasOwnProperty("selectorText")) {
|
|
29528
|
+
ruleClone.selectorText = rule14.selectorText;
|
|
29529
29529
|
}
|
|
29530
|
-
if (
|
|
29531
|
-
ruleClone.mediaText =
|
|
29530
|
+
if (rule14.hasOwnProperty("mediaText")) {
|
|
29531
|
+
ruleClone.mediaText = rule14.mediaText;
|
|
29532
29532
|
}
|
|
29533
|
-
if (
|
|
29534
|
-
ruleClone.conditionText =
|
|
29533
|
+
if (rule14.hasOwnProperty("conditionText")) {
|
|
29534
|
+
ruleClone.conditionText = rule14.conditionText;
|
|
29535
29535
|
}
|
|
29536
|
-
if (
|
|
29537
|
-
ruleClone.cssRules = clone(
|
|
29536
|
+
if (rule14.hasOwnProperty("cssRules")) {
|
|
29537
|
+
ruleClone.cssRules = clone(rule14).cssRules;
|
|
29538
29538
|
}
|
|
29539
29539
|
}
|
|
29540
29540
|
return cloned;
|
|
@@ -64268,17 +64268,17 @@ var require_style_rules = __commonJS({
|
|
|
64268
64268
|
};
|
|
64269
64269
|
function forEachMatchingSheetRuleOfElement(elementImpl, handleRule) {
|
|
64270
64270
|
function handleSheet(sheet) {
|
|
64271
|
-
forEach.call(sheet.cssRules, (
|
|
64272
|
-
if (
|
|
64273
|
-
if (indexOf.call(
|
|
64274
|
-
forEach.call(
|
|
64271
|
+
forEach.call(sheet.cssRules, (rule14) => {
|
|
64272
|
+
if (rule14.media) {
|
|
64273
|
+
if (indexOf.call(rule14.media, "screen") !== -1) {
|
|
64274
|
+
forEach.call(rule14.cssRules, (innerRule) => {
|
|
64275
64275
|
if (matches2(innerRule, elementImpl)) {
|
|
64276
64276
|
handleRule(innerRule);
|
|
64277
64277
|
}
|
|
64278
64278
|
});
|
|
64279
64279
|
}
|
|
64280
|
-
} else if (matches2(
|
|
64281
|
-
handleRule(
|
|
64280
|
+
} else if (matches2(rule14, elementImpl)) {
|
|
64281
|
+
handleRule(rule14);
|
|
64282
64282
|
}
|
|
64283
64283
|
});
|
|
64284
64284
|
}
|
|
@@ -64315,9 +64315,9 @@ var require_style_rules = __commonJS({
|
|
|
64315
64315
|
);
|
|
64316
64316
|
}
|
|
64317
64317
|
}
|
|
64318
|
-
forEachMatchingSheetRuleOfElement(elementImpl, (
|
|
64319
|
-
forEach.call(
|
|
64320
|
-
handleProperty(
|
|
64318
|
+
forEachMatchingSheetRuleOfElement(elementImpl, (rule14) => {
|
|
64319
|
+
forEach.call(rule14.style, (property) => {
|
|
64320
|
+
handleProperty(rule14.style, property);
|
|
64321
64321
|
});
|
|
64322
64322
|
});
|
|
64323
64323
|
forEach.call(elementImpl.style, (property) => {
|
|
@@ -64326,8 +64326,8 @@ var require_style_rules = __commonJS({
|
|
|
64326
64326
|
styleCache.set(elementImpl, declaration);
|
|
64327
64327
|
return declaration;
|
|
64328
64328
|
};
|
|
64329
|
-
function matches2(
|
|
64330
|
-
return matchesDontThrow(
|
|
64329
|
+
function matches2(rule14, elementImpl) {
|
|
64330
|
+
return matchesDontThrow(rule14.selectorText, elementImpl);
|
|
64331
64331
|
}
|
|
64332
64332
|
function getCascadedPropertyValue(element, property) {
|
|
64333
64333
|
return exports.getDeclarationForElement(element).getPropertyValue(property);
|
|
@@ -170729,6 +170729,13 @@ var recommended = {
|
|
|
170729
170729
|
"test-a11y-js/button-label": "error",
|
|
170730
170730
|
"test-a11y-js/form-label": "error",
|
|
170731
170731
|
"test-a11y-js/iframe-title": "error",
|
|
170732
|
+
"test-a11y-js/fieldset-legend": "error",
|
|
170733
|
+
"test-a11y-js/table-structure": "error",
|
|
170734
|
+
"test-a11y-js/details-summary": "error",
|
|
170735
|
+
"test-a11y-js/video-captions": "error",
|
|
170736
|
+
"test-a11y-js/audio-captions": "error",
|
|
170737
|
+
"test-a11y-js/landmark-roles": "warn",
|
|
170738
|
+
"test-a11y-js/dialog-modal": "error",
|
|
170732
170739
|
// Moderate/Minor violations - set to warn
|
|
170733
170740
|
"test-a11y-js/link-text": "warn",
|
|
170734
170741
|
"test-a11y-js/heading-order": "warn"
|
|
@@ -170743,7 +170750,14 @@ var strict = {
|
|
|
170743
170750
|
"test-a11y-js/link-text": "error",
|
|
170744
170751
|
"test-a11y-js/form-label": "error",
|
|
170745
170752
|
"test-a11y-js/heading-order": "error",
|
|
170746
|
-
"test-a11y-js/iframe-title": "error"
|
|
170753
|
+
"test-a11y-js/iframe-title": "error",
|
|
170754
|
+
"test-a11y-js/fieldset-legend": "error",
|
|
170755
|
+
"test-a11y-js/table-structure": "error",
|
|
170756
|
+
"test-a11y-js/details-summary": "error",
|
|
170757
|
+
"test-a11y-js/video-captions": "error",
|
|
170758
|
+
"test-a11y-js/audio-captions": "error",
|
|
170759
|
+
"test-a11y-js/landmark-roles": "error",
|
|
170760
|
+
"test-a11y-js/dialog-modal": "error"
|
|
170747
170761
|
};
|
|
170748
170762
|
var strict_default = strict;
|
|
170749
170763
|
|
|
@@ -170882,6 +170896,254 @@ var A11yChecker = class {
|
|
|
170882
170896
|
}
|
|
170883
170897
|
return violations;
|
|
170884
170898
|
}
|
|
170899
|
+
static checkFieldsetLegend(element) {
|
|
170900
|
+
const violations = [];
|
|
170901
|
+
const fieldsets = element.getElementsByTagName("fieldset");
|
|
170902
|
+
for (const fieldset of Array.from(fieldsets)) {
|
|
170903
|
+
const legend = Array.from(fieldset.children).find(
|
|
170904
|
+
(child) => child.tagName.toLowerCase() === "legend"
|
|
170905
|
+
);
|
|
170906
|
+
if (!legend) {
|
|
170907
|
+
violations.push({
|
|
170908
|
+
id: "fieldset-legend",
|
|
170909
|
+
description: "fieldset must have a legend element as a direct child",
|
|
170910
|
+
element: fieldset,
|
|
170911
|
+
impact: "serious"
|
|
170912
|
+
});
|
|
170913
|
+
} else if (!legend.textContent?.trim()) {
|
|
170914
|
+
violations.push({
|
|
170915
|
+
id: "fieldset-legend-empty",
|
|
170916
|
+
description: "fieldset legend must have non-empty text content",
|
|
170917
|
+
element: fieldset,
|
|
170918
|
+
impact: "serious"
|
|
170919
|
+
});
|
|
170920
|
+
}
|
|
170921
|
+
}
|
|
170922
|
+
return violations;
|
|
170923
|
+
}
|
|
170924
|
+
static checkTableStructure(element) {
|
|
170925
|
+
const violations = [];
|
|
170926
|
+
const tables = element.getElementsByTagName("table");
|
|
170927
|
+
for (const table of Array.from(tables)) {
|
|
170928
|
+
const hasCaption = table.querySelector("caption");
|
|
170929
|
+
const hasAriaLabel = table.hasAttribute("aria-label");
|
|
170930
|
+
const hasAriaLabelledBy = table.hasAttribute("aria-labelledby");
|
|
170931
|
+
if (!hasCaption && !hasAriaLabel && !hasAriaLabelledBy) {
|
|
170932
|
+
violations.push({
|
|
170933
|
+
id: "table-caption",
|
|
170934
|
+
description: "Table must have a caption or aria-label/aria-labelledby",
|
|
170935
|
+
element: table,
|
|
170936
|
+
impact: "serious"
|
|
170937
|
+
});
|
|
170938
|
+
}
|
|
170939
|
+
const headerCells = table.querySelectorAll("th");
|
|
170940
|
+
const dataCells = table.querySelectorAll("td");
|
|
170941
|
+
if (dataCells.length > 0 && headerCells.length === 0) {
|
|
170942
|
+
violations.push({
|
|
170943
|
+
id: "table-headers",
|
|
170944
|
+
description: "Table must have header cells (th elements) when it has data cells",
|
|
170945
|
+
element: table,
|
|
170946
|
+
impact: "serious"
|
|
170947
|
+
});
|
|
170948
|
+
}
|
|
170949
|
+
for (const th of Array.from(headerCells)) {
|
|
170950
|
+
if (!th.hasAttribute("scope")) {
|
|
170951
|
+
violations.push({
|
|
170952
|
+
id: "table-header-scope",
|
|
170953
|
+
description: "Table header cells (th) should have a scope attribute",
|
|
170954
|
+
element: th,
|
|
170955
|
+
impact: "moderate"
|
|
170956
|
+
});
|
|
170957
|
+
}
|
|
170958
|
+
}
|
|
170959
|
+
}
|
|
170960
|
+
return violations;
|
|
170961
|
+
}
|
|
170962
|
+
static checkDetailsSummary(element) {
|
|
170963
|
+
const violations = [];
|
|
170964
|
+
const detailsElements = element.getElementsByTagName("details");
|
|
170965
|
+
for (const details of Array.from(detailsElements)) {
|
|
170966
|
+
const firstChild = details.firstElementChild;
|
|
170967
|
+
if (!firstChild || firstChild.tagName.toLowerCase() !== "summary") {
|
|
170968
|
+
violations.push({
|
|
170969
|
+
id: "details-summary",
|
|
170970
|
+
description: "details element must have a summary element as its first child",
|
|
170971
|
+
element: details,
|
|
170972
|
+
impact: "serious"
|
|
170973
|
+
});
|
|
170974
|
+
} else if (!firstChild.textContent?.trim()) {
|
|
170975
|
+
violations.push({
|
|
170976
|
+
id: "details-summary-empty",
|
|
170977
|
+
description: "details summary element must have non-empty text content",
|
|
170978
|
+
element: details,
|
|
170979
|
+
impact: "serious"
|
|
170980
|
+
});
|
|
170981
|
+
}
|
|
170982
|
+
}
|
|
170983
|
+
return violations;
|
|
170984
|
+
}
|
|
170985
|
+
static checkVideoCaptions(element) {
|
|
170986
|
+
const violations = [];
|
|
170987
|
+
const videos = element.getElementsByTagName("video");
|
|
170988
|
+
for (const video of Array.from(videos)) {
|
|
170989
|
+
const tracks = video.querySelectorAll("track");
|
|
170990
|
+
const captionTracks = Array.from(tracks).filter(
|
|
170991
|
+
(track) => track.getAttribute("kind")?.toLowerCase() === "captions"
|
|
170992
|
+
);
|
|
170993
|
+
if (captionTracks.length === 0) {
|
|
170994
|
+
violations.push({
|
|
170995
|
+
id: "video-captions",
|
|
170996
|
+
description: 'Video element must have at least one track element with kind="captions"',
|
|
170997
|
+
element: video,
|
|
170998
|
+
impact: "serious"
|
|
170999
|
+
});
|
|
171000
|
+
} else {
|
|
171001
|
+
for (const track of captionTracks) {
|
|
171002
|
+
if (!track.hasAttribute("srclang")) {
|
|
171003
|
+
violations.push({
|
|
171004
|
+
id: "video-track-srclang",
|
|
171005
|
+
description: "Video caption track must have a srclang attribute",
|
|
171006
|
+
element: track,
|
|
171007
|
+
impact: "serious"
|
|
171008
|
+
});
|
|
171009
|
+
}
|
|
171010
|
+
if (!track.hasAttribute("label")) {
|
|
171011
|
+
violations.push({
|
|
171012
|
+
id: "video-track-label",
|
|
171013
|
+
description: "Video caption track should have a label attribute",
|
|
171014
|
+
element: track,
|
|
171015
|
+
impact: "moderate"
|
|
171016
|
+
});
|
|
171017
|
+
}
|
|
171018
|
+
}
|
|
171019
|
+
}
|
|
171020
|
+
}
|
|
171021
|
+
return violations;
|
|
171022
|
+
}
|
|
171023
|
+
static checkAudioCaptions(element) {
|
|
171024
|
+
const violations = [];
|
|
171025
|
+
const audios = element.getElementsByTagName("audio");
|
|
171026
|
+
for (const audio of Array.from(audios)) {
|
|
171027
|
+
const tracks = audio.querySelectorAll("track");
|
|
171028
|
+
const hasTranscript = audio.hasAttribute("aria-describedby") || audio.querySelector('a[href*="transcript"]') || audio.closest("div")?.querySelector('a[href*="transcript"]');
|
|
171029
|
+
if (tracks.length === 0 && !hasTranscript) {
|
|
171030
|
+
violations.push({
|
|
171031
|
+
id: "audio-captions",
|
|
171032
|
+
description: "Audio element must have track elements or a transcript link",
|
|
171033
|
+
element: audio,
|
|
171034
|
+
impact: "serious"
|
|
171035
|
+
});
|
|
171036
|
+
} else if (tracks.length > 0) {
|
|
171037
|
+
for (const track of Array.from(tracks)) {
|
|
171038
|
+
if (!track.hasAttribute("srclang")) {
|
|
171039
|
+
violations.push({
|
|
171040
|
+
id: "audio-track-srclang",
|
|
171041
|
+
description: "Audio track must have a srclang attribute",
|
|
171042
|
+
element: track,
|
|
171043
|
+
impact: "serious"
|
|
171044
|
+
});
|
|
171045
|
+
}
|
|
171046
|
+
if (!track.hasAttribute("label")) {
|
|
171047
|
+
violations.push({
|
|
171048
|
+
id: "audio-track-label",
|
|
171049
|
+
description: "Audio track should have a label attribute",
|
|
171050
|
+
element: track,
|
|
171051
|
+
impact: "moderate"
|
|
171052
|
+
});
|
|
171053
|
+
}
|
|
171054
|
+
}
|
|
171055
|
+
}
|
|
171056
|
+
}
|
|
171057
|
+
return violations;
|
|
171058
|
+
}
|
|
171059
|
+
static checkLandmarks(element) {
|
|
171060
|
+
const violations = [];
|
|
171061
|
+
const landmarkTags = ["nav", "main", "header", "footer", "aside", "section", "article"];
|
|
171062
|
+
const mainElements = element.getElementsByTagName("main");
|
|
171063
|
+
if (mainElements.length > 1) {
|
|
171064
|
+
const mains = Array.from(mainElements);
|
|
171065
|
+
for (let i = 1; i < mains.length; i++) {
|
|
171066
|
+
violations.push({
|
|
171067
|
+
id: "landmark-multiple-main",
|
|
171068
|
+
description: "Page should have only one main element",
|
|
171069
|
+
element: mains[i],
|
|
171070
|
+
impact: "serious"
|
|
171071
|
+
});
|
|
171072
|
+
}
|
|
171073
|
+
}
|
|
171074
|
+
for (const tag of landmarkTags) {
|
|
171075
|
+
const landmarks = element.getElementsByTagName(tag);
|
|
171076
|
+
for (const landmark of Array.from(landmarks)) {
|
|
171077
|
+
if (tag === "section" || tag === "article") {
|
|
171078
|
+
const hasHeading = landmark.querySelector("h1, h2, h3, h4, h5, h6");
|
|
171079
|
+
const hasAriaLabel = landmark.hasAttribute("aria-label");
|
|
171080
|
+
const hasAriaLabelledBy = landmark.hasAttribute("aria-labelledby");
|
|
171081
|
+
if (!hasHeading && !hasAriaLabel && !hasAriaLabelledBy) {
|
|
171082
|
+
violations.push({
|
|
171083
|
+
id: "landmark-missing-name",
|
|
171084
|
+
description: `${tag} element should have an accessible name (heading, aria-label, or aria-labelledby)`,
|
|
171085
|
+
element: landmark,
|
|
171086
|
+
impact: "moderate"
|
|
171087
|
+
});
|
|
171088
|
+
}
|
|
171089
|
+
}
|
|
171090
|
+
if (tag === "nav" || tag === "aside") {
|
|
171091
|
+
const hasAriaLabel = landmark.hasAttribute("aria-label");
|
|
171092
|
+
const hasAriaLabelledBy = landmark.hasAttribute("aria-labelledby");
|
|
171093
|
+
const sameType = Array.from(element.getElementsByTagName(tag));
|
|
171094
|
+
const unnamed = sameType.filter(
|
|
171095
|
+
(l) => !l.hasAttribute("aria-label") && !l.hasAttribute("aria-labelledby")
|
|
171096
|
+
);
|
|
171097
|
+
if (unnamed.length > 1 && !hasAriaLabel && !hasAriaLabelledBy) {
|
|
171098
|
+
violations.push({
|
|
171099
|
+
id: "landmark-duplicate-unnamed",
|
|
171100
|
+
description: `Multiple ${tag} elements found. Each should have an accessible name (aria-label or aria-labelledby)`,
|
|
171101
|
+
element: landmark,
|
|
171102
|
+
impact: "moderate"
|
|
171103
|
+
});
|
|
171104
|
+
}
|
|
171105
|
+
}
|
|
171106
|
+
}
|
|
171107
|
+
}
|
|
171108
|
+
return violations;
|
|
171109
|
+
}
|
|
171110
|
+
static checkDialogModal(element) {
|
|
171111
|
+
const violations = [];
|
|
171112
|
+
const dialogs = element.getElementsByTagName("dialog");
|
|
171113
|
+
for (const dialog of Array.from(dialogs)) {
|
|
171114
|
+
const hasAriaLabel = dialog.hasAttribute("aria-label");
|
|
171115
|
+
const hasAriaLabelledBy = dialog.hasAttribute("aria-labelledby");
|
|
171116
|
+
const hasHeading = dialog.querySelector("h1, h2, h3, h4, h5, h6");
|
|
171117
|
+
if (!hasAriaLabel && !hasAriaLabelledBy && !hasHeading) {
|
|
171118
|
+
violations.push({
|
|
171119
|
+
id: "dialog-missing-name",
|
|
171120
|
+
description: "Dialog element must have an accessible name (aria-label, aria-labelledby, or heading)",
|
|
171121
|
+
element: dialog,
|
|
171122
|
+
impact: "serious"
|
|
171123
|
+
});
|
|
171124
|
+
}
|
|
171125
|
+
const isModal = dialog.hasAttribute("open") || dialog.getAttribute("aria-modal") === "true";
|
|
171126
|
+
if (isModal && !dialog.hasAttribute("aria-modal")) {
|
|
171127
|
+
violations.push({
|
|
171128
|
+
id: "dialog-missing-modal",
|
|
171129
|
+
description: 'Modal dialog should have aria-modal="true" attribute',
|
|
171130
|
+
element: dialog,
|
|
171131
|
+
impact: "moderate"
|
|
171132
|
+
});
|
|
171133
|
+
}
|
|
171134
|
+
const hasRole = dialog.hasAttribute("role");
|
|
171135
|
+
const roleValue = dialog.getAttribute("role");
|
|
171136
|
+
if (hasRole && roleValue !== "dialog" && roleValue !== "alertdialog") {
|
|
171137
|
+
violations.push({
|
|
171138
|
+
id: "dialog-invalid-role",
|
|
171139
|
+
description: 'Dialog element should have role="dialog" or role="alertdialog"',
|
|
171140
|
+
element: dialog,
|
|
171141
|
+
impact: "moderate"
|
|
171142
|
+
});
|
|
171143
|
+
}
|
|
171144
|
+
}
|
|
171145
|
+
return violations;
|
|
171146
|
+
}
|
|
170885
171147
|
static async check(element) {
|
|
170886
171148
|
const violations = [
|
|
170887
171149
|
...this.checkImageAlt(element),
|
|
@@ -170889,7 +171151,14 @@ var A11yChecker = class {
|
|
|
170889
171151
|
...this.checkButtonLabel(element),
|
|
170890
171152
|
...this.checkFormLabels(element),
|
|
170891
171153
|
...this.checkHeadingOrder(element),
|
|
170892
|
-
...this.checkIframeTitle(element)
|
|
171154
|
+
...this.checkIframeTitle(element),
|
|
171155
|
+
...this.checkFieldsetLegend(element),
|
|
171156
|
+
...this.checkTableStructure(element),
|
|
171157
|
+
...this.checkDetailsSummary(element),
|
|
171158
|
+
...this.checkVideoCaptions(element),
|
|
171159
|
+
...this.checkAudioCaptions(element),
|
|
171160
|
+
...this.checkLandmarks(element),
|
|
171161
|
+
...this.checkDialogModal(element)
|
|
170893
171162
|
];
|
|
170894
171163
|
if (violations.length > 0) {
|
|
170895
171164
|
console.warn("\nAccessibility Violations Found:");
|
|
@@ -171845,11 +172114,863 @@ var rule6 = {
|
|
|
171845
172114
|
};
|
|
171846
172115
|
var iframe_title_default = rule6;
|
|
171847
172116
|
|
|
172117
|
+
// src/linter/eslint-plugin/rules/fieldset-legend.ts
|
|
172118
|
+
var rule7 = {
|
|
172119
|
+
meta: {
|
|
172120
|
+
type: "problem",
|
|
172121
|
+
docs: {
|
|
172122
|
+
description: "Enforce fieldset elements have a legend element as a direct child",
|
|
172123
|
+
category: "Accessibility",
|
|
172124
|
+
recommended: true,
|
|
172125
|
+
url: "https://github.com/nolrm/test-a11y-js"
|
|
172126
|
+
},
|
|
172127
|
+
messages: {
|
|
172128
|
+
missingLegend: "fieldset must have a legend element as a direct child",
|
|
172129
|
+
emptyLegend: "fieldset legend must have non-empty text content"
|
|
172130
|
+
},
|
|
172131
|
+
fixable: void 0,
|
|
172132
|
+
schema: []
|
|
172133
|
+
},
|
|
172134
|
+
create(context) {
|
|
172135
|
+
return {
|
|
172136
|
+
// Check JSX fieldset elements
|
|
172137
|
+
JSXOpeningElement(node) {
|
|
172138
|
+
const jsxNode = node;
|
|
172139
|
+
if (jsxNode.name?.name === "fieldset") {
|
|
172140
|
+
try {
|
|
172141
|
+
const element = jsxToElement(node, context);
|
|
172142
|
+
const violations = A11yChecker.checkFieldsetLegend(element);
|
|
172143
|
+
for (const violation of violations) {
|
|
172144
|
+
if (violation.id === "fieldset-legend") {
|
|
172145
|
+
context.report({
|
|
172146
|
+
node,
|
|
172147
|
+
messageId: "missingLegend"
|
|
172148
|
+
});
|
|
172149
|
+
} else if (violation.id === "fieldset-legend-empty") {
|
|
172150
|
+
context.report({
|
|
172151
|
+
node,
|
|
172152
|
+
messageId: "emptyLegend"
|
|
172153
|
+
});
|
|
172154
|
+
}
|
|
172155
|
+
}
|
|
172156
|
+
} catch (error2) {
|
|
172157
|
+
}
|
|
172158
|
+
}
|
|
172159
|
+
},
|
|
172160
|
+
// Check HTML strings
|
|
172161
|
+
Literal(node) {
|
|
172162
|
+
if (isHTMLLiteral(node)) {
|
|
172163
|
+
const element = htmlNodeToElement(node, context);
|
|
172164
|
+
if (element) {
|
|
172165
|
+
const violations = A11yChecker.checkFieldsetLegend(element);
|
|
172166
|
+
for (const violation of violations) {
|
|
172167
|
+
if (violation.id === "fieldset-legend") {
|
|
172168
|
+
context.report({
|
|
172169
|
+
node,
|
|
172170
|
+
messageId: "missingLegend"
|
|
172171
|
+
});
|
|
172172
|
+
} else if (violation.id === "fieldset-legend-empty") {
|
|
172173
|
+
context.report({
|
|
172174
|
+
node,
|
|
172175
|
+
messageId: "emptyLegend"
|
|
172176
|
+
});
|
|
172177
|
+
}
|
|
172178
|
+
}
|
|
172179
|
+
}
|
|
172180
|
+
}
|
|
172181
|
+
},
|
|
172182
|
+
TemplateLiteral(node) {
|
|
172183
|
+
if (isHTMLLiteral(node)) {
|
|
172184
|
+
const element = htmlNodeToElement(node, context);
|
|
172185
|
+
if (element) {
|
|
172186
|
+
const violations = A11yChecker.checkFieldsetLegend(element);
|
|
172187
|
+
for (const violation of violations) {
|
|
172188
|
+
if (violation.id === "fieldset-legend") {
|
|
172189
|
+
context.report({
|
|
172190
|
+
node,
|
|
172191
|
+
messageId: "missingLegend"
|
|
172192
|
+
});
|
|
172193
|
+
} else if (violation.id === "fieldset-legend-empty") {
|
|
172194
|
+
context.report({
|
|
172195
|
+
node,
|
|
172196
|
+
messageId: "emptyLegend"
|
|
172197
|
+
});
|
|
172198
|
+
}
|
|
172199
|
+
}
|
|
172200
|
+
}
|
|
172201
|
+
}
|
|
172202
|
+
},
|
|
172203
|
+
// Check Vue template fieldset elements
|
|
172204
|
+
VElement(node) {
|
|
172205
|
+
const vueNode = node;
|
|
172206
|
+
if (vueNode.name === "fieldset") {
|
|
172207
|
+
try {
|
|
172208
|
+
const element = vueElementToDOM(node, context);
|
|
172209
|
+
if (element) {
|
|
172210
|
+
const violations = A11yChecker.checkFieldsetLegend(element);
|
|
172211
|
+
for (const violation of violations) {
|
|
172212
|
+
if (violation.id === "fieldset-legend") {
|
|
172213
|
+
context.report({
|
|
172214
|
+
node,
|
|
172215
|
+
messageId: "missingLegend"
|
|
172216
|
+
});
|
|
172217
|
+
} else if (violation.id === "fieldset-legend-empty") {
|
|
172218
|
+
context.report({
|
|
172219
|
+
node,
|
|
172220
|
+
messageId: "emptyLegend"
|
|
172221
|
+
});
|
|
172222
|
+
}
|
|
172223
|
+
}
|
|
172224
|
+
}
|
|
172225
|
+
} catch (error2) {
|
|
172226
|
+
}
|
|
172227
|
+
}
|
|
172228
|
+
}
|
|
172229
|
+
};
|
|
172230
|
+
}
|
|
172231
|
+
};
|
|
172232
|
+
var fieldset_legend_default = rule7;
|
|
172233
|
+
|
|
172234
|
+
// src/linter/eslint-plugin/rules/table-structure.ts
|
|
172235
|
+
var rule8 = {
|
|
172236
|
+
meta: {
|
|
172237
|
+
type: "problem",
|
|
172238
|
+
docs: {
|
|
172239
|
+
description: "Enforce table elements have proper accessibility structure (caption, headers, scope)",
|
|
172240
|
+
category: "Accessibility",
|
|
172241
|
+
recommended: true,
|
|
172242
|
+
url: "https://github.com/nolrm/test-a11y-js"
|
|
172243
|
+
},
|
|
172244
|
+
messages: {
|
|
172245
|
+
missingCaption: "Table must have a caption or aria-label/aria-labelledby",
|
|
172246
|
+
missingHeaders: "Table must have header cells (th elements) when it has data cells",
|
|
172247
|
+
missingScope: "Table header cells (th) should have a scope attribute"
|
|
172248
|
+
},
|
|
172249
|
+
fixable: void 0,
|
|
172250
|
+
schema: []
|
|
172251
|
+
},
|
|
172252
|
+
create(context) {
|
|
172253
|
+
return {
|
|
172254
|
+
// Check JSX table elements
|
|
172255
|
+
JSXOpeningElement(node) {
|
|
172256
|
+
const jsxNode = node;
|
|
172257
|
+
if (jsxNode.name?.name === "table") {
|
|
172258
|
+
try {
|
|
172259
|
+
const element = jsxToElement(node, context);
|
|
172260
|
+
const violations = A11yChecker.checkTableStructure(element);
|
|
172261
|
+
for (const violation of violations) {
|
|
172262
|
+
if (violation.id === "table-caption") {
|
|
172263
|
+
context.report({
|
|
172264
|
+
node,
|
|
172265
|
+
messageId: "missingCaption"
|
|
172266
|
+
});
|
|
172267
|
+
} else if (violation.id === "table-headers") {
|
|
172268
|
+
context.report({
|
|
172269
|
+
node,
|
|
172270
|
+
messageId: "missingHeaders"
|
|
172271
|
+
});
|
|
172272
|
+
} else if (violation.id === "table-header-scope") {
|
|
172273
|
+
context.report({
|
|
172274
|
+
node: violation.element,
|
|
172275
|
+
messageId: "missingScope"
|
|
172276
|
+
});
|
|
172277
|
+
}
|
|
172278
|
+
}
|
|
172279
|
+
} catch (error2) {
|
|
172280
|
+
}
|
|
172281
|
+
}
|
|
172282
|
+
},
|
|
172283
|
+
// Check HTML strings
|
|
172284
|
+
Literal(node) {
|
|
172285
|
+
if (isHTMLLiteral(node)) {
|
|
172286
|
+
const element = htmlNodeToElement(node, context);
|
|
172287
|
+
if (element) {
|
|
172288
|
+
const violations = A11yChecker.checkTableStructure(element);
|
|
172289
|
+
for (const violation of violations) {
|
|
172290
|
+
if (violation.id === "table-caption") {
|
|
172291
|
+
context.report({
|
|
172292
|
+
node,
|
|
172293
|
+
messageId: "missingCaption"
|
|
172294
|
+
});
|
|
172295
|
+
} else if (violation.id === "table-headers") {
|
|
172296
|
+
context.report({
|
|
172297
|
+
node,
|
|
172298
|
+
messageId: "missingHeaders"
|
|
172299
|
+
});
|
|
172300
|
+
}
|
|
172301
|
+
}
|
|
172302
|
+
}
|
|
172303
|
+
}
|
|
172304
|
+
},
|
|
172305
|
+
TemplateLiteral(node) {
|
|
172306
|
+
if (isHTMLLiteral(node)) {
|
|
172307
|
+
const element = htmlNodeToElement(node, context);
|
|
172308
|
+
if (element) {
|
|
172309
|
+
const violations = A11yChecker.checkTableStructure(element);
|
|
172310
|
+
for (const violation of violations) {
|
|
172311
|
+
if (violation.id === "table-caption") {
|
|
172312
|
+
context.report({
|
|
172313
|
+
node,
|
|
172314
|
+
messageId: "missingCaption"
|
|
172315
|
+
});
|
|
172316
|
+
} else if (violation.id === "table-headers") {
|
|
172317
|
+
context.report({
|
|
172318
|
+
node,
|
|
172319
|
+
messageId: "missingHeaders"
|
|
172320
|
+
});
|
|
172321
|
+
}
|
|
172322
|
+
}
|
|
172323
|
+
}
|
|
172324
|
+
}
|
|
172325
|
+
},
|
|
172326
|
+
// Check Vue template table elements
|
|
172327
|
+
VElement(node) {
|
|
172328
|
+
const vueNode = node;
|
|
172329
|
+
if (vueNode.name === "table") {
|
|
172330
|
+
try {
|
|
172331
|
+
const element = vueElementToDOM(node, context);
|
|
172332
|
+
if (element) {
|
|
172333
|
+
const violations = A11yChecker.checkTableStructure(element);
|
|
172334
|
+
for (const violation of violations) {
|
|
172335
|
+
if (violation.id === "table-caption") {
|
|
172336
|
+
context.report({
|
|
172337
|
+
node,
|
|
172338
|
+
messageId: "missingCaption"
|
|
172339
|
+
});
|
|
172340
|
+
} else if (violation.id === "table-headers") {
|
|
172341
|
+
context.report({
|
|
172342
|
+
node,
|
|
172343
|
+
messageId: "missingHeaders"
|
|
172344
|
+
});
|
|
172345
|
+
} else if (violation.id === "table-header-scope") {
|
|
172346
|
+
context.report({
|
|
172347
|
+
node: violation.element,
|
|
172348
|
+
messageId: "missingScope"
|
|
172349
|
+
});
|
|
172350
|
+
}
|
|
172351
|
+
}
|
|
172352
|
+
}
|
|
172353
|
+
} catch (error2) {
|
|
172354
|
+
}
|
|
172355
|
+
}
|
|
172356
|
+
}
|
|
172357
|
+
};
|
|
172358
|
+
}
|
|
172359
|
+
};
|
|
172360
|
+
var table_structure_default = rule8;
|
|
172361
|
+
|
|
172362
|
+
// src/linter/eslint-plugin/rules/details-summary.ts
|
|
172363
|
+
var rule9 = {
|
|
172364
|
+
meta: {
|
|
172365
|
+
type: "problem",
|
|
172366
|
+
docs: {
|
|
172367
|
+
description: "Enforce details elements have a summary element as first child",
|
|
172368
|
+
category: "Accessibility",
|
|
172369
|
+
recommended: true,
|
|
172370
|
+
url: "https://github.com/nolrm/test-a11y-js"
|
|
172371
|
+
},
|
|
172372
|
+
messages: {
|
|
172373
|
+
missingSummary: "details element must have a summary element as its first child",
|
|
172374
|
+
emptySummary: "details summary element must have non-empty text content"
|
|
172375
|
+
},
|
|
172376
|
+
fixable: void 0,
|
|
172377
|
+
schema: []
|
|
172378
|
+
},
|
|
172379
|
+
create(context) {
|
|
172380
|
+
return {
|
|
172381
|
+
// Check JSX details elements
|
|
172382
|
+
JSXOpeningElement(node) {
|
|
172383
|
+
const jsxNode = node;
|
|
172384
|
+
if (jsxNode.name?.name === "details") {
|
|
172385
|
+
try {
|
|
172386
|
+
const element = jsxToElement(node, context);
|
|
172387
|
+
const violations = A11yChecker.checkDetailsSummary(element);
|
|
172388
|
+
for (const violation of violations) {
|
|
172389
|
+
if (violation.id === "details-summary") {
|
|
172390
|
+
context.report({
|
|
172391
|
+
node,
|
|
172392
|
+
messageId: "missingSummary"
|
|
172393
|
+
});
|
|
172394
|
+
} else if (violation.id === "details-summary-empty") {
|
|
172395
|
+
context.report({
|
|
172396
|
+
node,
|
|
172397
|
+
messageId: "emptySummary"
|
|
172398
|
+
});
|
|
172399
|
+
}
|
|
172400
|
+
}
|
|
172401
|
+
} catch (error2) {
|
|
172402
|
+
}
|
|
172403
|
+
}
|
|
172404
|
+
},
|
|
172405
|
+
// Check HTML strings
|
|
172406
|
+
Literal(node) {
|
|
172407
|
+
if (isHTMLLiteral(node)) {
|
|
172408
|
+
const element = htmlNodeToElement(node, context);
|
|
172409
|
+
if (element) {
|
|
172410
|
+
const violations = A11yChecker.checkDetailsSummary(element);
|
|
172411
|
+
for (const violation of violations) {
|
|
172412
|
+
if (violation.id === "details-summary") {
|
|
172413
|
+
context.report({
|
|
172414
|
+
node,
|
|
172415
|
+
messageId: "missingSummary"
|
|
172416
|
+
});
|
|
172417
|
+
} else if (violation.id === "details-summary-empty") {
|
|
172418
|
+
context.report({
|
|
172419
|
+
node,
|
|
172420
|
+
messageId: "emptySummary"
|
|
172421
|
+
});
|
|
172422
|
+
}
|
|
172423
|
+
}
|
|
172424
|
+
}
|
|
172425
|
+
}
|
|
172426
|
+
},
|
|
172427
|
+
TemplateLiteral(node) {
|
|
172428
|
+
if (isHTMLLiteral(node)) {
|
|
172429
|
+
const element = htmlNodeToElement(node, context);
|
|
172430
|
+
if (element) {
|
|
172431
|
+
const violations = A11yChecker.checkDetailsSummary(element);
|
|
172432
|
+
for (const violation of violations) {
|
|
172433
|
+
if (violation.id === "details-summary") {
|
|
172434
|
+
context.report({
|
|
172435
|
+
node,
|
|
172436
|
+
messageId: "missingSummary"
|
|
172437
|
+
});
|
|
172438
|
+
} else if (violation.id === "details-summary-empty") {
|
|
172439
|
+
context.report({
|
|
172440
|
+
node,
|
|
172441
|
+
messageId: "emptySummary"
|
|
172442
|
+
});
|
|
172443
|
+
}
|
|
172444
|
+
}
|
|
172445
|
+
}
|
|
172446
|
+
}
|
|
172447
|
+
},
|
|
172448
|
+
// Check Vue template details elements
|
|
172449
|
+
VElement(node) {
|
|
172450
|
+
const vueNode = node;
|
|
172451
|
+
if (vueNode.name === "details") {
|
|
172452
|
+
try {
|
|
172453
|
+
const element = vueElementToDOM(node, context);
|
|
172454
|
+
if (element) {
|
|
172455
|
+
const violations = A11yChecker.checkDetailsSummary(element);
|
|
172456
|
+
for (const violation of violations) {
|
|
172457
|
+
if (violation.id === "details-summary") {
|
|
172458
|
+
context.report({
|
|
172459
|
+
node,
|
|
172460
|
+
messageId: "missingSummary"
|
|
172461
|
+
});
|
|
172462
|
+
} else if (violation.id === "details-summary-empty") {
|
|
172463
|
+
context.report({
|
|
172464
|
+
node,
|
|
172465
|
+
messageId: "emptySummary"
|
|
172466
|
+
});
|
|
172467
|
+
}
|
|
172468
|
+
}
|
|
172469
|
+
}
|
|
172470
|
+
} catch (error2) {
|
|
172471
|
+
}
|
|
172472
|
+
}
|
|
172473
|
+
}
|
|
172474
|
+
};
|
|
172475
|
+
}
|
|
172476
|
+
};
|
|
172477
|
+
var details_summary_default = rule9;
|
|
172478
|
+
|
|
172479
|
+
// src/linter/eslint-plugin/rules/video-captions.ts
|
|
172480
|
+
var rule10 = {
|
|
172481
|
+
meta: {
|
|
172482
|
+
type: "problem",
|
|
172483
|
+
docs: {
|
|
172484
|
+
description: "Enforce video elements have caption tracks",
|
|
172485
|
+
category: "Accessibility",
|
|
172486
|
+
recommended: true,
|
|
172487
|
+
url: "https://github.com/nolrm/test-a11y-js"
|
|
172488
|
+
},
|
|
172489
|
+
messages: {
|
|
172490
|
+
missingCaptions: 'Video element must have at least one track element with kind="captions"',
|
|
172491
|
+
missingSrclang: "Video caption track must have a srclang attribute",
|
|
172492
|
+
missingLabel: "Video caption track should have a label attribute"
|
|
172493
|
+
},
|
|
172494
|
+
fixable: void 0,
|
|
172495
|
+
schema: []
|
|
172496
|
+
},
|
|
172497
|
+
create(context) {
|
|
172498
|
+
return {
|
|
172499
|
+
// Check JSX video elements
|
|
172500
|
+
JSXOpeningElement(node) {
|
|
172501
|
+
const jsxNode = node;
|
|
172502
|
+
if (jsxNode.name?.name === "video") {
|
|
172503
|
+
try {
|
|
172504
|
+
const element = jsxToElement(node, context);
|
|
172505
|
+
const violations = A11yChecker.checkVideoCaptions(element);
|
|
172506
|
+
for (const violation of violations) {
|
|
172507
|
+
if (violation.id === "video-captions") {
|
|
172508
|
+
context.report({
|
|
172509
|
+
node,
|
|
172510
|
+
messageId: "missingCaptions"
|
|
172511
|
+
});
|
|
172512
|
+
} else if (violation.id === "video-track-srclang") {
|
|
172513
|
+
context.report({
|
|
172514
|
+
node: violation.element,
|
|
172515
|
+
messageId: "missingSrclang"
|
|
172516
|
+
});
|
|
172517
|
+
} else if (violation.id === "video-track-label") {
|
|
172518
|
+
context.report({
|
|
172519
|
+
node: violation.element,
|
|
172520
|
+
messageId: "missingLabel"
|
|
172521
|
+
});
|
|
172522
|
+
}
|
|
172523
|
+
}
|
|
172524
|
+
} catch (error2) {
|
|
172525
|
+
}
|
|
172526
|
+
}
|
|
172527
|
+
},
|
|
172528
|
+
// Check HTML strings
|
|
172529
|
+
Literal(node) {
|
|
172530
|
+
if (isHTMLLiteral(node)) {
|
|
172531
|
+
const element = htmlNodeToElement(node, context);
|
|
172532
|
+
if (element) {
|
|
172533
|
+
const violations = A11yChecker.checkVideoCaptions(element);
|
|
172534
|
+
for (const violation of violations) {
|
|
172535
|
+
if (violation.id === "video-captions") {
|
|
172536
|
+
context.report({
|
|
172537
|
+
node,
|
|
172538
|
+
messageId: "missingCaptions"
|
|
172539
|
+
});
|
|
172540
|
+
}
|
|
172541
|
+
}
|
|
172542
|
+
}
|
|
172543
|
+
}
|
|
172544
|
+
},
|
|
172545
|
+
TemplateLiteral(node) {
|
|
172546
|
+
if (isHTMLLiteral(node)) {
|
|
172547
|
+
const element = htmlNodeToElement(node, context);
|
|
172548
|
+
if (element) {
|
|
172549
|
+
const violations = A11yChecker.checkVideoCaptions(element);
|
|
172550
|
+
for (const violation of violations) {
|
|
172551
|
+
if (violation.id === "video-captions") {
|
|
172552
|
+
context.report({
|
|
172553
|
+
node,
|
|
172554
|
+
messageId: "missingCaptions"
|
|
172555
|
+
});
|
|
172556
|
+
}
|
|
172557
|
+
}
|
|
172558
|
+
}
|
|
172559
|
+
}
|
|
172560
|
+
},
|
|
172561
|
+
// Check Vue template video elements
|
|
172562
|
+
VElement(node) {
|
|
172563
|
+
const vueNode = node;
|
|
172564
|
+
if (vueNode.name === "video") {
|
|
172565
|
+
try {
|
|
172566
|
+
const element = vueElementToDOM(node, context);
|
|
172567
|
+
if (element) {
|
|
172568
|
+
const violations = A11yChecker.checkVideoCaptions(element);
|
|
172569
|
+
for (const violation of violations) {
|
|
172570
|
+
if (violation.id === "video-captions") {
|
|
172571
|
+
context.report({
|
|
172572
|
+
node,
|
|
172573
|
+
messageId: "missingCaptions"
|
|
172574
|
+
});
|
|
172575
|
+
} else if (violation.id === "video-track-srclang") {
|
|
172576
|
+
context.report({
|
|
172577
|
+
node: violation.element,
|
|
172578
|
+
messageId: "missingSrclang"
|
|
172579
|
+
});
|
|
172580
|
+
} else if (violation.id === "video-track-label") {
|
|
172581
|
+
context.report({
|
|
172582
|
+
node: violation.element,
|
|
172583
|
+
messageId: "missingLabel"
|
|
172584
|
+
});
|
|
172585
|
+
}
|
|
172586
|
+
}
|
|
172587
|
+
}
|
|
172588
|
+
} catch (error2) {
|
|
172589
|
+
}
|
|
172590
|
+
}
|
|
172591
|
+
}
|
|
172592
|
+
};
|
|
172593
|
+
}
|
|
172594
|
+
};
|
|
172595
|
+
var video_captions_default = rule10;
|
|
172596
|
+
|
|
172597
|
+
// src/linter/eslint-plugin/rules/audio-captions.ts
|
|
172598
|
+
var rule11 = {
|
|
172599
|
+
meta: {
|
|
172600
|
+
type: "problem",
|
|
172601
|
+
docs: {
|
|
172602
|
+
description: "Enforce audio elements have caption tracks or transcripts",
|
|
172603
|
+
category: "Accessibility",
|
|
172604
|
+
recommended: true,
|
|
172605
|
+
url: "https://github.com/nolrm/test-a11y-js"
|
|
172606
|
+
},
|
|
172607
|
+
messages: {
|
|
172608
|
+
missingCaptions: "Audio element must have track elements or a transcript link",
|
|
172609
|
+
missingSrclang: "Audio track must have a srclang attribute",
|
|
172610
|
+
missingLabel: "Audio track should have a label attribute"
|
|
172611
|
+
},
|
|
172612
|
+
fixable: void 0,
|
|
172613
|
+
schema: []
|
|
172614
|
+
},
|
|
172615
|
+
create(context) {
|
|
172616
|
+
return {
|
|
172617
|
+
// Check JSX audio elements
|
|
172618
|
+
JSXOpeningElement(node) {
|
|
172619
|
+
const jsxNode = node;
|
|
172620
|
+
if (jsxNode.name?.name === "audio") {
|
|
172621
|
+
try {
|
|
172622
|
+
const element = jsxToElement(node, context);
|
|
172623
|
+
const violations = A11yChecker.checkAudioCaptions(element);
|
|
172624
|
+
for (const violation of violations) {
|
|
172625
|
+
if (violation.id === "audio-captions") {
|
|
172626
|
+
context.report({
|
|
172627
|
+
node,
|
|
172628
|
+
messageId: "missingCaptions"
|
|
172629
|
+
});
|
|
172630
|
+
} else if (violation.id === "audio-track-srclang") {
|
|
172631
|
+
context.report({
|
|
172632
|
+
node: violation.element,
|
|
172633
|
+
messageId: "missingSrclang"
|
|
172634
|
+
});
|
|
172635
|
+
} else if (violation.id === "audio-track-label") {
|
|
172636
|
+
context.report({
|
|
172637
|
+
node: violation.element,
|
|
172638
|
+
messageId: "missingLabel"
|
|
172639
|
+
});
|
|
172640
|
+
}
|
|
172641
|
+
}
|
|
172642
|
+
} catch (error2) {
|
|
172643
|
+
}
|
|
172644
|
+
}
|
|
172645
|
+
},
|
|
172646
|
+
// Check HTML strings
|
|
172647
|
+
Literal(node) {
|
|
172648
|
+
if (isHTMLLiteral(node)) {
|
|
172649
|
+
const element = htmlNodeToElement(node, context);
|
|
172650
|
+
if (element) {
|
|
172651
|
+
const violations = A11yChecker.checkAudioCaptions(element);
|
|
172652
|
+
for (const violation of violations) {
|
|
172653
|
+
if (violation.id === "audio-captions") {
|
|
172654
|
+
context.report({
|
|
172655
|
+
node,
|
|
172656
|
+
messageId: "missingCaptions"
|
|
172657
|
+
});
|
|
172658
|
+
}
|
|
172659
|
+
}
|
|
172660
|
+
}
|
|
172661
|
+
}
|
|
172662
|
+
},
|
|
172663
|
+
TemplateLiteral(node) {
|
|
172664
|
+
if (isHTMLLiteral(node)) {
|
|
172665
|
+
const element = htmlNodeToElement(node, context);
|
|
172666
|
+
if (element) {
|
|
172667
|
+
const violations = A11yChecker.checkAudioCaptions(element);
|
|
172668
|
+
for (const violation of violations) {
|
|
172669
|
+
if (violation.id === "audio-captions") {
|
|
172670
|
+
context.report({
|
|
172671
|
+
node,
|
|
172672
|
+
messageId: "missingCaptions"
|
|
172673
|
+
});
|
|
172674
|
+
}
|
|
172675
|
+
}
|
|
172676
|
+
}
|
|
172677
|
+
}
|
|
172678
|
+
},
|
|
172679
|
+
// Check Vue template audio elements
|
|
172680
|
+
VElement(node) {
|
|
172681
|
+
const vueNode = node;
|
|
172682
|
+
if (vueNode.name === "audio") {
|
|
172683
|
+
try {
|
|
172684
|
+
const element = vueElementToDOM(node, context);
|
|
172685
|
+
if (element) {
|
|
172686
|
+
const violations = A11yChecker.checkAudioCaptions(element);
|
|
172687
|
+
for (const violation of violations) {
|
|
172688
|
+
if (violation.id === "audio-captions") {
|
|
172689
|
+
context.report({
|
|
172690
|
+
node,
|
|
172691
|
+
messageId: "missingCaptions"
|
|
172692
|
+
});
|
|
172693
|
+
} else if (violation.id === "audio-track-srclang") {
|
|
172694
|
+
context.report({
|
|
172695
|
+
node: violation.element,
|
|
172696
|
+
messageId: "missingSrclang"
|
|
172697
|
+
});
|
|
172698
|
+
} else if (violation.id === "audio-track-label") {
|
|
172699
|
+
context.report({
|
|
172700
|
+
node: violation.element,
|
|
172701
|
+
messageId: "missingLabel"
|
|
172702
|
+
});
|
|
172703
|
+
}
|
|
172704
|
+
}
|
|
172705
|
+
}
|
|
172706
|
+
} catch (error2) {
|
|
172707
|
+
}
|
|
172708
|
+
}
|
|
172709
|
+
}
|
|
172710
|
+
};
|
|
172711
|
+
}
|
|
172712
|
+
};
|
|
172713
|
+
var audio_captions_default = rule11;
|
|
172714
|
+
|
|
172715
|
+
// src/linter/eslint-plugin/rules/landmark-roles.ts
|
|
172716
|
+
var rule12 = {
|
|
172717
|
+
meta: {
|
|
172718
|
+
type: "problem",
|
|
172719
|
+
docs: {
|
|
172720
|
+
description: "Enforce proper use of landmark elements (nav, main, header, footer, aside, section, article)",
|
|
172721
|
+
category: "Accessibility",
|
|
172722
|
+
recommended: true,
|
|
172723
|
+
url: "https://github.com/nolrm/test-a11y-js"
|
|
172724
|
+
},
|
|
172725
|
+
messages: {
|
|
172726
|
+
multipleMain: "Page should have only one main element",
|
|
172727
|
+
missingName: "Landmark element should have an accessible name (heading, aria-label, or aria-labelledby)",
|
|
172728
|
+
duplicateUnnamed: "Multiple landmark elements found. Each should have an accessible name (aria-label or aria-labelledby)"
|
|
172729
|
+
},
|
|
172730
|
+
fixable: void 0,
|
|
172731
|
+
schema: []
|
|
172732
|
+
},
|
|
172733
|
+
create(context) {
|
|
172734
|
+
return {
|
|
172735
|
+
// Check JSX landmark elements
|
|
172736
|
+
JSXOpeningElement(node) {
|
|
172737
|
+
const jsxNode = node;
|
|
172738
|
+
const tagName = jsxNode.name?.name?.toLowerCase();
|
|
172739
|
+
const landmarkTags = ["nav", "main", "header", "footer", "aside", "section", "article"];
|
|
172740
|
+
if (landmarkTags.includes(tagName)) {
|
|
172741
|
+
try {
|
|
172742
|
+
const element = jsxToElement(node, context);
|
|
172743
|
+
const violations = A11yChecker.checkLandmarks(element);
|
|
172744
|
+
for (const violation of violations) {
|
|
172745
|
+
if (violation.id === "landmark-multiple-main") {
|
|
172746
|
+
context.report({
|
|
172747
|
+
node,
|
|
172748
|
+
messageId: "multipleMain"
|
|
172749
|
+
});
|
|
172750
|
+
} else if (violation.id === "landmark-missing-name") {
|
|
172751
|
+
context.report({
|
|
172752
|
+
node,
|
|
172753
|
+
messageId: "missingName"
|
|
172754
|
+
});
|
|
172755
|
+
} else if (violation.id === "landmark-duplicate-unnamed") {
|
|
172756
|
+
context.report({
|
|
172757
|
+
node,
|
|
172758
|
+
messageId: "duplicateUnnamed"
|
|
172759
|
+
});
|
|
172760
|
+
}
|
|
172761
|
+
}
|
|
172762
|
+
} catch (error2) {
|
|
172763
|
+
}
|
|
172764
|
+
}
|
|
172765
|
+
},
|
|
172766
|
+
// Check HTML strings
|
|
172767
|
+
Literal(node) {
|
|
172768
|
+
if (isHTMLLiteral(node)) {
|
|
172769
|
+
const element = htmlNodeToElement(node, context);
|
|
172770
|
+
if (element) {
|
|
172771
|
+
const violations = A11yChecker.checkLandmarks(element);
|
|
172772
|
+
for (const violation of violations) {
|
|
172773
|
+
if (violation.id === "landmark-multiple-main") {
|
|
172774
|
+
context.report({
|
|
172775
|
+
node,
|
|
172776
|
+
messageId: "multipleMain"
|
|
172777
|
+
});
|
|
172778
|
+
} else if (violation.id === "landmark-missing-name") {
|
|
172779
|
+
context.report({
|
|
172780
|
+
node,
|
|
172781
|
+
messageId: "missingName"
|
|
172782
|
+
});
|
|
172783
|
+
}
|
|
172784
|
+
}
|
|
172785
|
+
}
|
|
172786
|
+
}
|
|
172787
|
+
},
|
|
172788
|
+
TemplateLiteral(node) {
|
|
172789
|
+
if (isHTMLLiteral(node)) {
|
|
172790
|
+
const element = htmlNodeToElement(node, context);
|
|
172791
|
+
if (element) {
|
|
172792
|
+
const violations = A11yChecker.checkLandmarks(element);
|
|
172793
|
+
for (const violation of violations) {
|
|
172794
|
+
if (violation.id === "landmark-multiple-main") {
|
|
172795
|
+
context.report({
|
|
172796
|
+
node,
|
|
172797
|
+
messageId: "multipleMain"
|
|
172798
|
+
});
|
|
172799
|
+
} else if (violation.id === "landmark-missing-name") {
|
|
172800
|
+
context.report({
|
|
172801
|
+
node,
|
|
172802
|
+
messageId: "missingName"
|
|
172803
|
+
});
|
|
172804
|
+
}
|
|
172805
|
+
}
|
|
172806
|
+
}
|
|
172807
|
+
}
|
|
172808
|
+
},
|
|
172809
|
+
// Check Vue template landmark elements
|
|
172810
|
+
VElement(node) {
|
|
172811
|
+
const vueNode = node;
|
|
172812
|
+
const tagName = vueNode.name?.toLowerCase();
|
|
172813
|
+
const landmarkTags = ["nav", "main", "header", "footer", "aside", "section", "article"];
|
|
172814
|
+
if (landmarkTags.includes(tagName)) {
|
|
172815
|
+
try {
|
|
172816
|
+
const element = vueElementToDOM(node, context);
|
|
172817
|
+
if (element) {
|
|
172818
|
+
const violations = A11yChecker.checkLandmarks(element);
|
|
172819
|
+
for (const violation of violations) {
|
|
172820
|
+
if (violation.id === "landmark-multiple-main") {
|
|
172821
|
+
context.report({
|
|
172822
|
+
node,
|
|
172823
|
+
messageId: "multipleMain"
|
|
172824
|
+
});
|
|
172825
|
+
} else if (violation.id === "landmark-missing-name") {
|
|
172826
|
+
context.report({
|
|
172827
|
+
node,
|
|
172828
|
+
messageId: "missingName"
|
|
172829
|
+
});
|
|
172830
|
+
} else if (violation.id === "landmark-duplicate-unnamed") {
|
|
172831
|
+
context.report({
|
|
172832
|
+
node,
|
|
172833
|
+
messageId: "duplicateUnnamed"
|
|
172834
|
+
});
|
|
172835
|
+
}
|
|
172836
|
+
}
|
|
172837
|
+
}
|
|
172838
|
+
} catch (error2) {
|
|
172839
|
+
}
|
|
172840
|
+
}
|
|
172841
|
+
}
|
|
172842
|
+
};
|
|
172843
|
+
}
|
|
172844
|
+
};
|
|
172845
|
+
var landmark_roles_default = rule12;
|
|
172846
|
+
|
|
172847
|
+
// src/linter/eslint-plugin/rules/dialog-modal.ts
|
|
172848
|
+
var rule13 = {
|
|
172849
|
+
meta: {
|
|
172850
|
+
type: "problem",
|
|
172851
|
+
docs: {
|
|
172852
|
+
description: "Enforce dialog elements have proper accessibility attributes",
|
|
172853
|
+
category: "Accessibility",
|
|
172854
|
+
recommended: true,
|
|
172855
|
+
url: "https://github.com/nolrm/test-a11y-js"
|
|
172856
|
+
},
|
|
172857
|
+
messages: {
|
|
172858
|
+
missingName: "Dialog element must have an accessible name (aria-label, aria-labelledby, or heading)",
|
|
172859
|
+
missingModal: 'Modal dialog should have aria-modal="true" attribute',
|
|
172860
|
+
invalidRole: 'Dialog element should have role="dialog" or role="alertdialog"'
|
|
172861
|
+
},
|
|
172862
|
+
fixable: void 0,
|
|
172863
|
+
schema: []
|
|
172864
|
+
},
|
|
172865
|
+
create(context) {
|
|
172866
|
+
return {
|
|
172867
|
+
// Check JSX dialog elements
|
|
172868
|
+
JSXOpeningElement(node) {
|
|
172869
|
+
const jsxNode = node;
|
|
172870
|
+
if (jsxNode.name?.name === "dialog" || jsxNode.name?.name && jsxNode.attributes?.some(
|
|
172871
|
+
(attr) => attr.name?.name === "role" && (attr.value?.value === "dialog" || attr.value?.value === "alertdialog")
|
|
172872
|
+
)) {
|
|
172873
|
+
try {
|
|
172874
|
+
const element = jsxToElement(node, context);
|
|
172875
|
+
const violations = A11yChecker.checkDialogModal(element);
|
|
172876
|
+
for (const violation of violations) {
|
|
172877
|
+
if (violation.id === "dialog-missing-name") {
|
|
172878
|
+
context.report({
|
|
172879
|
+
node,
|
|
172880
|
+
messageId: "missingName"
|
|
172881
|
+
});
|
|
172882
|
+
} else if (violation.id === "dialog-missing-modal") {
|
|
172883
|
+
context.report({
|
|
172884
|
+
node,
|
|
172885
|
+
messageId: "missingModal"
|
|
172886
|
+
});
|
|
172887
|
+
} else if (violation.id === "dialog-invalid-role") {
|
|
172888
|
+
context.report({
|
|
172889
|
+
node,
|
|
172890
|
+
messageId: "invalidRole"
|
|
172891
|
+
});
|
|
172892
|
+
}
|
|
172893
|
+
}
|
|
172894
|
+
} catch (error2) {
|
|
172895
|
+
}
|
|
172896
|
+
}
|
|
172897
|
+
},
|
|
172898
|
+
// Check HTML strings
|
|
172899
|
+
Literal(node) {
|
|
172900
|
+
if (isHTMLLiteral(node)) {
|
|
172901
|
+
const element = htmlNodeToElement(node, context);
|
|
172902
|
+
if (element) {
|
|
172903
|
+
const violations = A11yChecker.checkDialogModal(element);
|
|
172904
|
+
for (const violation of violations) {
|
|
172905
|
+
if (violation.id === "dialog-missing-name") {
|
|
172906
|
+
context.report({
|
|
172907
|
+
node,
|
|
172908
|
+
messageId: "missingName"
|
|
172909
|
+
});
|
|
172910
|
+
}
|
|
172911
|
+
}
|
|
172912
|
+
}
|
|
172913
|
+
}
|
|
172914
|
+
},
|
|
172915
|
+
TemplateLiteral(node) {
|
|
172916
|
+
if (isHTMLLiteral(node)) {
|
|
172917
|
+
const element = htmlNodeToElement(node, context);
|
|
172918
|
+
if (element) {
|
|
172919
|
+
const violations = A11yChecker.checkDialogModal(element);
|
|
172920
|
+
for (const violation of violations) {
|
|
172921
|
+
if (violation.id === "dialog-missing-name") {
|
|
172922
|
+
context.report({
|
|
172923
|
+
node,
|
|
172924
|
+
messageId: "missingName"
|
|
172925
|
+
});
|
|
172926
|
+
}
|
|
172927
|
+
}
|
|
172928
|
+
}
|
|
172929
|
+
}
|
|
172930
|
+
},
|
|
172931
|
+
// Check Vue template dialog elements
|
|
172932
|
+
VElement(node) {
|
|
172933
|
+
const vueNode = node;
|
|
172934
|
+
if (vueNode.name === "dialog" || vueNode.startTag?.attributes?.some(
|
|
172935
|
+
(attr) => attr.key?.name === "role" && (attr.value?.value === "dialog" || attr.value?.value === "alertdialog")
|
|
172936
|
+
)) {
|
|
172937
|
+
try {
|
|
172938
|
+
const element = vueElementToDOM(node, context);
|
|
172939
|
+
if (element) {
|
|
172940
|
+
const violations = A11yChecker.checkDialogModal(element);
|
|
172941
|
+
for (const violation of violations) {
|
|
172942
|
+
if (violation.id === "dialog-missing-name") {
|
|
172943
|
+
context.report({
|
|
172944
|
+
node,
|
|
172945
|
+
messageId: "missingName"
|
|
172946
|
+
});
|
|
172947
|
+
} else if (violation.id === "dialog-missing-modal") {
|
|
172948
|
+
context.report({
|
|
172949
|
+
node,
|
|
172950
|
+
messageId: "missingModal"
|
|
172951
|
+
});
|
|
172952
|
+
} else if (violation.id === "dialog-invalid-role") {
|
|
172953
|
+
context.report({
|
|
172954
|
+
node,
|
|
172955
|
+
messageId: "invalidRole"
|
|
172956
|
+
});
|
|
172957
|
+
}
|
|
172958
|
+
}
|
|
172959
|
+
}
|
|
172960
|
+
} catch (error2) {
|
|
172961
|
+
}
|
|
172962
|
+
}
|
|
172963
|
+
}
|
|
172964
|
+
};
|
|
172965
|
+
}
|
|
172966
|
+
};
|
|
172967
|
+
var dialog_modal_default = rule13;
|
|
172968
|
+
|
|
171848
172969
|
// src/linter/eslint-plugin/index.ts
|
|
171849
172970
|
var plugin = {
|
|
171850
172971
|
meta: {
|
|
171851
172972
|
name: "test-a11y-js",
|
|
171852
|
-
version: "0.2
|
|
172973
|
+
version: "0.6.2"
|
|
171853
172974
|
},
|
|
171854
172975
|
rules: {
|
|
171855
172976
|
"image-alt": image_alt_default,
|
|
@@ -171857,7 +172978,14 @@ var plugin = {
|
|
|
171857
172978
|
"link-text": link_text_default,
|
|
171858
172979
|
"form-label": form_label_default,
|
|
171859
172980
|
"heading-order": heading_order_default,
|
|
171860
|
-
"iframe-title": iframe_title_default
|
|
172981
|
+
"iframe-title": iframe_title_default,
|
|
172982
|
+
"fieldset-legend": fieldset_legend_default,
|
|
172983
|
+
"table-structure": table_structure_default,
|
|
172984
|
+
"details-summary": details_summary_default,
|
|
172985
|
+
"video-captions": video_captions_default,
|
|
172986
|
+
"audio-captions": audio_captions_default,
|
|
172987
|
+
"landmark-roles": landmark_roles_default,
|
|
172988
|
+
"dialog-modal": dialog_modal_default
|
|
171861
172989
|
},
|
|
171862
172990
|
configs: {
|
|
171863
172991
|
recommended: {
|