Skip to content

Commit

Permalink
feat(htmlcs): add runtime extending and rules set
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mendez committed Feb 11, 2024
1 parent 7e4ebc2 commit 1e44de6
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 60 deletions.
38 changes: 37 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const results = await kayle({

- [`fast_axecore`](./fast_htmlcs/README.md): run tests using fork of [axe-core](./lib/runners/axe.ts).
- [`fast_htmlcs`](./fast_htmlcs/README.md): run tests using fork of [HTML CodeSniffer](./lib/runners/htmlcs.ts).
- `custom`: custom runners using `injectRunner` util.
- `custom`: custom runners using [`injectRunner`](./kayle/lib/runner-js.ts#l=57) util - library authors.

## Linting

Expand Down Expand Up @@ -245,6 +245,42 @@ Use the command `yarn build` to compile all the scripts for each locale.

We are building a rust based runner called [kayle_innate](./kayle_innate/) that can port to wasm that will take the audits into the nanoseconds - low milliseconds zone.

## Custom Runner (library authors)

Below is an example on adding a new custom runner. Take a look at [HTMLCS](fast_htmlcs/HTMLCS.ts) and [HTMLCS_Runner](kayle/lib/runners/htmlcs.ts) setup for an example of how to setup the scripts, it could take around 10 mins to get familiar. You can also overwride the base runners by taking the `runnersJavascript` object and appending to the script.

```ts
import { injectRunner, kayle } from "kayle"

// example of the custom script take a
injectRunner("htmlcs_extended", "./custom_htmlcs_script", "en")

const results = await kayle({
page,
browser,
runners: ["htmlcs", "htmlcs_extended"]
origin: "https://a11ywatch.com",
});
```

## Extend Runner

Extending a runner can be done with the following.

```ts
import { extendRunner, kayle } from "kayle"

// example of the custom script take a
extendRunner("htmlcs", "./custom_htmlcs_script", "en")

const results = await kayle({
page,
browser,
runners: ["htmlcs", "htmlcs_extended"]
origin: "https://a11ywatch.com",
});
```

## Discord

If you want to chat about the project checkout our [Discord][discord-url].
Expand Down
35 changes: 16 additions & 19 deletions fast_htmlcs/HTMLCS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,23 +340,22 @@ _global.HTMLCS = new (function () {
failCallback,
options
) => {
const _standard = _getStandardPath(standard);

const localStandard = _getStandardPath(standard);
// See if the ruleset object is already included (eg. if minified).
const parts = _standard.split("/");
const parts = localStandard.split("/");
const part = parts[parts.length - 2];
const ruleSet = _getRuleset(part);

if (ruleSet) {
// Already included.
_registerStandard(_standard, part, callback, failCallback, options);
this.registerStandard(standard, part, callback, failCallback, options);
} else {
// TODO: remove _include script callback standard always included
_includeScript(
_standard,
function () {
// Script is included now register the standard.
_registerStandard(_standard, part, callback, failCallback, options);
this.registerStandard(_standard, part, callback, failCallback, options);
},
failCallback
);
Expand All @@ -370,7 +369,7 @@ _global.HTMLCS = new (function () {
* @param {Function} callback The function to call once the standard is registered.
* @param {Object} options The options for the standard (e.g. exclude sniffs).
*/
const _registerStandard = (
this.registerStandard = (
standard,
part,
callback,
Expand All @@ -390,6 +389,7 @@ _global.HTMLCS = new (function () {
}
}

// include the new rules for the standard
_standards.set(standard, ruleSet);

// Process the options.
Expand Down Expand Up @@ -456,8 +456,8 @@ _global.HTMLCS = new (function () {
if (typeof sniff === "string") {
const sniffObj = _getSniff(standard, sniff);

const cb = function () {
_registerSniff(standard, sniff);
const cb = () => {
this.registerSniff(standard, sniff);
callback.call(this);
};

Expand Down Expand Up @@ -490,7 +490,7 @@ _global.HTMLCS = new (function () {
* @param {String} standard The name of the standard.
* @param {String} sniff The name of the sniff.
*/
const _registerSniff = (standard, sniff) => {
this.registerSniff = (standard: string, sniff: string) => {
// Get the sniff object.
const sniffObj = _getSniff(standard, sniff);

Expand Down Expand Up @@ -542,20 +542,17 @@ _global.HTMLCS = new (function () {
*
* @returns {Object} The sniff object.
*/
const _getSniff = (standard, sniff) => {
const cstandard = _standards.has(standard) && _standards.get(standard); // standard should always exist
let name = "HTMLCS_";

name += ((cstandard && cstandard.name) || "") + "_Sniffs_";
name += sniff.split(".").join("_");
const _getSniff = (standard, sniff: string) => {
const name = `HTMLCS_${standard}_Sniffs_${sniff.split(".").join("_")}`;
const sniffSet = _global[name] || window[name];

if (!_global[name]) {
if (!sniffSet) {
return null;
}

sniffSet._name = sniff;

_global[name]._name = sniff;

return _global[name];
return sniffSet;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,28 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle3_Guideline3_1_3_1_1 = {
"H57.2"
);
} else {
if (element.hasAttribute("lang") === true) {
var lang = element.getAttribute("lang");
if (this.isValidLanguageTag(lang) === false) {
HTMLCS.addMessage(
HTMLCS.ERROR,
top,
_global.HTMLCS.getTranslation("3_1_1_H57.3.Lang"),
"H57.3.Lang"
);
}
if (
element.hasAttribute("lang") &&
!this.isValidLanguageTag(element.getAttribute("lang"))
) {
HTMLCS.addMessage(
HTMLCS.ERROR,
top,
_global.HTMLCS.getTranslation("3_1_1_H57.3.Lang"),
"H57.3.Lang"
);
}

if (element.hasAttribute("xml:lang") === true) {
var lang = element.getAttribute("xml:lang");
if (this.isValidLanguageTag(lang) === false) {
HTMLCS.addMessage(
HTMLCS.ERROR,
top,
_global.HTMLCS.getTranslation("3_1_1_H57.3.XmlLang"),
"H57.3.XmlLang"
);
}
if (
element.hasAttribute("xml:lang") &&
!this.isValidLanguageTag(element.getAttribute("xml:lang"))
) {
HTMLCS.addMessage(
HTMLCS.ERROR,
top,
_global.HTMLCS.getTranslation("3_1_1_H57.3.XmlLang"),
"H57.3.XmlLang"
);
}
}
},
Expand Down Expand Up @@ -97,16 +97,8 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle3_Guideline3_1_3_1_1 = {
regexStr += "(-x(-[a-z0-9]{1,8})+)?$";

// Make a regex out of it, and make it all case-insensitive.
var regex = new RegExp(regexStr, "i");

// Throw the correct lang code depending on whether this is a document
// element or not.
var valid = true;

if (regex.test(langTag) === false) {
valid = false;
}

return valid;
return new RegExp(regexStr, "i").test(langTag);
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ _global.HTMLCS_WCAG2AAA_Sniffs_Principle3_Guideline3_1_3_1_2 = {

let langEl = null;

for (var i = 0; i <= langEls.length; i++) {
for (let i = 0; i <= langEls.length; i++) {
if (i === langEls.length) {
langEl = top;
} else {
Expand Down
2 changes: 1 addition & 1 deletion fast_htmlcs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fast_htmlcs",
"version": "0.0.72",
"version": "0.0.74",
"description": "A high performance fork of HTML_CodeSniffer.",
"license": "BSD-3-Clause",
"main": "index.js",
Expand Down
5 changes: 5 additions & 0 deletions kayle/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,8 @@ export enum Standard {
}

export { Runner };

export const enum MainRunner {
htmlcs = "htmlcs",
axe = "axe",
}
8 changes: 7 additions & 1 deletion kayle/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
export { kayle } from "./kayle";
export type { Issue, Audit, MetaInfo, Automatable } from "./common";
export { autoKayle } from "./auto";
export { runnersJavascript, getRunner, injectRunner } from "./runner-js";
export {
runnersJavascript,
getRunner,
injectRunner,
extendRunner,
} from "./runner-js";
export {
goToPage,
setNetworkInterception,
Expand All @@ -14,6 +19,7 @@ export {
export {
setLogging,
Standard,
MainRunner,
type RunnerConfig,
type Runner,
type LifeCycleEvent,
Expand Down
24 changes: 22 additions & 2 deletions kayle/lib/runner-js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,13 @@ const runnersJavascript = {
// axe_pt_BR: loadRunnerScript("axe", "pt-BR"),
};

// inject a new runner for testing
/**
* Inject a new runner for testing
* @param {String} [runner="custom_name"] - The custom runner name.
* @param {String} [path=""] - The path of the file for the runner script.
* @param {String} [lang=""] - The language of the runner script.
* @returns {void}
*/
const injectRunner = (runner: string, path: string, lang: string) => {
runnersJavascript[runner] = loadRunnerScript(path, lang ?? "");
};
Expand Down Expand Up @@ -102,4 +108,18 @@ export type Runner = Exclude<
| "axe_ko"
>;

export { runnersJavascript, getRunner, injectRunner };
/**
* Extend the base of a runner with custom code.
* @param {String} [runner=""] - The custom runner to extend.
* @param {String} [script=""] - The custom javascript.
* @param {String} [lang=""] - The target langauge for the script.
* @returns {void}
*/
const extendRunner = (runner: Runner, script: string, lang?: string) => {
const runnerType = `${runner}${lang ? `_${lang}` : ""}`;
const runnerCode = runnersJavascript[runnerType];

runnersJavascript[runnerType] = `${runnerCode}${script};`;
};

export { runnersJavascript, getRunner, injectRunner, extendRunner };
5 changes: 1 addition & 4 deletions kayle/lib/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,7 @@
if (issue.element) {
context = getElementContext(issue.element);
selector = getElementSelector(issue.element);
if (
cliped &&
typeof issue.element.getBoundingClientRect === "function"
) {
if (cliped && typeof issue.element.getBoundingClientRect === "function") {
const { x, y, width, height } = issue.element.getBoundingClientRect();

clip = {
Expand Down
3 changes: 2 additions & 1 deletion kayle/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kayle",
"version": "0.8.11",
"version": "0.8.12",
"description": "Extremely fast and accurate accessibility engine built for any headless tool like playwright or puppeteer.",
"main": "./build/index.js",
"keywords": [
Expand Down Expand Up @@ -53,6 +53,7 @@
"test:puppeteer:tables": "npm run compile:test && node _tests/tests/tables.js",
"test:puppeteer:clips": "npm run compile:test && node _tests/tests/clips.js",
"test:puppeteer:innate": "npm run compile:test && node _tests/tests/innate.js",
"test:htmlcs:extend": "npm run compile:test && node _tests/tests/extend-runner.js",
"test:full": "npm run compile:test && node _tests/tests/full.js",
"test:lint": "node build/lint.js",
"test:unit:unique-selector": "npm run compile:test && node _tests/tests/unit/unique-selector.js",
Expand Down
2 changes: 1 addition & 1 deletion kayle/tests/basic-htmlcs-playwright.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ test("fast_htmlcs audit drakeMock", async ({ page, browser }, testInfo) => {
includeWarnings: true,
html: drakeMock,
origin: "https://www.drake.com",
standard: Standard.WCAG2AA
standard: Standard.WCAG2AA,
});
const endTime = performance.now() - startTime;

Expand Down
Loading

0 comments on commit 1e44de6

Please sign in to comment.