@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/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 resolvedConfig = siteCfg.lighthouseUrl ? {
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: { ...lighthouseConfig.ci.collect, url: [siteCfg.lighthouseUrl] }
472
+ collect: {
473
+ ...lighthouseConfig.ci.collect,
474
+ url: [withFreePort(baseUrl, port)],
475
+ startServerCommand: `npm run vite:dev -- --port ${port} --strictPort`
476
+ }
445
477
  }
446
- } : lighthouseConfig;
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("npx", ["--yes", "playwright", "test", "--reporter=line", specPath], {
615
- cwd: site.path,
616
- env: { ...process.env, REDDOOR_A11Y_OUTPUT: resultsPath },
617
- // playwright on a cold tree downloads Chrome, boots the site's dev
618
- // server, and runs axe over every configured route. The shared 30 s
619
- // default in runAudits is fine for deps/lint/security but starves
620
- // playwright (mirrors the lighthouse fix shipped earlier).
621
- timeoutMs: 5 * 6e4
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
- const here = dirname(fileURLToPath(callerImportMetaUrl));
1818
- const raw = readFileSync(join16(here, "..", "..", "package.json"), "utf-8");
1819
- const pkg = JSON.parse(raw);
1820
- return pkg.version ?? "0.0.0";
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 existsSync2 } from "fs";
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 (existsSync2(srcCandidate)) {
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 (existsSync2(distCandidate)) {
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,