@reddoorla/maintenance 0.10.3 → 0.10.5
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/README.md +34 -16
- package/dist/cli/bin.js +127 -27
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.js +77 -12
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +111 -20
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -397,6 +397,32 @@ async function readSiteConfig(sitePath) {
|
|
|
397
397
|
return out;
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
+
// src/util/free-port.ts
|
|
401
|
+
import { createServer } from "net";
|
|
402
|
+
async function findFreePort() {
|
|
403
|
+
return new Promise((resolve, reject) => {
|
|
404
|
+
const server = createServer();
|
|
405
|
+
server.unref();
|
|
406
|
+
server.on("error", reject);
|
|
407
|
+
server.listen(0, "127.0.0.1", () => {
|
|
408
|
+
const addr = server.address();
|
|
409
|
+
if (typeof addr === "object" && addr) {
|
|
410
|
+
const port = addr.port;
|
|
411
|
+
server.close(() => resolve(port));
|
|
412
|
+
} else {
|
|
413
|
+
server.close();
|
|
414
|
+
reject(new Error("findFreePort: could not determine assigned port from socket"));
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
function withFreePort(url, port) {
|
|
420
|
+
const u = new URL(url);
|
|
421
|
+
u.hostname = "localhost";
|
|
422
|
+
u.port = String(port);
|
|
423
|
+
return u.toString();
|
|
424
|
+
}
|
|
425
|
+
|
|
400
426
|
// src/audits/lighthouse.ts
|
|
401
427
|
async function readJsonMaybe(path) {
|
|
402
428
|
try {
|
|
@@ -437,13 +463,19 @@ async function lighthouseAudit(ctx) {
|
|
|
437
463
|
const site = ctx.site;
|
|
438
464
|
const label = siteLabel(site);
|
|
439
465
|
const siteCfg = await readSiteConfig(site.path);
|
|
440
|
-
const
|
|
466
|
+
const port = await findFreePort();
|
|
467
|
+
const baseUrl = siteCfg.lighthouseUrl ?? lighthouseConfig.ci.collect.url[0];
|
|
468
|
+
const resolvedConfig = {
|
|
441
469
|
...lighthouseConfig,
|
|
442
470
|
ci: {
|
|
443
471
|
...lighthouseConfig.ci,
|
|
444
|
-
collect: {
|
|
472
|
+
collect: {
|
|
473
|
+
...lighthouseConfig.ci.collect,
|
|
474
|
+
url: [withFreePort(baseUrl, port)],
|
|
475
|
+
startServerCommand: `npm run vite:dev -- --port ${port} --strictPort`
|
|
476
|
+
}
|
|
445
477
|
}
|
|
446
|
-
}
|
|
478
|
+
};
|
|
447
479
|
const configDir = await mkdtemp(join4(tmpdir(), "reddoor-lhci-"));
|
|
448
480
|
const configPath = join4(configDir, "lighthouserc.json");
|
|
449
481
|
await writeFile(configPath, JSON.stringify(resolvedConfig), "utf-8");
|
|
@@ -554,6 +586,32 @@ async function readJsonMaybe2(path) {
|
|
|
554
586
|
return null;
|
|
555
587
|
}
|
|
556
588
|
}
|
|
589
|
+
function buildPlaywrightConfig(port) {
|
|
590
|
+
return `import { defineConfig } from "@playwright/test";
|
|
591
|
+
|
|
592
|
+
export default defineConfig({
|
|
593
|
+
testDir: ".",
|
|
594
|
+
testMatch: /.*\\.spec\\.ts$/,
|
|
595
|
+
fullyParallel: true,
|
|
596
|
+
forbidOnly: !!process.env.CI,
|
|
597
|
+
retries: process.env.CI ? 2 : 0,
|
|
598
|
+
reporter: process.env.CI ? "github" : "list",
|
|
599
|
+
use: {
|
|
600
|
+
baseURL: "http://localhost:${port}",
|
|
601
|
+
trace: "on-first-retry",
|
|
602
|
+
},
|
|
603
|
+
webServer: {
|
|
604
|
+
// --strictPort: refuse to bump to a different port if ours is taken,
|
|
605
|
+
// so the audit fails loudly instead of probing a zombie.
|
|
606
|
+
// reuseExistingServer:false: never reuse \u2014 we control the lifecycle.
|
|
607
|
+
command: "npm run vite:dev -- --port ${port} --strictPort",
|
|
608
|
+
url: "http://localhost:${port}/dev/a11y-fixtures",
|
|
609
|
+
reuseExistingServer: false,
|
|
610
|
+
timeout: 120_000,
|
|
611
|
+
},
|
|
612
|
+
});
|
|
613
|
+
`;
|
|
614
|
+
}
|
|
557
615
|
function buildSpec() {
|
|
558
616
|
return `import { test, expect } from "@playwright/test";
|
|
559
617
|
import AxeBuilder from "@axe-core/playwright";
|
|
@@ -607,19 +665,26 @@ async function a11yAudit(ctx) {
|
|
|
607
665
|
const specDir = await mkdtemp2(join5(tmpdir2(), "reddoor-a11y-spec-"));
|
|
608
666
|
const specPath = join5(specDir, "a11y.spec.ts");
|
|
609
667
|
await writeFile2(specPath, buildSpec(), "utf-8");
|
|
668
|
+
const port = await findFreePort();
|
|
669
|
+
const configPath = join5(specDir, "playwright.config.ts");
|
|
670
|
+
await writeFile2(configPath, buildPlaywrightConfig(port), "utf-8");
|
|
610
671
|
const resultsPath = join5(site.path, RESULTS_REL);
|
|
611
672
|
await rm2(join5(site.path, ".reddoor-a11y"), { recursive: true, force: true });
|
|
612
673
|
let raw;
|
|
613
674
|
try {
|
|
614
|
-
raw = await spawn2(
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
675
|
+
raw = await spawn2(
|
|
676
|
+
"npx",
|
|
677
|
+
["--yes", "playwright", "test", `--config=${configPath}`, "--reporter=line", specPath],
|
|
678
|
+
{
|
|
679
|
+
cwd: site.path,
|
|
680
|
+
env: { ...process.env, REDDOOR_A11Y_OUTPUT: resultsPath },
|
|
681
|
+
// playwright on a cold tree downloads Chrome, boots the site's dev
|
|
682
|
+
// server, and runs axe over every configured route. The shared 30 s
|
|
683
|
+
// default in runAudits is fine for deps/lint/security but starves
|
|
684
|
+
// playwright (mirrors the lighthouse fix shipped earlier).
|
|
685
|
+
timeoutMs: 5 * 6e4
|
|
686
|
+
}
|
|
687
|
+
);
|
|
623
688
|
} catch (err) {
|
|
624
689
|
await rm2(specDir, { recursive: true, force: true });
|
|
625
690
|
const e = err;
|
|
@@ -1521,6 +1586,20 @@ function findMatchingClose(source, openIdx) {
|
|
|
1521
1586
|
i = closeStr + 1;
|
|
1522
1587
|
continue;
|
|
1523
1588
|
}
|
|
1589
|
+
if (ch === "/") {
|
|
1590
|
+
const next = source[i + 1];
|
|
1591
|
+
if (next === "/") {
|
|
1592
|
+
const eol = source.indexOf("\n", i + 2);
|
|
1593
|
+
i = eol === -1 ? source.length : eol;
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
if (next === "*") {
|
|
1597
|
+
const end = source.indexOf("*/", i + 2);
|
|
1598
|
+
if (end === -1) return -1;
|
|
1599
|
+
i = end + 2;
|
|
1600
|
+
continue;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1524
1603
|
if (ch === "{") depth++;
|
|
1525
1604
|
else if (ch === "}") {
|
|
1526
1605
|
depth--;
|
|
@@ -1809,15 +1888,25 @@ import { stat as stat3 } from "fs/promises";
|
|
|
1809
1888
|
import { join as join17 } from "path";
|
|
1810
1889
|
|
|
1811
1890
|
// src/util/self-version.ts
|
|
1812
|
-
import { readFileSync } from "fs";
|
|
1891
|
+
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
1813
1892
|
import { fileURLToPath } from "url";
|
|
1814
1893
|
import { dirname, join as join16 } from "path";
|
|
1815
1894
|
function selfPackageVersion(callerImportMetaUrl) {
|
|
1816
1895
|
try {
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1896
|
+
let dir = dirname(fileURLToPath(callerImportMetaUrl));
|
|
1897
|
+
while (true) {
|
|
1898
|
+
const candidate = join16(dir, "package.json");
|
|
1899
|
+
if (existsSync2(candidate)) {
|
|
1900
|
+
const raw = readFileSync(candidate, "utf-8");
|
|
1901
|
+
const pkg = JSON.parse(raw);
|
|
1902
|
+
if (pkg.name === "@reddoorla/maintenance") {
|
|
1903
|
+
return pkg.version ?? "0.0.0";
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
const parent = dirname(dir);
|
|
1907
|
+
if (parent === dir) return "0.0.0";
|
|
1908
|
+
dir = parent;
|
|
1909
|
+
}
|
|
1821
1910
|
} catch {
|
|
1822
1911
|
return "0.0.0";
|
|
1823
1912
|
}
|
|
@@ -2152,7 +2241,7 @@ import mjml2html from "mjml";
|
|
|
2152
2241
|
|
|
2153
2242
|
// src/reports/maintenance-email/assets/index.ts
|
|
2154
2243
|
import { readFile as readFile11 } from "fs/promises";
|
|
2155
|
-
import { existsSync as
|
|
2244
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2156
2245
|
import { dirname as dirname3, join as join19 } from "path";
|
|
2157
2246
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2158
2247
|
var CHECK_CID = "rd-check-png";
|
|
@@ -2163,12 +2252,12 @@ function resolveAssetsDir() {
|
|
|
2163
2252
|
let dir = dirname3(fileURLToPath2(import.meta.url));
|
|
2164
2253
|
while (true) {
|
|
2165
2254
|
const srcCandidate = join19(dir, "src", "reports", "maintenance-email", "assets", "check.png");
|
|
2166
|
-
if (
|
|
2255
|
+
if (existsSync3(srcCandidate)) {
|
|
2167
2256
|
cachedAssetsDir = dirname3(srcCandidate);
|
|
2168
2257
|
return cachedAssetsDir;
|
|
2169
2258
|
}
|
|
2170
2259
|
const distCandidate = join19(dir, "dist", "reports", "maintenance-email", "assets", "check.png");
|
|
2171
|
-
if (
|
|
2260
|
+
if (existsSync3(distCandidate)) {
|
|
2172
2261
|
cachedAssetsDir = dirname3(distCandidate);
|
|
2173
2262
|
return cachedAssetsDir;
|
|
2174
2263
|
}
|
|
@@ -2839,6 +2928,8 @@ export {
|
|
|
2839
2928
|
runAudits,
|
|
2840
2929
|
runAuditsAcross,
|
|
2841
2930
|
securityAudit,
|
|
2931
|
+
selfCaretRange,
|
|
2932
|
+
selfPackageVersion,
|
|
2842
2933
|
sendApprovedReports,
|
|
2843
2934
|
svelteCodemods,
|
|
2844
2935
|
syncConfigs,
|