Skip to content

Commit

Permalink
chore(rules): add htmlcs rule tags
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mendez committed Mar 10, 2024
1 parent 278b9b8 commit 3249b3b
Show file tree
Hide file tree
Showing 23 changed files with 4,162 additions and 682 deletions.
30 changes: 19 additions & 11 deletions kayle/builder/build-htmlcs-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import { parse } from "acorn";
import { simple } from "acorn-walk";
import { generate } from "escodegen";
import type { ParamList } from "./build-types";
import { processIncludeFiles } from "./build-htmlcs-rule-list";

const paramList: ParamList[] = [];

const processDirectory = (directory) => {
const processDirectory = (directory, paramList: ParamList[]) => {
readdirSync(directory).forEach((file) => {
const fullPath = join(directory, file);
if (lstatSync(fullPath).isDirectory()) {
processDirectory(fullPath);
processDirectory(fullPath, paramList);
} else if (fullPath.endsWith(".js")) {
processFile(fullPath);
processFile(fullPath, paramList);
}
});
};
Expand All @@ -36,11 +35,10 @@ const isHTMLCSAddMessageCall = (node) => {
};

// get the add Message call directly
const extractPureAddMessageArgs = (s: string) => {
return s.replace(/\.replace\(.*?\)/, "").replace(/^_global\./, "");
};
const extractPureAddMessageArgs = (s: string) =>
s.replace(/\.replace\(.*?\)/, "").replace(/^_global\./, "");

const processFile = (filePath) => {
const processFile = (filePath, paramList: ParamList[]) => {
const code = readFileSync(filePath, "utf8");
const ast = parse(code, { sourceType: "script", ecmaVersion: 2020 });

Expand Down Expand Up @@ -105,6 +103,16 @@ const processFile = (filePath) => {

// process the params to a list
export const processParams = () => {
processDirectory("../fast_htmlcs/dist/Standards");
return paramList;
const paramList: ParamList[] = [];

const { WCAGAAA, WCAGAA, WCAGA } = processIncludeFiles();

processDirectory("../fast_htmlcs/dist/Standards", paramList);

return {
WCAGAAA,
WCAGAA,
WCAGA,
paramList,
};
};
74 changes: 74 additions & 0 deletions kayle/builder/build-htmlcs-rule-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { readFileSync } from "fs";
import { parse } from "acorn";

const traverse = (node, callback) => {
callback(node);
for (const key in node) {
if (node.hasOwnProperty(key)) {
const child = node[key];
if (typeof child === "object" && child !== null) {
if (Array.isArray(child)) {
child.forEach((node) => traverse(node, callback));
} else {
traverse(child, callback);
}
}
}
}
};

const processFile = (filePath, arr: string[]) => {
const code = readFileSync(filePath, "utf8");
const ast = parse(code, { sourceType: "script", ecmaVersion: 2020 });

traverse(ast, (node) => {
if (node.type === "Property" || node.type === "ObjectProperty") {
const key = node.key.name || (node.key.value ? node.key.value : "");

if (key === "sniffs") {
if (
node.value.type === "ArrayExpression" &&
node.value.elements.every((ele) => ele.type === "Literal")
) {
node.value.elements.forEach((element) => {
arr.push(element.value);
});
} else if (node.value.type === "ArrayExpression") {
node.value.elements.forEach((element) => {
if (element.type === "ObjectExpression") {
element.properties.forEach((prop) => {
if (
prop.key.name === "include" &&
prop.value.type === "ArrayExpression"
) {
prop.value.elements.forEach((innerElement) => {
if (innerElement.type === "Literal") {
arr.push(innerElement.value);
}
});
}
});
}
});
}
}
}
});
};

// process the files by wcag code
export const processIncludeFiles = () => {
const WCAGAAA: string[] = [];
const WCAGAA: string[] = [];
const WCAGA: string[] = [];

processFile("../fast_htmlcs/dist/Standards/WCAG2AAA/ruleset.js", WCAGAAA);
processFile("../fast_htmlcs/dist/Standards/WCAG2AA/ruleset.js", WCAGAA);
processFile("../fast_htmlcs/dist/Standards/WCAG2A/ruleset.js", WCAGA);

return {
WCAGAAA,
WCAGAA,
WCAGA,
};
};
40 changes: 23 additions & 17 deletions kayle/builder/build-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { processParams } from "./build-htmlcs-params";
import type { Rule } from "./build-types";

(async () => {
const paramList = await processParams();
const dynamicParams = await processParams();
const browser = await chromium.launch({ headless: true });

// default config
Expand All @@ -21,6 +21,7 @@ import type { Rule } from "./build-types";

const runBuildRules = async (language: string) => {
const page = await browser.newPage();
page.on("console", (msg) => console.log("PAGE LOG:", msg.text()));

const fast_htmlcs_rules: Rule[] = [];
const fast_axe_rules: Rule[] = [];
Expand All @@ -39,21 +40,24 @@ import type { Rule } from "./build-types";
true,
);

await page.evaluate((o) => {
window.paramList = o;
}, paramList);

await page.addScriptTag({
content: `window.htmlcsRuleMap = ${htmlcsRuleMap.toString()};`,
});

await page.exposeFunction("pushHtmlcsRule", (t: Rule[]) =>
fast_htmlcs_rules.push(...t),
);

await page.exposeFunction("pushAxeRule", (t: Rule) =>
fast_axe_rules.push(t),
);
await Promise.all([
page.evaluate((o) => {
window.paramList = o.paramList;
window.WCAGA = o.WCAGA;
window.WCAGAA = o.WCAGAA;
window.WCAGAAA = o.WCAGAAA;
}, dynamicParams),
page.addScriptTag({
content: `window.htmlcsRuleMap = ${htmlcsRuleMap.toString()};`,
}),
page.addScriptTag({
content: `window.htmlcsRuleMap = ${htmlcsRuleMap.toString()};`,
}),
page.exposeFunction("pushHtmlcsRule", (t: Rule[]) =>
fast_htmlcs_rules.push(...t),
),
page.exposeFunction("pushAxeRule", (t: Rule) => fast_axe_rules.push(t)),
]);

await page.evaluate(() => {
for (const r of window.axe.getRules()) {
Expand Down Expand Up @@ -100,7 +104,9 @@ import type { Rule } from "./build-types";
"utf8",
);

await page.close();
await page.close({
runBeforeUnload: true,
});
};

const localesList: string[] = Array.from(
Expand Down
3 changes: 3 additions & 0 deletions kayle/builder/build-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ declare global {
pushAxeRule: (r: Rule) => void;
htmlcsRuleMap: (t: ParamList) => Rule[];
paramList: ParamList[];
WCAGAAA: string[];
WCAGAA: string[];
WCAGA: string[];
}
}

Expand Down
43 changes: 36 additions & 7 deletions kayle/builder/htmlcs-rule-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ export const htmlcsRuleMap = (rule: ParamList) => {
} catch (_e) {}

if (description.startsWith("HTMLCS.getTranslation(")) {
description = eval(description);
try {
description = eval(description);
} catch (_e) {}
}

const baseRule = `${rule[4]}${
Expand All @@ -56,30 +58,57 @@ export const htmlcsRuleMap = (rule: ParamList) => {
? inlineRule.substring(1, inlineRule.length - 1)
: baseRuleId;

const ruleId = rule[5]
? `${rule[5].replace("_Guideline", ".Guideline")}.${_ruleId}`
: _ruleId;
const ruleId =
rule[5] && (inlineRule || !rule[2])
? `${rule[5].replace("_Guideline", ".Guideline")}.${_ruleId}`
: _ruleId;

const pattern = /(.{3})_or_(.{3})/;

const [, leftPart, rightPart] = ruleId.match(pattern) || [];

const ruleObj = {
ruleId,
ruleId: ruleId.replace("'", ""),
description,
helpUrl: section508
? []
: helpLinks.map((r) => concatWcagLink(r.split(".")[0])),
ruleType: rule[0] as "error" | "warning" | "notice",
tags: [] as string[],
};

// invalid rule
if (!ruleObj.description || ruleObj.description === "msg") {
return;
}

const getTags = (rid: string) => {
const _rid = rid.split(".");
const sl = _rid[2] || "";
const ruleTarget =
rid.length >= 3 ? `${_rid[0]}.${_rid[1]}.${sl.substring(0, 5)}` : _rid[0];

return [
ruleTarget.startsWith("Principle") ? "" : "SECTION508",
window.WCAGA.includes(ruleTarget) ? "WCAGA" : "",
window.WCAGAA.includes(ruleTarget) ? "WCAGAA" : "",
window.WCAGAAA.includes(ruleTarget) ? "WCAGAAA" : "",
].filter(Boolean);
};

// Check if both parts were found
if (leftPart && rightPart) {
ruleObj.ruleId = ruleId.replace(pattern, leftPart);
ruleObj.ruleId = ruleId.replace(pattern, leftPart).replace("'", "");
ruleObj.tags = getTags(ruleObj.ruleId);
rules.push(ruleObj);
ruleObj.ruleId = ruleId.replace(pattern, rightPart);

ruleObj.ruleId = ruleId.replace(pattern, rightPart).replace("'", "");
ruleObj.tags = getTags(ruleObj.ruleId);

rules.push(ruleObj);
} else {
ruleObj.tags = getTags(ruleObj.ruleId);

rules.push(ruleObj);
}

Expand Down
Loading

0 comments on commit 3249b3b

Please sign in to comment.