everywhere-qa 0.2.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/LICENSE +21 -0
- package/README.md +12 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +121 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.js +120 -0
- package/dist/config.js.map +1 -0
- package/dist/findings.d.ts +18 -0
- package/dist/findings.js +36 -0
- package/dist/findings.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/pseudo.d.ts +1 -0
- package/dist/pseudo.js +21 -0
- package/dist/pseudo.js.map +1 -0
- package/dist/report.d.ts +8 -0
- package/dist/report.js +176 -0
- package/dist/report.js.map +1 -0
- package/dist/runner.d.ts +2 -0
- package/dist/runner.js +289 -0
- package/dist/runner.js.map +1 -0
- package/dist/scoring.d.ts +8 -0
- package/dist/scoring.js +73 -0
- package/dist/scoring.js.map +1 -0
- package/dist/source-scan.d.ts +2 -0
- package/dist/source-scan.js +63 -0
- package/dist/source-scan.js.map +1 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Everywhere QA Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# everywhere-qa
|
|
2
|
+
|
|
3
|
+
The public CLI for [Everywhere QA](https://github.com/GuduruBharath-hub/EverywhereQA): deterministic accessibility, RTL, text-expansion, locale, and constrained-network audits with verified before/after Global Passports.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npx --yes everywhere-qa@0.2.0 setup
|
|
7
|
+
npx --yes everywhere-qa@0.2.0 audit --url https://example.com --out artifacts/everywhere-qa
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
See the repository README for configuration, Codex plugin installation, supported platforms, scoring, limitations, and the audit-fix-verify workflow.
|
|
11
|
+
|
|
12
|
+
MIT licensed. Automated evidence is not certification, legal advice, or a translation-quality assessment.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { chromium } from "playwright";
|
|
7
|
+
import { readAuditConfig, resolveAuditConfig } from "./config.js";
|
|
8
|
+
import { runAudit } from "./runner.js";
|
|
9
|
+
import { readReport } from "./report.js";
|
|
10
|
+
function usage() {
|
|
11
|
+
return `Everywhere QA — Fix once. Work everywhere.
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
everywhere setup
|
|
15
|
+
everywhere audit --url <url> [--config <file>] [--repo <path>] [--out <directory>] [--timeout <ms>]
|
|
16
|
+
everywhere verify --baseline <report.json> --url <url> [--config <file>] [--repo <path>] [--out <directory>] [--timeout <ms>] [--gate <off|regression>]
|
|
17
|
+
|
|
18
|
+
Audit is read-only for the target repository. Output defaults to ./artifacts/everywhere-qa.`;
|
|
19
|
+
}
|
|
20
|
+
function parse(argv) {
|
|
21
|
+
const command = argv[0];
|
|
22
|
+
if (command !== "setup" && command !== "audit" && command !== "verify")
|
|
23
|
+
throw new Error(usage());
|
|
24
|
+
const flags = new Map();
|
|
25
|
+
for (let index = 1; index < argv.length; index += 1) {
|
|
26
|
+
const token = argv[index];
|
|
27
|
+
if (!token?.startsWith("--"))
|
|
28
|
+
throw new Error(`Unexpected argument: ${token ?? ""}\n\n${usage()}`);
|
|
29
|
+
const value = argv[index + 1];
|
|
30
|
+
if (!value || value.startsWith("--"))
|
|
31
|
+
throw new Error(`Missing value for ${token}`);
|
|
32
|
+
flags.set(token.slice(2), value);
|
|
33
|
+
index += 1;
|
|
34
|
+
}
|
|
35
|
+
return { command, flags };
|
|
36
|
+
}
|
|
37
|
+
async function setup() {
|
|
38
|
+
const executable = chromium.executablePath();
|
|
39
|
+
try {
|
|
40
|
+
await access(executable);
|
|
41
|
+
process.stdout.write(`Chromium is already installed at ${executable}\n`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
process.stdout.write("Installing the Playwright Chromium browser…\n");
|
|
46
|
+
}
|
|
47
|
+
const require = createRequire(import.meta.url);
|
|
48
|
+
const cli = join(dirname(require.resolve("playwright/package.json")), "cli.js");
|
|
49
|
+
const code = await new Promise((resolveCode, reject) => {
|
|
50
|
+
const child = spawn(process.execPath, [cli, "install", "chromium"], { stdio: "inherit", windowsHide: true });
|
|
51
|
+
child.on("error", reject);
|
|
52
|
+
child.on("exit", (exitCode) => resolveCode(exitCode ?? 1));
|
|
53
|
+
});
|
|
54
|
+
if (code !== 0)
|
|
55
|
+
throw new Error(`Chromium installation exited with code ${code}.`);
|
|
56
|
+
process.stdout.write("Chromium setup complete.\n");
|
|
57
|
+
}
|
|
58
|
+
async function main() {
|
|
59
|
+
const { command, flags } = parse(process.argv.slice(2));
|
|
60
|
+
if (command === "setup") {
|
|
61
|
+
if (flags.size)
|
|
62
|
+
throw new Error(`setup does not accept flags.\n\n${usage()}`);
|
|
63
|
+
await setup();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const url = flags.get("url");
|
|
67
|
+
if (!url)
|
|
68
|
+
throw new Error("--url is required.\n\n" + usage());
|
|
69
|
+
let parsedUrl;
|
|
70
|
+
try {
|
|
71
|
+
parsedUrl = new URL(url);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
throw new Error(`--url must be an absolute http(s) URL: ${url}`);
|
|
75
|
+
}
|
|
76
|
+
if (!/^https?:$/.test(parsedUrl.protocol))
|
|
77
|
+
throw new Error("Only http and https URLs are supported.");
|
|
78
|
+
const timeout = flags.get("timeout") ? Number(flags.get("timeout")) : 30_000;
|
|
79
|
+
if (!Number.isFinite(timeout) || timeout < 1_000)
|
|
80
|
+
throw new Error("--timeout must be a number of at least 1000 milliseconds.");
|
|
81
|
+
const outDir = resolve(flags.get("out") ?? "artifacts/everywhere-qa");
|
|
82
|
+
const baselinePath = flags.get("baseline") ? resolve(flags.get("baseline")) : undefined;
|
|
83
|
+
if (command === "verify" && !baselinePath)
|
|
84
|
+
throw new Error("verify requires --baseline <report.json>.");
|
|
85
|
+
if (command === "audit" && baselinePath)
|
|
86
|
+
throw new Error("--baseline is only valid with verify.");
|
|
87
|
+
const gate = flags.get("gate") ?? "off";
|
|
88
|
+
if (gate !== "off" && gate !== "regression")
|
|
89
|
+
throw new Error("--gate must be off or regression.");
|
|
90
|
+
if (command === "audit" && gate !== "off")
|
|
91
|
+
throw new Error("--gate is only valid with verify.");
|
|
92
|
+
const configPath = flags.get("config") ? resolve(flags.get("config")) : undefined;
|
|
93
|
+
const configFile = configPath ? await readAuditConfig(configPath) : undefined;
|
|
94
|
+
const config = resolveAuditConfig(url, configFile);
|
|
95
|
+
const baseline = baselinePath ? await readReport(baselinePath) : undefined;
|
|
96
|
+
process.stdout.write(`\nAuditing ${config.pages.length} page${config.pages.length === 1 ? "" : "s"} from ${url}\n`);
|
|
97
|
+
const report = await runAudit({
|
|
98
|
+
url,
|
|
99
|
+
outDir,
|
|
100
|
+
timeoutMs: timeout,
|
|
101
|
+
config,
|
|
102
|
+
gatePolicy: gate,
|
|
103
|
+
...(flags.get("repo") ? { repo: resolve(flags.get("repo")) } : {}),
|
|
104
|
+
...(baseline ? { baseline, baselineDir: dirname(baselinePath) } : {})
|
|
105
|
+
});
|
|
106
|
+
process.stdout.write(`\nGlobal Passport ${report.runId}\n`);
|
|
107
|
+
process.stdout.write(`Score: ${report.scores.overall}/100 · Findings: ${report.findings.length} · Advisories: ${report.advisories.length}\n`);
|
|
108
|
+
if (report.verification) {
|
|
109
|
+
process.stdout.write(`Verified: ${report.verification.fixed.length} fixed, ${report.verification.introduced.length} introduced, ${report.verification.scoreChange >= 0 ? "+" : ""}${report.verification.scoreChange} points\n`);
|
|
110
|
+
if (report.verification.gate.policy !== "off")
|
|
111
|
+
process.stdout.write(`Regression gate: ${report.verification.gate.status}\n`);
|
|
112
|
+
}
|
|
113
|
+
process.stdout.write(`Report: ${resolve(outDir, "report.html")}\n\n`);
|
|
114
|
+
if (report.verification?.gate.status === "failed")
|
|
115
|
+
process.exitCode = 2;
|
|
116
|
+
}
|
|
117
|
+
main().catch((error) => {
|
|
118
|
+
process.stderr.write(`\nEverywhere QA failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
119
|
+
process.exitCode = 1;
|
|
120
|
+
});
|
|
121
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC,SAAS,KAAK;IACZ,OAAO;;;;;;;4FAOmF,CAAC;AAC7F,CAAC;AAED,SAAS,KAAK,CAAC,IAAc;IAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IACjG,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,IAAI,EAAE,OAAO,KAAK,EAAE,EAAE,CAAC,CAAC;QACnG,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,KAAK,EAAE,CAAC,CAAC;QACpF,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACjC,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,KAAK,UAAU,KAAK;IAClB,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,UAAU,IAAI,CAAC,CAAC;QACzE,OAAO;IACT,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAChF,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE;QAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7G,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IACH,IAAI,IAAI,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,IAAI,GAAG,CAAC,CAAC;IACnF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,IAAI,KAAK,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC9E,MAAM,KAAK,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,KAAK,EAAE,CAAC,CAAC;IAC9D,IAAI,SAAc,CAAC;IACnB,IAAI,CAAC;QAAC,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,IAAI,KAAK,CAAC,0CAA0C,GAAG,EAAE,CAAC,CAAC;IAAC,CAAC;IAC7G,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACtG,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/H,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,yBAAyB,CAAC,CAAC;IACtE,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzF,IAAI,OAAO,KAAK,QAAQ,IAAI,CAAC,YAAY;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IACxG,IAAI,OAAO,KAAK,OAAO,IAAI,YAAY;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAClG,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;IACxC,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,YAAY;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAClG,IAAI,OAAO,KAAK,OAAO,IAAI,IAAI,KAAK,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAChG,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACnF,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9E,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,MAAM,CAAC,KAAK,CAAC,MAAM,QAAQ,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC;IACpH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC;QAC5B,GAAG;QACH,MAAM;QACN,SAAS,EAAE,OAAO;QAClB,MAAM;QACN,UAAU,EAAE,IAAkB;QAC9B,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,YAAa,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvE,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;IAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,MAAM,CAAC,MAAM,CAAC,OAAO,oBAAoB,MAAM,CAAC,QAAQ,CAAC,MAAM,kBAAkB,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC;IAC9I,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,WAAW,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,gBAAgB,MAAM,CAAC,YAAY,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC,WAAW,WAAW,CAAC,CAAC;QAChO,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,KAAK,KAAK;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IAC/H,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,OAAO,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtE,IAAI,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AAC1E,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5G,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AuditProfiles, ResolvedAuditConfig, Viewport } from "./types.js";
|
|
2
|
+
export interface AuditConfigFile {
|
|
3
|
+
routes?: Array<{
|
|
4
|
+
id: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}>;
|
|
7
|
+
profiles?: {
|
|
8
|
+
accessibility?: {
|
|
9
|
+
locale?: string;
|
|
10
|
+
viewport?: Partial<Viewport>;
|
|
11
|
+
};
|
|
12
|
+
rtl?: {
|
|
13
|
+
locale?: string;
|
|
14
|
+
timezoneId?: string;
|
|
15
|
+
viewport?: Partial<Viewport>;
|
|
16
|
+
};
|
|
17
|
+
textExpansion?: {
|
|
18
|
+
locale?: string;
|
|
19
|
+
viewport?: Partial<Viewport>;
|
|
20
|
+
ratio?: number;
|
|
21
|
+
};
|
|
22
|
+
resilience?: {
|
|
23
|
+
locale?: string;
|
|
24
|
+
timezoneId?: string;
|
|
25
|
+
viewport?: Partial<Viewport>;
|
|
26
|
+
network?: {
|
|
27
|
+
latencyMs?: number;
|
|
28
|
+
downloadKbps?: number;
|
|
29
|
+
uploadKbps?: number;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export declare const DEFAULT_PROFILES: AuditProfiles;
|
|
35
|
+
export declare function readAuditConfig(path: string): Promise<AuditConfigFile>;
|
|
36
|
+
export declare function resolveAuditConfig(baseUrl: string, raw?: AuditConfigFile): ResolvedAuditConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
export const DEFAULT_PROFILES = {
|
|
4
|
+
accessibility: { locale: "en-US", viewport: { width: 1440, height: 900 } },
|
|
5
|
+
rtl: { locale: "ar-SA", timezoneId: "Asia/Riyadh", viewport: { width: 390, height: 844 } },
|
|
6
|
+
textExpansion: { locale: "en-XA", viewport: { width: 390, height: 844 }, ratio: 0.4 },
|
|
7
|
+
resilience: {
|
|
8
|
+
locale: "hi-IN",
|
|
9
|
+
timezoneId: "Asia/Kolkata",
|
|
10
|
+
viewport: { width: 390, height: 844 },
|
|
11
|
+
network: { latencyMs: 250, downloadKbps: 768, uploadKbps: 384 }
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function object(value, label) {
|
|
15
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
16
|
+
throw new Error(`${label} must be an object.`);
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function optionalString(value, fallback, label) {
|
|
20
|
+
if (value === undefined)
|
|
21
|
+
return fallback;
|
|
22
|
+
if (typeof value !== "string" || !value.trim())
|
|
23
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function boundedNumber(value, fallback, label, minimum, maximum) {
|
|
27
|
+
if (value === undefined)
|
|
28
|
+
return fallback;
|
|
29
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < minimum || value > maximum) {
|
|
30
|
+
throw new Error(`${label} must be between ${minimum} and ${maximum}.`);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
function viewport(value, fallback, label) {
|
|
35
|
+
if (value === undefined)
|
|
36
|
+
return { ...fallback };
|
|
37
|
+
const parsed = object(value, label);
|
|
38
|
+
return {
|
|
39
|
+
width: boundedNumber(parsed.width, fallback.width, `${label}.width`, 240, 3840),
|
|
40
|
+
height: boundedNumber(parsed.height, fallback.height, `${label}.height`, 240, 3840)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function resolveProfiles(value) {
|
|
44
|
+
if (value === undefined)
|
|
45
|
+
return structuredClone(DEFAULT_PROFILES);
|
|
46
|
+
const profiles = object(value, "profiles");
|
|
47
|
+
const access = profiles.accessibility === undefined ? {} : object(profiles.accessibility, "profiles.accessibility");
|
|
48
|
+
const rtl = profiles.rtl === undefined ? {} : object(profiles.rtl, "profiles.rtl");
|
|
49
|
+
const expansion = profiles.textExpansion === undefined ? {} : object(profiles.textExpansion, "profiles.textExpansion");
|
|
50
|
+
const resilience = profiles.resilience === undefined ? {} : object(profiles.resilience, "profiles.resilience");
|
|
51
|
+
const network = resilience.network === undefined ? {} : object(resilience.network, "profiles.resilience.network");
|
|
52
|
+
return {
|
|
53
|
+
accessibility: {
|
|
54
|
+
locale: optionalString(access.locale, DEFAULT_PROFILES.accessibility.locale, "profiles.accessibility.locale"),
|
|
55
|
+
viewport: viewport(access.viewport, DEFAULT_PROFILES.accessibility.viewport, "profiles.accessibility.viewport")
|
|
56
|
+
},
|
|
57
|
+
rtl: {
|
|
58
|
+
locale: optionalString(rtl.locale, DEFAULT_PROFILES.rtl.locale, "profiles.rtl.locale"),
|
|
59
|
+
timezoneId: optionalString(rtl.timezoneId, DEFAULT_PROFILES.rtl.timezoneId, "profiles.rtl.timezoneId"),
|
|
60
|
+
viewport: viewport(rtl.viewport, DEFAULT_PROFILES.rtl.viewport, "profiles.rtl.viewport")
|
|
61
|
+
},
|
|
62
|
+
textExpansion: {
|
|
63
|
+
locale: optionalString(expansion.locale, DEFAULT_PROFILES.textExpansion.locale, "profiles.textExpansion.locale"),
|
|
64
|
+
viewport: viewport(expansion.viewport, DEFAULT_PROFILES.textExpansion.viewport, "profiles.textExpansion.viewport"),
|
|
65
|
+
ratio: boundedNumber(expansion.ratio, DEFAULT_PROFILES.textExpansion.ratio, "profiles.textExpansion.ratio", 0.1, 1)
|
|
66
|
+
},
|
|
67
|
+
resilience: {
|
|
68
|
+
locale: optionalString(resilience.locale, DEFAULT_PROFILES.resilience.locale, "profiles.resilience.locale"),
|
|
69
|
+
timezoneId: optionalString(resilience.timezoneId, DEFAULT_PROFILES.resilience.timezoneId, "profiles.resilience.timezoneId"),
|
|
70
|
+
viewport: viewport(resilience.viewport, DEFAULT_PROFILES.resilience.viewport, "profiles.resilience.viewport"),
|
|
71
|
+
network: {
|
|
72
|
+
latencyMs: boundedNumber(network.latencyMs, DEFAULT_PROFILES.resilience.network.latencyMs, "profiles.resilience.network.latencyMs", 0, 60_000),
|
|
73
|
+
downloadKbps: boundedNumber(network.downloadKbps, DEFAULT_PROFILES.resilience.network.downloadKbps, "profiles.resilience.network.downloadKbps", 1, 1_000_000),
|
|
74
|
+
uploadKbps: boundedNumber(network.uploadKbps, DEFAULT_PROFILES.resilience.network.uploadKbps, "profiles.resilience.network.uploadKbps", 1, 1_000_000)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export async function readAuditConfig(path) {
|
|
80
|
+
try {
|
|
81
|
+
const value = JSON.parse(await readFile(path, "utf8"));
|
|
82
|
+
return object(value, "Everywhere QA config");
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error instanceof SyntaxError)
|
|
86
|
+
throw new Error(`Config at ${path} is not valid JSON: ${error.message}`);
|
|
87
|
+
if (error instanceof Error && error.message.startsWith("Everywhere QA config"))
|
|
88
|
+
throw error;
|
|
89
|
+
throw new Error(`Unable to read config at ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export function resolveAuditConfig(baseUrl, raw) {
|
|
93
|
+
const base = new URL(baseUrl);
|
|
94
|
+
const configuredRoutes = raw?.routes;
|
|
95
|
+
if (configuredRoutes !== undefined && !Array.isArray(configuredRoutes))
|
|
96
|
+
throw new Error("routes must be an array.");
|
|
97
|
+
if (configuredRoutes && (configuredRoutes.length < 1 || configuredRoutes.length > 10))
|
|
98
|
+
throw new Error("routes must contain between 1 and 10 entries.");
|
|
99
|
+
const seen = new Set();
|
|
100
|
+
const pages = configuredRoutes?.map((route, index) => {
|
|
101
|
+
const value = object(route, `routes[${index}]`);
|
|
102
|
+
const id = optionalString(value.id, "", `routes[${index}].id`);
|
|
103
|
+
const path = optionalString(value.path, "", `routes[${index}].path`);
|
|
104
|
+
if (!/^[a-z0-9][a-z0-9-]{0,39}$/.test(id))
|
|
105
|
+
throw new Error(`routes[${index}].id must use lowercase letters, numbers, and hyphens.`);
|
|
106
|
+
if (seen.has(id))
|
|
107
|
+
throw new Error(`Route id "${id}" is duplicated.`);
|
|
108
|
+
seen.add(id);
|
|
109
|
+
if (!path.startsWith("/") || path.startsWith("//"))
|
|
110
|
+
throw new Error(`routes[${index}].path must be a same-origin path beginning with one slash.`);
|
|
111
|
+
const url = new URL(path, base);
|
|
112
|
+
if (url.origin !== base.origin)
|
|
113
|
+
throw new Error(`routes[${index}].path must stay on ${base.origin}.`);
|
|
114
|
+
return { id, url: url.href };
|
|
115
|
+
}) ?? [{ id: "target", url: base.href }];
|
|
116
|
+
const profiles = resolveProfiles(raw?.profiles);
|
|
117
|
+
const profileSignature = createHash("sha256").update(JSON.stringify(profiles)).digest("hex").slice(0, 16);
|
|
118
|
+
return { pages, profiles, profileSignature, isDefault: raw === undefined };
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Confidence, Finding, Pillar, Severity } from "./types.js";
|
|
2
|
+
export interface FindingInput {
|
|
3
|
+
ruleId: string;
|
|
4
|
+
pillar: Pillar;
|
|
5
|
+
severity: Severity;
|
|
6
|
+
scenario: string;
|
|
7
|
+
pageId?: string;
|
|
8
|
+
pageUrl?: string;
|
|
9
|
+
selector?: string;
|
|
10
|
+
message: string;
|
|
11
|
+
evidence: string;
|
|
12
|
+
confidence?: Confidence;
|
|
13
|
+
remediation: string;
|
|
14
|
+
helpUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function finding(input: FindingInput): Finding;
|
|
17
|
+
export declare function dedupeFindings(findings: Finding[]): Finding[];
|
|
18
|
+
export declare function stableSignature(item: Finding): string;
|
package/dist/findings.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export function finding(input) {
|
|
3
|
+
const selector = input.selector ?? "document";
|
|
4
|
+
const signature = [input.pageId ?? "global", input.ruleId, input.scenario, selector, input.message].join("|");
|
|
5
|
+
const id = createHash("sha1").update(signature).digest("hex").slice(0, 12);
|
|
6
|
+
return {
|
|
7
|
+
id,
|
|
8
|
+
ruleId: input.ruleId,
|
|
9
|
+
pillar: input.pillar,
|
|
10
|
+
severity: input.severity,
|
|
11
|
+
scenario: input.scenario,
|
|
12
|
+
...(input.pageId ? { pageId: input.pageId } : {}),
|
|
13
|
+
...(input.pageUrl ? { pageUrl: input.pageUrl } : {}),
|
|
14
|
+
selector,
|
|
15
|
+
message: input.message,
|
|
16
|
+
evidence: input.evidence,
|
|
17
|
+
confidence: input.confidence ?? "deterministic",
|
|
18
|
+
remediation: input.remediation,
|
|
19
|
+
...(input.helpUrl ? { helpUrl: input.helpUrl } : {})
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function dedupeFindings(findings) {
|
|
23
|
+
const byId = new Map();
|
|
24
|
+
for (const item of findings) {
|
|
25
|
+
if (!byId.has(item.id))
|
|
26
|
+
byId.set(item.id, item);
|
|
27
|
+
}
|
|
28
|
+
return [...byId.values()].sort((a, b) => {
|
|
29
|
+
const rank = { critical: 0, serious: 1, moderate: 2, minor: 3 };
|
|
30
|
+
return rank[a.severity] - rank[b.severity] || a.ruleId.localeCompare(b.ruleId);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export function stableSignature(item) {
|
|
34
|
+
return [item.pageId ?? "target", item.ruleId, item.scenario, item.selector].join("|");
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.js","sourceRoot":"","sources":["../src/findings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkBzC,MAAM,UAAU,OAAO,CAAC,KAAmB;IACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,UAAU,CAAC;IAC9C,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9G,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3E,OAAO;QACL,EAAE;QACF,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,QAAQ;QACR,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,eAAe;QAC/C,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAmB;IAChD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAmB,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACtC,MAAM,IAAI,GAA6B,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAC1F,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxF,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { runAudit } from "./runner.js";
|
|
2
|
+
export { calculateScores, calculatePageScores, compareReports, evaluateGate } from "./scoring.js";
|
|
3
|
+
export { dedupeFindings, finding, stableSignature } from "./findings.js";
|
|
4
|
+
export { pseudoLocalize } from "./pseudo.js";
|
|
5
|
+
export { DEFAULT_PROFILES, readAuditConfig, resolveAuditConfig } from "./config.js";
|
|
6
|
+
export type * from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { runAudit } from "./runner.js";
|
|
2
|
+
export { calculateScores, calculatePageScores, compareReports, evaluateGate } from "./scoring.js";
|
|
3
|
+
export { dedupeFindings, finding, stableSignature } from "./findings.js";
|
|
4
|
+
export { pseudoLocalize } from "./pseudo.js";
|
|
5
|
+
export { DEFAULT_PROFILES, readAuditConfig, resolveAuditConfig } from "./config.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/pseudo.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function pseudoLocalize(input: string, expansion?: number): string;
|
package/dist/pseudo.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const accented = {
|
|
2
|
+
a: "á", b: "ƀ", c: "ç", d: "đ", e: "é", f: "ƒ", g: "ğ", h: "ħ", i: "í", j: "ĵ",
|
|
3
|
+
k: "ķ", l: "ľ", m: "ɱ", n: "ñ", o: "ó", p: "þ", q: "ɋ", r: "ř", s: "š", t: "ŧ",
|
|
4
|
+
u: "ú", v: "ṽ", w: "ŵ", x: "ẋ", y: "ý", z: "ž"
|
|
5
|
+
};
|
|
6
|
+
export function pseudoLocalize(input, expansion = 0.4) {
|
|
7
|
+
if (!input.trim())
|
|
8
|
+
return input;
|
|
9
|
+
const transformed = [...input].map((char) => {
|
|
10
|
+
const lower = char.toLowerCase();
|
|
11
|
+
const replacement = accented[lower];
|
|
12
|
+
if (!replacement)
|
|
13
|
+
return char;
|
|
14
|
+
return char === lower ? replacement : replacement.toUpperCase();
|
|
15
|
+
}).join("");
|
|
16
|
+
const words = input.trim().split(/\s+/).filter(Boolean);
|
|
17
|
+
const padLength = Math.max(1, Math.ceil(input.length * expansion));
|
|
18
|
+
const pad = "~".repeat(padLength + Math.max(0, words.length - 1));
|
|
19
|
+
return `[${transformed} ${pad}]`;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=pseudo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pseudo.js","sourceRoot":"","sources":["../src/pseudo.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAA2B;IACvC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IAC9E,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;IAC9E,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG;CAC/C,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,SAAS,GAAG,GAAG;IAC3D,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAC9B,OAAO,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IAClE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,IAAI,WAAW,IAAI,GAAG,GAAG,CAAC;AACnC,CAAC"}
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AuditReport, ResolvedAuditConfig, ScenarioResult, VisualComparison } from "./types.js";
|
|
2
|
+
export declare function writeReport(report: AuditReport, outDir: string): Promise<{
|
|
3
|
+
jsonPath: string;
|
|
4
|
+
htmlPath: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function readReport(path: string): Promise<AuditReport>;
|
|
7
|
+
export declare function assertBaselineCompatible(baseline: AuditReport, config: ResolvedAuditConfig): void;
|
|
8
|
+
export declare function copyBaselineScreenshots(baseline: AuditReport, current: ScenarioResult[], baselineDir: string, outDir: string): Promise<VisualComparison[]>;
|