diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5edd9befb..43d08288f 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -46,6 +46,11 @@ jobs:
with:
name: Rule listing
path: accessibility-checker-engine/dist/help/rules.html
+ - name: Upload rule mapping spreadsheet
+ uses: actions/upload-artifact@v4
+ with:
+ name: Rule mapping spreadsheet
+ path: accessibility-checker-engine/dist/help/rules.csv
act-results:
diff --git a/accessibility-checker-engine/src/genHelp.ts b/accessibility-checker-engine/src/genHelp.ts
index cbe00433a..84c58b859 100644
--- a/accessibility-checker-engine/src/genHelp.ts
+++ b/accessibility-checker-engine/src/genHelp.ts
@@ -135,7 +135,7 @@ width="16px" height="16px" viewBox="0 0 16 16" style="enable-background:new 0 0
return `${icon} ${val}`;
}
-function processRules() {
+function processRules(includePass?: boolean) {
let retVal = [];
for (const ruleset of a11yRulesets as Guideline[]) {
if (ruleset.type === "extension") continue;
@@ -183,7 +183,7 @@ function processRules() {
if (msgCode === "group") return;
let re = new RegExp(`\\.Rule([^()) ]+)[ ()]+["']${msgCode}["']`);
let reMatch = re.exec(rule.run.toString());
- if (reMatch && reMatch[1] !== "Pass") {
+ if (includePass || (reMatch && reMatch[1] !== "Pass")) {
ruleInfo.reasons.push({
id: msgCode,
message: rule.messages["en-US"][msgCode],
@@ -200,6 +200,8 @@ function processRules() {
if (b.level === "Potential") return 1;
if (a.level === "Manual") return -1;
if (b.level === "Manual") return 1;
+ if (a.level === "Pass") return -1;
+ if (b.level === "Pass") return 1;
return 0;
})
cpInfo.rules.push(ruleInfo);
@@ -214,6 +216,9 @@ function processRules() {
if (retVal === 0) {
retVal = b.reasons.filter(reasonInfo => (reasonInfo.type === "Manual")).length - a.reasons.filter(reasonInfo => (reasonInfo.type === "Manual")).length;
}
+ if (retVal === 0) {
+ retVal = b.reasons.filter(reasonInfo => (reasonInfo.type === "Pass")).length - a.reasons.filter(reasonInfo => (reasonInfo.type === "Pass")).length;
+ }
return retVal;
}
if (a.level === "VIOLATION") return -1;
@@ -304,7 +309,73 @@ ${cpSections}
writeFileSync(path.join(__dirname, '..', 'dist', "help", "rules.html"), rulesHTML);
}
+function buildRuleMapping() {
+ const vMap = {
+ "VIOLATION_Fail": "Violation",
+ "VIOLATION_Potential": "Violation Potential",
+ "VIOLATION_Manual": "Violation Manual",
+ "VIOLATION_Pass": "Pass",
+ "RECOMMENDATION_Fail": "Rec",
+ "RECOMMENDATION_Potential": "Rec Potential",
+ "RECOMMENDATION_Manual": "Rec Manual",
+ "RECOMMENDATION_Pass": "Pass"
+ }
+ const actMap = {
+ "Pass": "pass",
+ "Fail": "fail",
+ "Potential": "cantTell",
+ "Manual": "cantTell"
+ }
+ const csv = (str : string) => {
+ if (str === null) {
+ return '"null"';
+ } else if (!str || str.length == 0) {
+ return '""';
+ } else {
+ str = str.replace(/"/g, '""');
+ return `"${str}"`;
+ }
+ }
+ let rsInfo = processRules(true);
+ let csvStr = `Rule ID, Reason Code, Rule message, Reason message, Violation Level, Toolkit Level, WCAG Requirements, ACT mapping\n`;
+ let ruleset = rsInfo.filter(rs => rs.id === "IBM_Accessibility")[0];
+ for (const checkpoint of ruleset.checkpoints) {
+ for (const rule of checkpoint.rules) {
+ for (const reason of rule.reasons) {
+ let vLevelStrings = [];
+ let tkLevelStrings = [];
+ let rsStrings = [];
+ let actStrings = [];
+ for (const rsInfo of rule.rule.rulesets) {
+ tkLevelStrings.push(rsInfo.toolkitLevel);
+ vLevelStrings.push(vMap[`${rsInfo.level}_${reason.type}`]);
+ rsStrings.push(rsInfo.num);
+ }
+ if (typeof rule.rule.act === typeof "") {
+ actStrings.push(rule.rule.act+":"+actMap[reason.type]);
+ } else if (rule.rule.act.length) {
+ for (const actInfo of rule.rule.act) {
+ if (typeof actInfo === typeof "") {
+ actStrings.push(actInfo+":"+actMap[reason.type]);
+ } else {
+ for (const key in actInfo) {
+ if (reason.id in actInfo[key]) {
+ actStrings.push(key+":"+actInfo[key][reason.id])
+ }
+ }
+ }
+ }
+ }
+ let csvStrLine = `${csv(rule.rule.id)},${csv(reason.id)},${csv(rule.rule.messages['en-US'].group)},${csv(reason.message)},${csv(vLevelStrings.join(" | "))},${csv(tkLevelStrings.join(" | "))},${csv(rsStrings.join(" | "))},${csv(actStrings.join(" | "))}\n`;
+ csvStr += csvStrLine;
+ }
+ }
+ }
+ writeFileSync(path.join(__dirname, '..', 'dist', "help", "rules.csv"), csvStr);
+}
+
(async () => {
await buildV4();
await buildRuleViewer();
+ await buildRuleMapping();
})();
\ No newline at end of file
diff --git a/accessibility-checker-engine/src/v4/rules/aria_activedescendant_valid.ts b/accessibility-checker-engine/src/v4/rules/aria_activedescendant_valid.ts
index 729b38b42..e13b21e91 100644
--- a/accessibility-checker-engine/src/v4/rules/aria_activedescendant_valid.ts
+++ b/accessibility-checker-engine/src/v4/rules/aria_activedescendant_valid.ts
@@ -26,8 +26,9 @@ export let aria_activedescendant_valid: Rule = {
"Pass_0": "Pass_0",
"Fail_1": "Fail_1",
"Fail_2": "Fail_2",
- "Fail_3": "Fail_3",
- "Fail_4": "Fail_4"}
+ "Fail_3": "Fail_3"
+ // "Fail_4": "Fail_4"
+ }
},
help: {
"en-US": {
@@ -35,7 +36,7 @@ export let aria_activedescendant_valid: Rule = {
"Fail_1": "aria_activedescendant_valid.html",
"Fail_2": "aria_activedescendant_valid.html",
"Fail_3": "aria_activedescendant_valid.html",
- "Fail_4": "aria_activedescendant_valid.html",
+ // "Fail_4": "aria_activedescendant_valid.html",
"group": "aria_activedescendant_valid.html"
}
},
@@ -45,7 +46,7 @@ export let aria_activedescendant_valid: Rule = {
"Fail_1": "The 'aria-activedescendant' property is empty",
"Fail_2": "The 'aria-activedescendant' property references a hidden node",
"Fail_3": "Element is not a combobox, and the referenced active-descendant element is not a valid descendant",
- "Fail_4": "Element is a combobox, and the referenced active-descendant element is not controlled by this component",
+ // "Fail_4": "Element is a combobox, and the referenced active-descendant element is not controlled by this component",
"group": "The 'aria-activedescendant' property must reference the 'id' of a non-empty, non-hidden active child element"
}
},
diff --git a/accessibility-checker-engine/src/v4/rules/aria_attribute_conflict.ts b/accessibility-checker-engine/src/v4/rules/aria_attribute_conflict.ts
index 38a67811b..27c7b3d11 100644
--- a/accessibility-checker-engine/src/v4/rules/aria_attribute_conflict.ts
+++ b/accessibility-checker-engine/src/v4/rules/aria_attribute_conflict.ts
@@ -23,14 +23,14 @@ export let aria_attribute_conflict: Rule = {
+ ", dom:*[aria-rowspan]",
help: {
"en-US": {
- "pass": "aria_attribute_conflict.html",
+ // "pass": "aria_attribute_conflict.html",
"fail_conflict": "aria_attribute_conflict.html",
"group": "aria_attribute_conflict.html"
}
},
messages: {
"en-US": {
- "pass": "The ARIA attribute is not conflict with the corresponding HTML attribute",
+ // "pass": "The ARIA attribute is not conflict with the corresponding HTML attribute",
"fail_conflict": "The ARIA attribute \"{0}\" is in conflict with the corresponding HTML attribute \"{1}\"",
"group": "An ARIA attribute must not conflict with the corresponding HTML attribute"
}
diff --git a/accessibility-checker-engine/src/v4/rules/aria_attribute_deprecated.ts b/accessibility-checker-engine/src/v4/rules/aria_attribute_deprecated.ts
index ccaa3aa61..e72a9b87d 100644
--- a/accessibility-checker-engine/src/v4/rules/aria_attribute_deprecated.ts
+++ b/accessibility-checker-engine/src/v4/rules/aria_attribute_deprecated.ts
@@ -20,7 +20,7 @@ export let aria_attribute_deprecated: Rule = {
context: "dom:*",
help: {
"en-US": {
- "pass": "aria_attribute_deprecated.html",
+ // "pass": "aria_attribute_deprecated.html",
"fail_aria_role": "aria_attribute_deprecated.html",
"fail_aria_attr": "aria_attribute_deprecated.html",
"fail_role_attr": "aria_attribute_deprecated.html",
@@ -29,7 +29,7 @@ export let aria_attribute_deprecated: Rule = {
},
messages: {
"en-US": {
- "pass": "The ARIA roles and attribute are used per specification",
+ // "pass": "The ARIA roles and attribute are used per specification",
"fail_aria_role": "The ARIA role \"{0}\" is deprecated in the ARIA specification",
"fail_aria_attr": "The ARIA attributes \"{0}\" are deprecated in the ARIA specification",
"fail_role_attr": "The ARIA attributes \"{0}\" are deprecated for the role \"{1}\" in the ARIA specification",
diff --git a/accessibility-checker-engine/src/v4/rules/aria_region_labelled.ts b/accessibility-checker-engine/src/v4/rules/aria_region_labelled.ts
index 408d71008..03a861209 100644
--- a/accessibility-checker-engine/src/v4/rules/aria_region_labelled.ts
+++ b/accessibility-checker-engine/src/v4/rules/aria_region_labelled.ts
@@ -22,14 +22,15 @@ export let aria_region_labelled: Rule = {
refactor: {
"Rpt_Aria_RegionLabel_Implicit": {
"Pass_0": "Pass_0",
- "Fail_1": "Fail_1",
- "Fail_2": "Fail_2"}
+ "Fail_1": "Fail_1"
+ // "Fail_2": "Fail_2"
+ }
},
help: {
"en-US": {
"Pass_0": "aria_region_labelled.html",
"Fail_1": "aria_region_labelled.html",
- "Fail_2": "aria_region_labelled.html",
+ // "Fail_2": "aria_region_labelled.html",
"group": "aria_region_labelled.html"
}
},
@@ -37,7 +38,7 @@ export let aria_region_labelled: Rule = {
"en-US": {
"Pass_0": "Rule Passed",
"Fail_1": "Element with \"region\" role does not have a label",
- "Fail_2": "Element with \"region\" role is not labeled with 'aria-label' or 'aria-labelledby'",
+ // "Fail_2": "Element with \"region\" role is not labeled with 'aria-label' or 'aria-labelledby'",
"group": "Each element with \"region\" role must have a label that describes its purpose"
}
},
diff --git a/accessibility-checker-engine/src/v4/rules/blink_elem_deprecated.ts b/accessibility-checker-engine/src/v4/rules/blink_elem_deprecated.ts
index 13f71ff5a..21c4d8f5c 100644
--- a/accessibility-checker-engine/src/v4/rules/blink_elem_deprecated.ts
+++ b/accessibility-checker-engine/src/v4/rules/blink_elem_deprecated.ts
@@ -19,21 +19,18 @@ export let blink_elem_deprecated: Rule = {
context: "dom:blink",
refactor: {
"WCAG20_Blink_AlwaysTrigger": {
- "Pass_0": "Pass_0",
"Fail_1": "Fail_1"
}
},
help: {
"en-US": {
"group": `blink_elem_deprecated.html`,
- "Pass_0": `blink_elem_deprecated.html`,
"Fail_1": `blink_elem_deprecated.html`
}
},
messages: {
"en-US": {
"group": "Content that blinks persistently must not be used",
- "Pass_0": "Rule Passed",
"Fail_1": "Content found that blinks persistently"
}
},
diff --git a/accessibility-checker-engine/src/v4/rules/canvas_content_described.ts b/accessibility-checker-engine/src/v4/rules/canvas_content_described.ts
index 65968b706..6fc320f28 100644
--- a/accessibility-checker-engine/src/v4/rules/canvas_content_described.ts
+++ b/accessibility-checker-engine/src/v4/rules/canvas_content_described.ts
@@ -49,7 +49,7 @@ export let canvas_content_described: Rule = {
//skip the rule
if (VisUtil.isNodeHiddenFromAT(ruleContext)) return null;
let passed = ruleContext.innerHTML.trim().length > 0;
- if (passed) return RulePass(1);
+ if (passed) return RulePass("Pass_0");
if (!passed) return RuleManual("Manual_1");
}
}
\ No newline at end of file
diff --git a/accessibility-checker-engine/src/v4/rules/combobox_popup_reference.ts b/accessibility-checker-engine/src/v4/rules/combobox_popup_reference.ts
index 7d72e6378..f20e79e57 100644
--- a/accessibility-checker-engine/src/v4/rules/combobox_popup_reference.ts
+++ b/accessibility-checker-engine/src/v4/rules/combobox_popup_reference.ts
@@ -119,9 +119,17 @@ export let combobox_popup_reference: Rule = {
}
if (pattern === "1.0") {
- return RulePass(expanded ? "Pass_1.0_expanded" : "Pass_1.0_collapsed");
+ if (expanded) {
+ return RulePass("Pass_1.0_expanded");
+ } else {
+ return RulePass("Pass_1.0_collapsed");
+ }
} else {
- return RulePass(expanded ? "Pass_1.2_expanded" : "Pass_1.2_collapsed");
+ if (expanded) {
+ return RulePass("Pass_1.2_expanded");
+ } else {
+ return RulePass("Pass_1.2_collapsed");
+ }
}
}
}
\ No newline at end of file
diff --git a/accessibility-checker-engine/src/v4/rules/download_keyboard_controllable.ts b/accessibility-checker-engine/src/v4/rules/download_keyboard_controllable.ts
index 505498a6f..8b27756f3 100644
--- a/accessibility-checker-engine/src/v4/rules/download_keyboard_controllable.ts
+++ b/accessibility-checker-engine/src/v4/rules/download_keyboard_controllable.ts
@@ -21,19 +21,16 @@ export let download_keyboard_controllable: Rule = {
context: "dom:a[href],dom:area[href]",
refactor: {
"HAAC_Media_DocumentTrigger2": {
- "Pass_0": "Pass_0",
"Manual_1": "Manual_1"}
},
help: {
"en-US": {
- "Pass_0": "download_keyboard_controllable.html",
"Manual_1": "download_keyboard_controllable.html",
"group": "download_keyboard_controllable.html"
}
},
messages: {
"en-US": {
- "Pass_0": "Rule Passed",
"Manual_1": "Verify that the file download mechanism does not cause a keyboard trap",
"group": "File download mechanisms should be keyboard-operable and preserve page focus location"
}
diff --git a/accessibility-checker-engine/src/v4/rules/draggable_alternative_exists.ts b/accessibility-checker-engine/src/v4/rules/draggable_alternative_exists.ts
index b3e71b3d4..828d6c531 100644
--- a/accessibility-checker-engine/src/v4/rules/draggable_alternative_exists.ts
+++ b/accessibility-checker-engine/src/v4/rules/draggable_alternative_exists.ts
@@ -23,7 +23,7 @@ export let draggable_alternative_exists: Rule = {
help: {
"en-US": {
"group": "draggable_alternative_exists.html",
- "pass_alternative": "draggable_alternative_exists.html",
+ // "pass_alternative": "draggable_alternative_exists.html",
"pass_undraggable": "draggable_alternative_exists.html",
"potential_alternative": "draggable_alternative_exists.html"
}
@@ -31,7 +31,7 @@ export let draggable_alternative_exists: Rule = {
messages: {
"en-US": {
"group": "A draggable element must have a \"single pointer\" alternative",
- "pass_alternative": "The draggable element \"{0}\" has a \"single pointer\" alternative",
+ // "pass_alternative": "The draggable element \"{0}\" has a \"single pointer\" alternative",
"pass_undraggable": "The element \"{0}\" is not draggable",
"potential_alternative": "Ensure the draggable element \"{0}\" has a \"single pointer\" alternative"
}
diff --git a/accessibility-checker-engine/src/v4/rules/input_haspopup_conflict.ts b/accessibility-checker-engine/src/v4/rules/input_haspopup_conflict.ts
index 10dd36395..a38a25c38 100644
--- a/accessibility-checker-engine/src/v4/rules/input_haspopup_conflict.ts
+++ b/accessibility-checker-engine/src/v4/rules/input_haspopup_conflict.ts
@@ -21,14 +21,14 @@ export let input_haspopup_conflict: Rule = {
context: "dom:input[list][aria-haspopup]",
refactor: {
"input_haspopup_invalid": {
- "Pass": "pass",
+ // "Pass": "pass",
"Potential_1": "potential_type_misuse",
"Potential_2": "potential_misuse"}
},
help: {
"en-US": {
"group": "input_haspopup_conflict.html",
- "pass": "input_haspopup_conflict.html",
+ // "pass": "input_haspopup_conflict.html",
"potential_type_misuse": "input_haspopup_conflict.html",
"potential_misuse": "input_haspopup_conflict.html",
"potential_list_notexist": "input_haspopup_conflict.html",
@@ -39,7 +39,7 @@ export let input_haspopup_conflict: Rule = {
messages: {
"en-US": {
"group": " element with a 'list' attribute should not use an explicit 'aria-haspopup' attribute",
- "pass": "The element with a 'list' attribute does not use an explicit 'aria-haspopup' attribute",
+ // "pass": "The element with a 'list' attribute does not use an explicit 'aria-haspopup' attribute",
"potential_type_misuse": "The element with type \"{0}\" and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"potential_misuse": "The element with a missing or invalid type and 'list' attribute uses an explicit 'aria-haspopup' attribute",
"potential_list_notexist": "The list attribute for the element is invalid",
diff --git a/accessibility-checker-engine/src/v4/rules/input_onchange_review.ts b/accessibility-checker-engine/src/v4/rules/input_onchange_review.ts
index 973ca53ad..a8ca38ea4 100644
--- a/accessibility-checker-engine/src/v4/rules/input_onchange_review.ts
+++ b/accessibility-checker-engine/src/v4/rules/input_onchange_review.ts
@@ -19,12 +19,12 @@ export let input_onchange_review: Rule = {
context: "dom:input[onchange], dom:textarea[onchange], dom:select[onchange]",
refactor: {
"WCAG20_Input_HasOnchange": {
- "Pass_0": "pass",
+ // "Pass_0": "pass",
"Potential_1": "potential_warning"}
},
help: {
"en-US": {
- "pass": "input_onchange_review.html",
+ // "pass": "input_onchange_review.html",
"potential_warning": "input_onchange_review.html",
"group": "input_onchange_review.html"
}
@@ -32,7 +32,7 @@ export let input_onchange_review: Rule = {
messages: {
"en-US": {
"group": "Users must be advised if, due to a change of element value, a form automatically submits, a new window opens, or a change in focus occurs",
- "pass": "The user is advised of the automatic form submission, new window opening, or focus change",
+ // "pass": "The user is advised of the automatic form submission, new window opening, or focus change",
"potential_warning": "Confirm that the user is advised if, due to a change of element value, a form automatically submits, a new window opens, or a change in focus occurs"
}
},
diff --git a/accessibility-checker-engine/src/v4/rules/list_markup_review.ts b/accessibility-checker-engine/src/v4/rules/list_markup_review.ts
index dcf43807c..7c3e0cc49 100644
--- a/accessibility-checker-engine/src/v4/rules/list_markup_review.ts
+++ b/accessibility-checker-engine/src/v4/rules/list_markup_review.ts
@@ -21,19 +21,19 @@ export let list_markup_review: Rule = {
context: "dom:*",
refactor: {
"RPT_List_UseMarkup": {
- "Pass_0": "Pass_0",
+ // "Pass_0": "Pass_0",
"Potential_1": "Potential_1"}
},
help: {
"en-US": {
- "pass": "list_markup_review.html",
+ // "pass": "list_markup_review.html",
"potential_list": "list_markup_review.html",
"group": "list_markup_review.html"
}
},
messages: {
"en-US": {
- "pass": "Proper HTML elements are used to create a list",
+ // "pass": "Proper HTML elements are used to create a list",
"potential_list": "Verify this is a list and if so, modify to use proper HTML elements for the list",
"group": "Proper HTML elements should be used to create a list"
}
diff --git a/accessibility-checker-engine/src/v4/rules/marquee_elem_avoid.ts b/accessibility-checker-engine/src/v4/rules/marquee_elem_avoid.ts
index 6b38094ca..abc619018 100644
--- a/accessibility-checker-engine/src/v4/rules/marquee_elem_avoid.ts
+++ b/accessibility-checker-engine/src/v4/rules/marquee_elem_avoid.ts
@@ -20,19 +20,17 @@ export let marquee_elem_avoid: Rule = {
context: "dom:marquee",
refactor: {
"RPT_Marquee_Trigger": {
- "Passed_0": "Passed_0",
- "Fail_1": "Fail_1"}
+ "Fail_1": "Fail_1"
+ }
},
help: {
"en-US": {
- "Passed_0": "marquee_elem_avoid.html",
"Fail_1": "marquee_elem_avoid.html",
"group": "marquee_elem_avoid.html"
}
},
messages: {
"en-US": {
- "Passed_0": "Rule Passed",
"Fail_1": "Scrolling content found that uses the obsolete