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