@accesslint/cli 0.2.0 → 0.3.0
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/dist/audit.d.ts +12 -0
- package/dist/audit.js +47 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +6 -7
- package/dist/format.d.ts +4 -0
- package/dist/inline-css.d.ts +1 -0
- package/dist/inline-css.js +81 -0
- package/dist/input.d.ts +1 -0
- package/package.json +8 -2
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type AuditResult } from "@accesslint/core";
|
|
2
|
+
export interface AuditOptions {
|
|
3
|
+
includeAAA?: boolean;
|
|
4
|
+
componentMode?: boolean;
|
|
5
|
+
disabledRules?: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Returns true if the HTML looks like a fragment/component rather than a full
|
|
9
|
+
* document (i.e. it lacks a doctype or <html> tag).
|
|
10
|
+
*/
|
|
11
|
+
export declare function isHTMLFragment(html: string): boolean;
|
|
12
|
+
export declare function audit(html: string, options?: AuditOptions): AuditResult;
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/audit.ts
|
|
2
|
+
import { JSDOM, VirtualConsole } from "jsdom";
|
|
3
|
+
import {
|
|
4
|
+
runAudit,
|
|
5
|
+
configureRules
|
|
6
|
+
} from "@accesslint/core";
|
|
7
|
+
function isHTMLFragment(html) {
|
|
8
|
+
const prefix = html.slice(0, 1000);
|
|
9
|
+
return !(/<!doctype\s/i.test(prefix) || /<html[\s>]/i.test(prefix));
|
|
10
|
+
}
|
|
11
|
+
var globalsRegistered = false;
|
|
12
|
+
function ensureGlobals(window) {
|
|
13
|
+
if (globalsRegistered)
|
|
14
|
+
return;
|
|
15
|
+
for (const key of Object.getOwnPropertyNames(window)) {
|
|
16
|
+
if (key in globalThis)
|
|
17
|
+
continue;
|
|
18
|
+
const desc = Object.getOwnPropertyDescriptor(window, key);
|
|
19
|
+
if (!desc || typeof desc.value !== "function")
|
|
20
|
+
continue;
|
|
21
|
+
try {
|
|
22
|
+
globalThis[key] = desc.value;
|
|
23
|
+
} catch {}
|
|
24
|
+
}
|
|
25
|
+
globalsRegistered = true;
|
|
26
|
+
}
|
|
27
|
+
function audit(html, options = {}) {
|
|
28
|
+
const config = {};
|
|
29
|
+
if (options.includeAAA)
|
|
30
|
+
config.includeAAA = true;
|
|
31
|
+
if (options.componentMode)
|
|
32
|
+
config.componentMode = true;
|
|
33
|
+
if (options.disabledRules?.length)
|
|
34
|
+
config.disabledRules = options.disabledRules;
|
|
35
|
+
configureRules(config);
|
|
36
|
+
const virtualConsole = new VirtualConsole;
|
|
37
|
+
const dom = new JSDOM(html, { pretendToBeVisual: true, virtualConsole });
|
|
38
|
+
ensureGlobals(dom.window);
|
|
39
|
+
const result = runAudit(dom.window.document);
|
|
40
|
+
result.violations = result.violations.map(({ element: _el, ...rest }) => rest);
|
|
41
|
+
dom.window.close();
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
isHTMLFragment,
|
|
46
|
+
audit
|
|
47
|
+
};
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
CHANGED
|
@@ -7745,6 +7745,10 @@ function Gn(e2) {
|
|
|
7745
7745
|
var jn = new Map(Ze.map((e2) => [e2.id, e2]));
|
|
7746
7746
|
|
|
7747
7747
|
// src/audit.ts
|
|
7748
|
+
function isHTMLFragment(html) {
|
|
7749
|
+
const prefix = html.slice(0, 1000);
|
|
7750
|
+
return !(/<!doctype\s/i.test(prefix) || /<html[\s>]/i.test(prefix));
|
|
7751
|
+
}
|
|
7748
7752
|
var globalsRegistered = false;
|
|
7749
7753
|
function ensureGlobals(window) {
|
|
7750
7754
|
if (globalsRegistered)
|
|
@@ -7774,7 +7778,7 @@ function audit(html, options = {}) {
|
|
|
7774
7778
|
const dom = new JSDOM2(html, { pretendToBeVisual: true, virtualConsole });
|
|
7775
7779
|
ensureGlobals(dom.window);
|
|
7776
7780
|
const result = Gn(dom.window.document);
|
|
7777
|
-
result.violations = result.violations.map(({ element, ...rest }) => rest);
|
|
7781
|
+
result.violations = result.violations.map(({ element: _el, ...rest }) => rest);
|
|
7778
7782
|
dom.window.close();
|
|
7779
7783
|
return result;
|
|
7780
7784
|
}
|
|
@@ -7852,11 +7856,6 @@ var main = defineCommand({
|
|
|
7852
7856
|
description: "Include AAA-level rules",
|
|
7853
7857
|
default: false
|
|
7854
7858
|
},
|
|
7855
|
-
"component-mode": {
|
|
7856
|
-
type: "boolean",
|
|
7857
|
-
description: "Exclude page-level rules",
|
|
7858
|
-
default: false
|
|
7859
|
-
},
|
|
7860
7859
|
disable: {
|
|
7861
7860
|
type: "string",
|
|
7862
7861
|
alias: "d",
|
|
@@ -7869,7 +7868,7 @@ var main = defineCommand({
|
|
|
7869
7868
|
const disabledRules = args.disable ? args.disable.split(",").map((s2) => s2.trim()) : undefined;
|
|
7870
7869
|
const result = audit(html, {
|
|
7871
7870
|
includeAAA: args["include-aaa"],
|
|
7872
|
-
componentMode:
|
|
7871
|
+
componentMode: isHTMLFragment(html),
|
|
7873
7872
|
disabledRules
|
|
7874
7873
|
});
|
|
7875
7874
|
console.log(format(result, args.format));
|
package/dist/format.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function inlineCSS(html: string, baseURL: string): Promise<string>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// src/inline-css.ts
|
|
2
|
+
import { JSDOM } from "jsdom";
|
|
3
|
+
async function fetchCSS(url) {
|
|
4
|
+
try {
|
|
5
|
+
const res = await fetch(url);
|
|
6
|
+
if (!res.ok) {
|
|
7
|
+
console.warn(`Warning: failed to fetch stylesheet ${url}: ${res.status}`);
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
return res.text();
|
|
11
|
+
} catch (err) {
|
|
12
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
13
|
+
console.warn(`Warning: failed to fetch stylesheet ${url}: ${msg}`);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function resolveImports(css, baseURL) {
|
|
18
|
+
const importPattern = /@import\s+(?:url\(\s*['"]?([^'")\s]+)['"]?\s*\)|['"]([^'"]+)['""])\s*([^;]*);/g;
|
|
19
|
+
const replacements = [];
|
|
20
|
+
for (const m of css.matchAll(importPattern)) {
|
|
21
|
+
const importURL = m[1] || m[2];
|
|
22
|
+
if (!importURL)
|
|
23
|
+
continue;
|
|
24
|
+
let resolved;
|
|
25
|
+
try {
|
|
26
|
+
resolved = new URL(importURL, baseURL).href;
|
|
27
|
+
} catch {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const imported = await fetchCSS(resolved);
|
|
31
|
+
if (imported !== null) {
|
|
32
|
+
const mediaQuery = m[3]?.trim();
|
|
33
|
+
const wrapped = mediaQuery ? `@media ${mediaQuery} {
|
|
34
|
+
${imported}
|
|
35
|
+
}` : imported;
|
|
36
|
+
replacements.push({ match: m[0], replacement: wrapped });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
let result = css;
|
|
40
|
+
for (const { match, replacement } of replacements) {
|
|
41
|
+
result = result.replace(match, replacement);
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
async function inlineCSS(html, baseURL) {
|
|
46
|
+
const dom = new JSDOM(html);
|
|
47
|
+
const doc = dom.window.document;
|
|
48
|
+
const links = doc.querySelectorAll('link[rel="stylesheet"][href]');
|
|
49
|
+
if (links.length === 0) {
|
|
50
|
+
dom.window.close();
|
|
51
|
+
return html;
|
|
52
|
+
}
|
|
53
|
+
const tasks = Array.from(links).map(async (link) => {
|
|
54
|
+
const href = link.getAttribute("href");
|
|
55
|
+
if (href.startsWith("data:"))
|
|
56
|
+
return;
|
|
57
|
+
let resolved;
|
|
58
|
+
try {
|
|
59
|
+
resolved = new URL(href, baseURL).href;
|
|
60
|
+
} catch {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const css = await fetchCSS(resolved);
|
|
64
|
+
if (css === null)
|
|
65
|
+
return;
|
|
66
|
+
const inlined = await resolveImports(css, resolved);
|
|
67
|
+
const style = doc.createElement("style");
|
|
68
|
+
style.textContent = inlined;
|
|
69
|
+
const media = link.getAttribute("media");
|
|
70
|
+
if (media)
|
|
71
|
+
style.setAttribute("media", media);
|
|
72
|
+
link.replaceWith(style);
|
|
73
|
+
});
|
|
74
|
+
await Promise.all(tasks);
|
|
75
|
+
const result = dom.serialize();
|
|
76
|
+
dom.window.close();
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
inlineCSS
|
|
81
|
+
};
|
package/dist/input.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveInput(source?: string): Promise<string>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@accesslint/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/AccessLint/cli"
|
|
@@ -10,11 +10,15 @@
|
|
|
10
10
|
"bin": {
|
|
11
11
|
"accesslint": "./dist/cli.js"
|
|
12
12
|
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./dist/audit.js",
|
|
15
|
+
"./inline-css": "./dist/inline-css.js"
|
|
16
|
+
},
|
|
13
17
|
"files": [
|
|
14
18
|
"dist"
|
|
15
19
|
],
|
|
16
20
|
"scripts": {
|
|
17
|
-
"build": "bun build src/cli.ts --target=node --outdir=dist --external jsdom",
|
|
21
|
+
"build": "bun build src/cli.ts --target=node --outdir=dist --external jsdom && bun build src/audit.ts src/inline-css.ts --target=node --outdir=dist --external jsdom --external @accesslint/core && tsc --emitDeclarationOnly",
|
|
18
22
|
"start": "bun src/cli.ts"
|
|
19
23
|
},
|
|
20
24
|
"dependencies": {
|
|
@@ -22,6 +26,8 @@
|
|
|
22
26
|
"jsdom": "^26.0.0"
|
|
23
27
|
},
|
|
24
28
|
"devDependencies": {
|
|
29
|
+
"@types/jsdom": "^28.0.0",
|
|
30
|
+
"@types/node": "^25.3.0",
|
|
25
31
|
"citty": "^0.1.6",
|
|
26
32
|
"typescript": "^5.7.0"
|
|
27
33
|
},
|