@reddoorla/maintenance 0.14.0 → 0.16.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/cli/bin.js +255 -118
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.js +144 -50
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/index.js +37 -16
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/cli/bin.js
CHANGED
|
@@ -9,6 +9,54 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/util/credentials.ts
|
|
13
|
+
import { readFileSync } from "fs";
|
|
14
|
+
import { homedir } from "os";
|
|
15
|
+
import { join } from "path";
|
|
16
|
+
function defaultCredentialsPath() {
|
|
17
|
+
const base = process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
|
|
18
|
+
return join(base, "reddoor-maint", "credentials.env");
|
|
19
|
+
}
|
|
20
|
+
function parseEnvFile(contents) {
|
|
21
|
+
const out = {};
|
|
22
|
+
for (const rawLine of contents.split(/\r?\n/)) {
|
|
23
|
+
const line = rawLine.trim();
|
|
24
|
+
if (!line || line.startsWith("#")) continue;
|
|
25
|
+
const eq = line.indexOf("=");
|
|
26
|
+
if (eq <= 0) continue;
|
|
27
|
+
const key = line.slice(0, eq).trim();
|
|
28
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue;
|
|
29
|
+
let value = line.slice(eq + 1).trim();
|
|
30
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
31
|
+
value = value.slice(1, -1);
|
|
32
|
+
}
|
|
33
|
+
out[key] = value;
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
function loadCredentialsIntoEnv(path = defaultCredentialsPath()) {
|
|
38
|
+
let contents;
|
|
39
|
+
try {
|
|
40
|
+
contents = readFileSync(path, "utf-8");
|
|
41
|
+
} catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const parsed = parseEnvFile(contents);
|
|
45
|
+
const applied = [];
|
|
46
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
47
|
+
if (process.env[k] === void 0) {
|
|
48
|
+
process.env[k] = v;
|
|
49
|
+
applied.push(k);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return applied;
|
|
53
|
+
}
|
|
54
|
+
var init_credentials = __esm({
|
|
55
|
+
"src/util/credentials.ts"() {
|
|
56
|
+
"use strict";
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
12
60
|
// src/reports/airtable/client.ts
|
|
13
61
|
var client_exports = {};
|
|
14
62
|
__export(client_exports, {
|
|
@@ -16,11 +64,19 @@ __export(client_exports, {
|
|
|
16
64
|
readAirtableConfig: () => readAirtableConfig
|
|
17
65
|
});
|
|
18
66
|
import Airtable from "airtable";
|
|
67
|
+
function missing(name) {
|
|
68
|
+
return Object.assign(
|
|
69
|
+
new Error(
|
|
70
|
+
`${name} not set. Export it in your shell or put it in ${defaultCredentialsPath()} as ${name}=...`
|
|
71
|
+
),
|
|
72
|
+
{ exitCode: 2 }
|
|
73
|
+
);
|
|
74
|
+
}
|
|
19
75
|
function readAirtableConfig() {
|
|
20
76
|
const apiKey = process.env.AIRTABLE_PAT;
|
|
21
77
|
const baseId = process.env.AIRTABLE_BASE_ID;
|
|
22
|
-
if (!apiKey) throw
|
|
23
|
-
if (!baseId) throw
|
|
78
|
+
if (!apiKey) throw missing("AIRTABLE_PAT");
|
|
79
|
+
if (!baseId) throw missing("AIRTABLE_BASE_ID");
|
|
24
80
|
return { apiKey, baseId };
|
|
25
81
|
}
|
|
26
82
|
function openBase(cfg) {
|
|
@@ -29,6 +85,7 @@ function openBase(cfg) {
|
|
|
29
85
|
var init_client = __esm({
|
|
30
86
|
"src/reports/airtable/client.ts"() {
|
|
31
87
|
"use strict";
|
|
88
|
+
init_credentials();
|
|
32
89
|
}
|
|
33
90
|
});
|
|
34
91
|
|
|
@@ -179,7 +236,7 @@ __export(lighthouse_airtable_exports, {
|
|
|
179
236
|
resolveSlugFromCwd: () => resolveSlugFromCwd
|
|
180
237
|
});
|
|
181
238
|
import { readFile as readFile7 } from "fs/promises";
|
|
182
|
-
import { join as
|
|
239
|
+
import { join as join8 } from "path";
|
|
183
240
|
function hasRealScores(result) {
|
|
184
241
|
if (result.audit !== "lighthouse") return false;
|
|
185
242
|
const details = result.details ?? {};
|
|
@@ -204,7 +261,7 @@ function lighthouseScoresFromResult(result) {
|
|
|
204
261
|
}
|
|
205
262
|
async function resolveSlugFromCwd(cwd) {
|
|
206
263
|
try {
|
|
207
|
-
const pkgPath =
|
|
264
|
+
const pkgPath = join8(cwd, "package.json");
|
|
208
265
|
const raw = await readFile7(pkgPath, "utf-8");
|
|
209
266
|
const pkg = JSON.parse(raw);
|
|
210
267
|
if (!pkg.name) throw new Error("package.json has no 'name' field");
|
|
@@ -457,18 +514,18 @@ var init_reports = __esm({
|
|
|
457
514
|
// src/reports/maintenance-email/assets/index.ts
|
|
458
515
|
import { readFile as readFile13 } from "fs/promises";
|
|
459
516
|
import { existsSync as existsSync3 } from "fs";
|
|
460
|
-
import { dirname as dirname2, join as
|
|
517
|
+
import { dirname as dirname2, join as join22 } from "path";
|
|
461
518
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
462
519
|
function resolveAssetsDir() {
|
|
463
520
|
if (cachedAssetsDir) return cachedAssetsDir;
|
|
464
521
|
let dir = dirname2(fileURLToPath2(import.meta.url));
|
|
465
522
|
while (true) {
|
|
466
|
-
const srcCandidate =
|
|
523
|
+
const srcCandidate = join22(dir, "src", "reports", "maintenance-email", "assets", "check.png");
|
|
467
524
|
if (existsSync3(srcCandidate)) {
|
|
468
525
|
cachedAssetsDir = dirname2(srcCandidate);
|
|
469
526
|
return cachedAssetsDir;
|
|
470
527
|
}
|
|
471
|
-
const distCandidate =
|
|
528
|
+
const distCandidate = join22(dir, "dist", "reports", "maintenance-email", "assets", "check.png");
|
|
472
529
|
if (existsSync3(distCandidate)) {
|
|
473
530
|
cachedAssetsDir = dirname2(distCandidate);
|
|
474
531
|
return cachedAssetsDir;
|
|
@@ -485,8 +542,8 @@ function resolveAssetsDir() {
|
|
|
485
542
|
async function loadBundledImages() {
|
|
486
543
|
const assetsDir = resolveAssetsDir();
|
|
487
544
|
const [check, blurred] = await Promise.all([
|
|
488
|
-
readFile13(
|
|
489
|
-
readFile13(
|
|
545
|
+
readFile13(join22(assetsDir, "check.png")),
|
|
546
|
+
readFile13(join22(assetsDir, "blurredTests.jpg"))
|
|
490
547
|
]);
|
|
491
548
|
return {
|
|
492
549
|
check: {
|
|
@@ -932,12 +989,14 @@ var init_orchestrate = __esm({
|
|
|
932
989
|
});
|
|
933
990
|
|
|
934
991
|
// src/cli/bin.ts
|
|
992
|
+
init_credentials();
|
|
935
993
|
import { dirname as dirname6 } from "path";
|
|
936
994
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
937
995
|
import { cac } from "cac";
|
|
938
996
|
|
|
939
997
|
// src/cli/commands/audit.ts
|
|
940
998
|
import { resolve as resolve2 } from "path";
|
|
999
|
+
import { Listr } from "listr2";
|
|
941
1000
|
|
|
942
1001
|
// src/audits/util/spawn.ts
|
|
943
1002
|
import { spawn } from "child_process";
|
|
@@ -970,7 +1029,7 @@ var defaultSpawn = (cmd, args, opts = {}) => new Promise((resolve10, reject) =>
|
|
|
970
1029
|
|
|
971
1030
|
// src/audits/deps.ts
|
|
972
1031
|
import { readFile } from "fs/promises";
|
|
973
|
-
import { join } from "path";
|
|
1032
|
+
import { join as join2 } from "path";
|
|
974
1033
|
|
|
975
1034
|
// src/util/site.ts
|
|
976
1035
|
function siteLabel(site) {
|
|
@@ -1037,7 +1096,7 @@ function compareSemver(actual, baseline) {
|
|
|
1037
1096
|
return "same";
|
|
1038
1097
|
}
|
|
1039
1098
|
async function depsAudit(ctx) {
|
|
1040
|
-
const pkgPath =
|
|
1099
|
+
const pkgPath = join2(ctx.site.path, "package.json");
|
|
1041
1100
|
let pkgRaw;
|
|
1042
1101
|
try {
|
|
1043
1102
|
pkgRaw = await readFile(pkgPath, "utf-8");
|
|
@@ -1083,7 +1142,7 @@ async function depsAudit(ctx) {
|
|
|
1083
1142
|
// src/audits/lint.ts
|
|
1084
1143
|
import { existsSync } from "fs";
|
|
1085
1144
|
import { readFile as readFile2 } from "fs/promises";
|
|
1086
|
-
import { join as
|
|
1145
|
+
import { join as join3 } from "path";
|
|
1087
1146
|
import { ESLint } from "eslint";
|
|
1088
1147
|
import { check as prettierCheck, resolveConfig as prettierResolveConfig } from "prettier";
|
|
1089
1148
|
import { glob } from "tinyglobby";
|
|
@@ -1094,7 +1153,7 @@ async function listFiles(cwd) {
|
|
|
1094
1153
|
}
|
|
1095
1154
|
async function lintAudit(ctx) {
|
|
1096
1155
|
const { site } = ctx;
|
|
1097
|
-
const configPath =
|
|
1156
|
+
const configPath = join3(site.path, "eslint.config.js");
|
|
1098
1157
|
if (!existsSync(configPath)) {
|
|
1099
1158
|
return {
|
|
1100
1159
|
audit: "lint",
|
|
@@ -1114,7 +1173,7 @@ async function lintAudit(ctx) {
|
|
|
1114
1173
|
const eslintWarnings = eslintResults.reduce((n, r) => n + r.warningCount, 0);
|
|
1115
1174
|
const prettierUnformatted = [];
|
|
1116
1175
|
for (const rel of relFiles) {
|
|
1117
|
-
const absForResolve =
|
|
1176
|
+
const absForResolve = join3(site.path, rel);
|
|
1118
1177
|
const source = await readFile2(absForResolve, "utf-8");
|
|
1119
1178
|
const options = await prettierResolveConfig(absForResolve) ?? {};
|
|
1120
1179
|
const ok = await prettierCheck(source, { ...options, filepath: absForResolve });
|
|
@@ -1278,7 +1337,7 @@ async function securityAudit(ctx) {
|
|
|
1278
1337
|
// src/audits/lighthouse.ts
|
|
1279
1338
|
import { readFile as readFile4, writeFile, mkdtemp, rm, readdir } from "fs/promises";
|
|
1280
1339
|
import { tmpdir } from "os";
|
|
1281
|
-
import { join as
|
|
1340
|
+
import { join as join5 } from "path";
|
|
1282
1341
|
|
|
1283
1342
|
// src/configs/lighthouse.ts
|
|
1284
1343
|
var lighthouseConfig = {
|
|
@@ -1313,11 +1372,11 @@ var lighthouseConfig = {
|
|
|
1313
1372
|
|
|
1314
1373
|
// src/audits/util/site-config.ts
|
|
1315
1374
|
import { readFile as readFile3 } from "fs/promises";
|
|
1316
|
-
import { join as
|
|
1375
|
+
import { join as join4 } from "path";
|
|
1317
1376
|
async function readSiteConfig(sitePath) {
|
|
1318
1377
|
let raw;
|
|
1319
1378
|
try {
|
|
1320
|
-
raw = await readFile3(
|
|
1379
|
+
raw = await readFile3(join4(sitePath, "package.json"), "utf-8");
|
|
1321
1380
|
} catch {
|
|
1322
1381
|
return {};
|
|
1323
1382
|
}
|
|
@@ -1378,7 +1437,7 @@ async function readLhrEntries(resultsDir) {
|
|
|
1378
1437
|
const entries = [];
|
|
1379
1438
|
for (const f of files) {
|
|
1380
1439
|
if (!f.startsWith("lhr-") || !f.endsWith(".json")) continue;
|
|
1381
|
-
const lhr = await readJsonMaybe(
|
|
1440
|
+
const lhr = await readJsonMaybe(join5(resultsDir, f));
|
|
1382
1441
|
if (!lhr || !lhr.categories) continue;
|
|
1383
1442
|
const summary = {};
|
|
1384
1443
|
for (const [k, v] of Object.entries(lhr.categories)) {
|
|
@@ -1432,10 +1491,10 @@ async function lighthouseAudit(ctx) {
|
|
|
1432
1491
|
}
|
|
1433
1492
|
}
|
|
1434
1493
|
};
|
|
1435
|
-
const configDir = await mkdtemp(
|
|
1436
|
-
const configPath =
|
|
1494
|
+
const configDir = await mkdtemp(join5(tmpdir(), "reddoor-lhci-"));
|
|
1495
|
+
const configPath = join5(configDir, "lighthouserc.json");
|
|
1437
1496
|
await writeFile(configPath, JSON.stringify(resolvedConfig), "utf-8");
|
|
1438
|
-
const resultsDir =
|
|
1497
|
+
const resultsDir = join5(site.path, ".lighthouseci");
|
|
1439
1498
|
await rm(resultsDir, { recursive: true, force: true });
|
|
1440
1499
|
let raw;
|
|
1441
1500
|
try {
|
|
@@ -1470,7 +1529,7 @@ async function lighthouseAudit(ctx) {
|
|
|
1470
1529
|
summary: `lighthouse: no lhr-*.json written (exit ${raw.code})${raw.stderr ? ` \u2014 ${raw.stderr.slice(0, 200)}` : ""}`
|
|
1471
1530
|
};
|
|
1472
1531
|
}
|
|
1473
|
-
const assertionResults = await readJsonMaybe(
|
|
1532
|
+
const assertionResults = await readJsonMaybe(join5(resultsDir, "assertion-results.json")) ?? [];
|
|
1474
1533
|
const failed = assertionResults.filter((a) => !a.passed);
|
|
1475
1534
|
const assertions = failed.map((a) => ({
|
|
1476
1535
|
category: categoryFromAssertion(a),
|
|
@@ -1497,7 +1556,7 @@ async function lighthouseAudit(ctx) {
|
|
|
1497
1556
|
|
|
1498
1557
|
// src/audits/a11y.ts
|
|
1499
1558
|
import { readFile as readFile5, writeFile as writeFile2, mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
|
|
1500
|
-
import { join as
|
|
1559
|
+
import { join as join6 } from "path";
|
|
1501
1560
|
|
|
1502
1561
|
// src/configs/playwright-a11y.ts
|
|
1503
1562
|
import { defineConfig, devices } from "@playwright/test";
|
|
@@ -1622,14 +1681,14 @@ async function a11yAudit(ctx) {
|
|
|
1622
1681
|
const spawn2 = ctx.spawn ?? defaultSpawn;
|
|
1623
1682
|
const site = ctx.site;
|
|
1624
1683
|
const label = siteLabel(site);
|
|
1625
|
-
const specDir = await mkdtemp2(
|
|
1626
|
-
const specPath =
|
|
1684
|
+
const specDir = await mkdtemp2(join6(site.path, ".reddoor-a11y-spec-"));
|
|
1685
|
+
const specPath = join6(specDir, "a11y.spec.ts");
|
|
1627
1686
|
await writeFile2(specPath, buildSpec(), "utf-8");
|
|
1628
1687
|
const port = await findFreePort();
|
|
1629
|
-
const configPath =
|
|
1688
|
+
const configPath = join6(specDir, "playwright.config.ts");
|
|
1630
1689
|
await writeFile2(configPath, buildPlaywrightConfig(port, site.path), "utf-8");
|
|
1631
|
-
const resultsPath =
|
|
1632
|
-
await rm2(
|
|
1690
|
+
const resultsPath = join6(site.path, RESULTS_REL);
|
|
1691
|
+
await rm2(join6(site.path, ".reddoor-a11y"), { recursive: true, force: true });
|
|
1633
1692
|
let raw;
|
|
1634
1693
|
try {
|
|
1635
1694
|
raw = await spawn2(
|
|
@@ -1694,29 +1753,27 @@ var DEFAULT_AUDIT_TIMEOUT_MS = 3e4;
|
|
|
1694
1753
|
function timedSpawn(timeoutMs) {
|
|
1695
1754
|
return (cmd, args, opts = {}) => defaultSpawn(cmd, args, { ...opts, timeoutMs: opts.timeoutMs ?? timeoutMs });
|
|
1696
1755
|
}
|
|
1756
|
+
async function runOneAudit(site, name) {
|
|
1757
|
+
if (!(name in REGISTRY)) throw new Error(`unknown audit: ${name}`);
|
|
1758
|
+
const spawn2 = timedSpawn(DEFAULT_AUDIT_TIMEOUT_MS);
|
|
1759
|
+
const label = site.name ?? site.path;
|
|
1760
|
+
try {
|
|
1761
|
+
return await REGISTRY[name]({ site, spawn: spawn2 });
|
|
1762
|
+
} catch (err) {
|
|
1763
|
+
return {
|
|
1764
|
+
audit: name,
|
|
1765
|
+
site: label,
|
|
1766
|
+
status: "fail",
|
|
1767
|
+
summary: `${name}: unexpected error \u2014 ${String(err)}`
|
|
1768
|
+
};
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1697
1771
|
async function runAudits(site, which) {
|
|
1698
1772
|
const names = which ?? ALL_AUDIT_NAMES;
|
|
1699
1773
|
for (const n of names) {
|
|
1700
1774
|
if (!(n in REGISTRY)) throw new Error(`unknown audit: ${n}`);
|
|
1701
1775
|
}
|
|
1702
|
-
|
|
1703
|
-
const label = site.name ?? site.path;
|
|
1704
|
-
return Promise.all(
|
|
1705
|
-
names.map(
|
|
1706
|
-
(n) => REGISTRY[n]({ site, spawn: spawn2 }).catch(
|
|
1707
|
-
(err) => ({
|
|
1708
|
-
audit: n,
|
|
1709
|
-
site: label,
|
|
1710
|
-
status: "fail",
|
|
1711
|
-
summary: `${n}: unexpected error \u2014 ${String(err)}`
|
|
1712
|
-
})
|
|
1713
|
-
)
|
|
1714
|
-
)
|
|
1715
|
-
);
|
|
1716
|
-
}
|
|
1717
|
-
async function runAuditsAcross(sites, which) {
|
|
1718
|
-
const all = await Promise.all(sites.map((s) => runAudits(s, which)));
|
|
1719
|
-
return all.flat();
|
|
1776
|
+
return Promise.all(names.map((n) => runOneAudit(site, n)));
|
|
1720
1777
|
}
|
|
1721
1778
|
|
|
1722
1779
|
// src/cli/fleet/resolve-sites.ts
|
|
@@ -1807,7 +1864,7 @@ async function resolveSites(input) {
|
|
|
1807
1864
|
|
|
1808
1865
|
// src/cli/fleet/clone-if-needed.ts
|
|
1809
1866
|
import { stat, readdir as readdir2, mkdir } from "fs/promises";
|
|
1810
|
-
import { isAbsolute as isAbsolute2, join as
|
|
1867
|
+
import { isAbsolute as isAbsolute2, join as join7 } from "path";
|
|
1811
1868
|
function deriveNameFromRepoUrl(repoUrl) {
|
|
1812
1869
|
const slash = repoUrl.split("/").pop() ?? repoUrl;
|
|
1813
1870
|
return slash.replace(/\.git$/, "");
|
|
@@ -1848,7 +1905,7 @@ async function cloneIfNeeded(site, opts) {
|
|
|
1848
1905
|
const name = site.name ?? deriveNameFromRepoUrl(site.repoUrl);
|
|
1849
1906
|
assertSafeName(name);
|
|
1850
1907
|
assertSafeRepoUrl(site.repoUrl);
|
|
1851
|
-
const target =
|
|
1908
|
+
const target = join7(opts.workdir, name);
|
|
1852
1909
|
await mkdir(opts.workdir, { recursive: true });
|
|
1853
1910
|
if (await isNonEmptyDir(target)) {
|
|
1854
1911
|
return { ...site, name, path: target };
|
|
@@ -1882,8 +1939,87 @@ function formatTable(results) {
|
|
|
1882
1939
|
function exitCode(results) {
|
|
1883
1940
|
return results.some((r) => r.status === "fail") ? 1 : 0;
|
|
1884
1941
|
}
|
|
1942
|
+
function formatDuration(ms) {
|
|
1943
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
1944
|
+
const totalSeconds = Math.round(ms / 1e3);
|
|
1945
|
+
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
1946
|
+
const m = Math.floor(totalSeconds / 60);
|
|
1947
|
+
const s = totalSeconds % 60;
|
|
1948
|
+
return `${m}m${s.toString().padStart(2, "0")}s`;
|
|
1949
|
+
}
|
|
1950
|
+
function buildAuditTasks(sites, which, results, renderer) {
|
|
1951
|
+
const singleSite = sites.length === 1;
|
|
1952
|
+
if (singleSite) {
|
|
1953
|
+
const site = sites[0];
|
|
1954
|
+
return new Listr(
|
|
1955
|
+
which.map((name) => ({
|
|
1956
|
+
title: name,
|
|
1957
|
+
task: async (_ctx, task) => {
|
|
1958
|
+
const start = Date.now();
|
|
1959
|
+
const result = await runOneAudit(site, name);
|
|
1960
|
+
results.push(result);
|
|
1961
|
+
const elapsed = formatDuration(Date.now() - start);
|
|
1962
|
+
task.title = `${name}: ${result.summary} (${elapsed})`;
|
|
1963
|
+
if (result.status === "fail") throw new Error(result.summary);
|
|
1964
|
+
}
|
|
1965
|
+
})),
|
|
1966
|
+
{ concurrent: true, exitOnError: false, renderer }
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
return new Listr(
|
|
1970
|
+
sites.map((site) => {
|
|
1971
|
+
const label = site.name ?? site.path;
|
|
1972
|
+
return {
|
|
1973
|
+
title: label,
|
|
1974
|
+
task: async (_ctx, task) => {
|
|
1975
|
+
const start = Date.now();
|
|
1976
|
+
let done = 0;
|
|
1977
|
+
task.output = `0/${which.length} audits`;
|
|
1978
|
+
const settled = await Promise.all(
|
|
1979
|
+
which.map(async (name) => {
|
|
1980
|
+
const r = await runOneAudit(site, name);
|
|
1981
|
+
results.push(r);
|
|
1982
|
+
done += 1;
|
|
1983
|
+
task.output = `${done}/${which.length} audits`;
|
|
1984
|
+
return r;
|
|
1985
|
+
})
|
|
1986
|
+
);
|
|
1987
|
+
const elapsed = formatDuration(Date.now() - start);
|
|
1988
|
+
const failed = settled.filter((r) => r.status === "fail").length;
|
|
1989
|
+
const warned = settled.filter((r) => r.status === "warn").length;
|
|
1990
|
+
const note = failed > 0 ? `${failed} failed` : warned > 0 ? `${warned} warning${warned === 1 ? "" : "s"}` : "all green";
|
|
1991
|
+
task.title = `${label}: ${note} (${elapsed})`;
|
|
1992
|
+
if (failed > 0) throw new Error(`${label}: ${failed} audit(s) failed`);
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
}),
|
|
1996
|
+
{ concurrent: true, exitOnError: false, renderer }
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
function formatWriteSummary(summary) {
|
|
2000
|
+
const lines = summary.writes.map((w) => {
|
|
2001
|
+
if (w.audit === "lighthouse") {
|
|
2002
|
+
const s = w.counts;
|
|
2003
|
+
return ` lighthouse: P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo}`;
|
|
2004
|
+
}
|
|
2005
|
+
if (w.audit === "a11y") {
|
|
2006
|
+
return ` a11y: ${w.counts.violations} violations`;
|
|
2007
|
+
}
|
|
2008
|
+
if (w.audit === "deps") {
|
|
2009
|
+
const c2 = w.counts;
|
|
2010
|
+
return ` deps: ${c2.drifted} drifted (${c2.majorBehind} major)`;
|
|
2011
|
+
}
|
|
2012
|
+
const c = w.counts;
|
|
2013
|
+
return ` security: ${c.critical}C/${c.high}H/${c.moderate}M/${c.low}L`;
|
|
2014
|
+
});
|
|
2015
|
+
return `\u2192 wrote to Websites[${summary.siteName}]:
|
|
2016
|
+
${lines.join("\n")}`;
|
|
2017
|
+
}
|
|
2018
|
+
function rendererFor(json) {
|
|
2019
|
+
return json ? "silent" : "default";
|
|
2020
|
+
}
|
|
1885
2021
|
async function runAuditCommand(site, opts) {
|
|
1886
|
-
const which = parseOnly(opts.only);
|
|
2022
|
+
const which = parseOnly(opts.only) ?? ALL_AUDIT_NAMES;
|
|
1887
2023
|
const cwd = opts.cwd ? resolve2(opts.cwd) : process.cwd();
|
|
1888
2024
|
let sites = await resolveSites({
|
|
1889
2025
|
...site !== void 0 ? { site } : {},
|
|
@@ -1895,7 +2031,9 @@ async function runAuditCommand(site, opts) {
|
|
|
1895
2031
|
const workdir = opts.workdir ?? `${process.env.HOME ?? ""}/.reddoor-maint/sites`;
|
|
1896
2032
|
sites = await Promise.all(sites.map((s) => cloneIfNeeded(s, { workdir })));
|
|
1897
2033
|
}
|
|
1898
|
-
const results =
|
|
2034
|
+
const results = [];
|
|
2035
|
+
const renderer = rendererFor(opts.json);
|
|
2036
|
+
await buildAuditTasks(sites, which, results, renderer).run();
|
|
1899
2037
|
let output = opts.json ? JSON.stringify(results, null, 2) : formatTable(results);
|
|
1900
2038
|
if (opts.writeAirtable !== void 0) {
|
|
1901
2039
|
const { openBase: openBase2, readAirtableConfig: readAirtableConfig2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
@@ -1903,39 +2041,37 @@ async function runAuditCommand(site, opts) {
|
|
|
1903
2041
|
const { resolveSlugFromCwd: resolveSlugFromCwd2 } = await Promise.resolve().then(() => (init_lighthouse_airtable(), lighthouse_airtable_exports));
|
|
1904
2042
|
const { writeAuditsToAirtable: writeAuditsToAirtable2 } = await Promise.resolve().then(() => (init_write_audits_to_airtable(), write_audits_to_airtable_exports));
|
|
1905
2043
|
const slug = typeof opts.writeAirtable === "string" && opts.writeAirtable.length > 0 ? opts.writeAirtable : await resolveSlugFromCwd2(cwd);
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
output += `
|
|
2044
|
+
let writeSummary = null;
|
|
2045
|
+
await new Listr(
|
|
2046
|
+
[
|
|
2047
|
+
{
|
|
2048
|
+
title: `Write to Airtable[${slug}]`,
|
|
2049
|
+
task: async (_ctx, task) => {
|
|
2050
|
+
const base = openBase2(readAirtableConfig2());
|
|
2051
|
+
task.output = "loading Websites\u2026";
|
|
2052
|
+
const websites = await listWebsites2(base);
|
|
2053
|
+
task.output = "writing scores\u2026";
|
|
2054
|
+
writeSummary = await writeAuditsToAirtable2({ base, websites, slug, results });
|
|
2055
|
+
task.title = `Wrote to Websites[${writeSummary.siteName}] (${writeSummary.writes.length} audit type${writeSummary.writes.length === 1 ? "" : "s"})`;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
],
|
|
2059
|
+
{ renderer }
|
|
2060
|
+
).run();
|
|
2061
|
+
if (writeSummary) output += `
|
|
1925
2062
|
|
|
1926
|
-
|
|
1927
|
-
${lines.join("\n")}`;
|
|
2063
|
+
${formatWriteSummary(writeSummary)}`;
|
|
1928
2064
|
}
|
|
1929
2065
|
return { output, code: exitCode(results) };
|
|
1930
2066
|
}
|
|
1931
2067
|
|
|
1932
2068
|
// src/cli/commands/sync-configs.ts
|
|
1933
2069
|
import { readFile as readFile9 } from "fs/promises";
|
|
1934
|
-
import { join as
|
|
2070
|
+
import { join as join10, resolve as resolve3 } from "path";
|
|
1935
2071
|
|
|
1936
2072
|
// src/recipes/sync-configs.ts
|
|
1937
2073
|
import { readFile as readFile8, writeFile as writeFile3 } from "fs/promises";
|
|
1938
|
-
import { join as
|
|
2074
|
+
import { join as join9 } from "path";
|
|
1939
2075
|
|
|
1940
2076
|
// src/recipes/sync-configs/templates.ts
|
|
1941
2077
|
var eslint = {
|
|
@@ -2208,13 +2344,13 @@ async function readMaybe(path) {
|
|
|
2208
2344
|
async function planTemplateDiffs(cwd, templates) {
|
|
2209
2345
|
const diffs = [];
|
|
2210
2346
|
for (const t of templates) {
|
|
2211
|
-
const existing = await readMaybe(
|
|
2347
|
+
const existing = await readMaybe(join9(cwd, t.path));
|
|
2212
2348
|
if (existing !== t.contents) diffs.push(t);
|
|
2213
2349
|
}
|
|
2214
2350
|
return diffs;
|
|
2215
2351
|
}
|
|
2216
2352
|
async function planGitignore(cwd) {
|
|
2217
|
-
const existing = await readMaybe(
|
|
2353
|
+
const existing = await readMaybe(join9(cwd, ".gitignore"));
|
|
2218
2354
|
const merge = mergeGitignore(existing, CANONICAL_GITIGNORE_ENTRIES);
|
|
2219
2355
|
const tracked = await listTrackedFiles(cwd);
|
|
2220
2356
|
const toUntrack = findTrackedArtifacts(tracked, CANONICAL_GITIGNORE_ENTRIES);
|
|
@@ -2222,7 +2358,7 @@ async function planGitignore(cwd) {
|
|
|
2222
2358
|
return { kind: "apply", content: merge.content, toUntrack, added: merge.added };
|
|
2223
2359
|
}
|
|
2224
2360
|
async function applyGitignore(cwd, plan) {
|
|
2225
|
-
await writeFile3(
|
|
2361
|
+
await writeFile3(join9(cwd, ".gitignore"), plan.content, "utf-8");
|
|
2226
2362
|
if (plan.toUntrack.length > 0) {
|
|
2227
2363
|
await removeFromIndex(cwd, plan.toUntrack);
|
|
2228
2364
|
}
|
|
@@ -2245,7 +2381,7 @@ async function syncConfigs(site, opts = {}) {
|
|
|
2245
2381
|
},
|
|
2246
2382
|
apply: async ({ templateDiffs, gitignorePlan }, { commit: commit2 }) => {
|
|
2247
2383
|
for (const t of templateDiffs) {
|
|
2248
|
-
await writeFile3(
|
|
2384
|
+
await writeFile3(join9(site.path, t.path), t.contents, "utf-8");
|
|
2249
2385
|
await commit2(`chore: sync ${t.config} config from @reddoorla/maintenance`);
|
|
2250
2386
|
}
|
|
2251
2387
|
if (gitignorePlan.kind === "apply") {
|
|
@@ -2274,7 +2410,7 @@ function parseOnly2(value) {
|
|
|
2274
2410
|
async function dryPlanGitignore(cwd) {
|
|
2275
2411
|
let existing;
|
|
2276
2412
|
try {
|
|
2277
|
-
existing = await readFile9(
|
|
2413
|
+
existing = await readFile9(join10(cwd, ".gitignore"), "utf-8");
|
|
2278
2414
|
} catch {
|
|
2279
2415
|
return "would create .gitignore";
|
|
2280
2416
|
}
|
|
@@ -2289,7 +2425,7 @@ async function dryPlan(cwd, which) {
|
|
|
2289
2425
|
for (const t of templateTargets) {
|
|
2290
2426
|
let existing = "";
|
|
2291
2427
|
try {
|
|
2292
|
-
existing = await readFile9(
|
|
2428
|
+
existing = await readFile9(join10(cwd, t.path), "utf-8");
|
|
2293
2429
|
} catch {
|
|
2294
2430
|
}
|
|
2295
2431
|
if (existing !== t.contents) lines.push(`would update ${t.path} (config: ${t.config})`);
|
|
@@ -2337,7 +2473,7 @@ import { resolve as resolve4 } from "path";
|
|
|
2337
2473
|
|
|
2338
2474
|
// src/recipes/bump-deps.ts
|
|
2339
2475
|
import { stat as stat2 } from "fs/promises";
|
|
2340
|
-
import { join as
|
|
2476
|
+
import { join as join11 } from "path";
|
|
2341
2477
|
async function exists(path) {
|
|
2342
2478
|
try {
|
|
2343
2479
|
await stat2(path);
|
|
@@ -2366,10 +2502,10 @@ async function bumpDeps(site, opts = {}) {
|
|
|
2366
2502
|
// land on top of whatever else was in the tree.
|
|
2367
2503
|
checkTreeFirst: true,
|
|
2368
2504
|
plan: async () => {
|
|
2369
|
-
const hasPnpmLock = await exists(
|
|
2505
|
+
const hasPnpmLock = await exists(join11(site.path, "pnpm-lock.yaml"));
|
|
2370
2506
|
if (!hasPnpmLock) {
|
|
2371
|
-
const hasNpmLock = await exists(
|
|
2372
|
-
const hasYarnLock = await exists(
|
|
2507
|
+
const hasNpmLock = await exists(join11(site.path, "package-lock.json"));
|
|
2508
|
+
const hasYarnLock = await exists(join11(site.path, "yarn.lock"));
|
|
2373
2509
|
if (hasNpmLock || hasYarnLock) {
|
|
2374
2510
|
const competing = hasNpmLock ? "package-lock.json" : "yarn.lock";
|
|
2375
2511
|
return {
|
|
@@ -2439,7 +2575,7 @@ async function runBumpDepsCommand(site, opts) {
|
|
|
2439
2575
|
import { resolve as resolve5 } from "path";
|
|
2440
2576
|
|
|
2441
2577
|
// src/recipes/svelte-5/index.ts
|
|
2442
|
-
import { join as
|
|
2578
|
+
import { join as join17 } from "path";
|
|
2443
2579
|
|
|
2444
2580
|
// src/util/pkg.ts
|
|
2445
2581
|
import { readFile as readFile10, writeFile as writeFile4 } from "fs/promises";
|
|
@@ -2488,7 +2624,7 @@ function bumpDep(pkg, name, version2, opts = {}) {
|
|
|
2488
2624
|
}
|
|
2489
2625
|
|
|
2490
2626
|
// src/recipes/svelte-5/step-bump-versions.ts
|
|
2491
|
-
import { join as
|
|
2627
|
+
import { join as join12 } from "path";
|
|
2492
2628
|
var SVELTE_5_VERSIONS = {
|
|
2493
2629
|
svelte: "^5.55.5",
|
|
2494
2630
|
"@sveltejs/kit": "^2.59.0",
|
|
@@ -2501,7 +2637,7 @@ var SVELTE_5_VERSIONS = {
|
|
|
2501
2637
|
"typescript-svelte-plugin": "^0.3.52"
|
|
2502
2638
|
};
|
|
2503
2639
|
async function bumpToSvelte5Versions(cwd) {
|
|
2504
|
-
const pkgPath =
|
|
2640
|
+
const pkgPath = join12(cwd, "package.json");
|
|
2505
2641
|
const pkg = await readPackageJson(pkgPath);
|
|
2506
2642
|
let next = pkg;
|
|
2507
2643
|
for (const [name, version2] of Object.entries(SVELTE_5_VERSIONS)) {
|
|
@@ -2514,7 +2650,7 @@ async function bumpToSvelte5Versions(cwd) {
|
|
|
2514
2650
|
|
|
2515
2651
|
// src/recipes/svelte-5/step-svelte-config.ts
|
|
2516
2652
|
import { readFile as readFile11, writeFile as writeFile5 } from "fs/promises";
|
|
2517
|
-
import { join as
|
|
2653
|
+
import { join as join13 } from "path";
|
|
2518
2654
|
var VITE_PLUGIN_PKG = "@sveltejs/vite-plugin-svelte";
|
|
2519
2655
|
var IMPORT_FROM_VITE_PLUGIN = new RegExp(
|
|
2520
2656
|
String.raw`^import\s+\{\s*([^}]+?)\s*\}\s+from\s+["']` + VITE_PLUGIN_PKG.replace(/[/]/g, "\\/") + String.raw`["'];?[ \t]*\n`,
|
|
@@ -2555,7 +2691,7 @@ function dropPreprocessKey(source) {
|
|
|
2555
2691
|
return source.slice(0, m.index) + source.slice(tailIdx).replace(new RegExp(`^${indent}\\n`), "");
|
|
2556
2692
|
}
|
|
2557
2693
|
async function migrateSvelteConfig(cwd) {
|
|
2558
|
-
const path =
|
|
2694
|
+
const path = join13(cwd, "svelte.config.js");
|
|
2559
2695
|
let src;
|
|
2560
2696
|
try {
|
|
2561
2697
|
src = await readFile11(path, "utf-8");
|
|
@@ -2592,9 +2728,9 @@ async function runSvelteMigrate(cwd, spawn2 = defaultSpawn) {
|
|
|
2592
2728
|
}
|
|
2593
2729
|
|
|
2594
2730
|
// src/recipes/svelte-5/step-tailwind-upgrade.ts
|
|
2595
|
-
import { join as
|
|
2731
|
+
import { join as join14 } from "path";
|
|
2596
2732
|
async function upgradeTailwind(cwd, spawn2 = defaultSpawn) {
|
|
2597
|
-
const pkg = await readPackageJson(
|
|
2733
|
+
const pkg = await readPackageJson(join14(cwd, "package.json"));
|
|
2598
2734
|
const tailwindVersion = pkg.devDependencies?.tailwindcss ?? pkg.dependencies?.tailwindcss;
|
|
2599
2735
|
if (!tailwindVersion) return { ran: false, reason: "tailwindcss not installed" };
|
|
2600
2736
|
if (/^\^?4\./.test(tailwindVersion)) return { ran: false, reason: "already on tailwind 4.x" };
|
|
@@ -2616,7 +2752,7 @@ async function upgradeTailwind(cwd, spawn2 = defaultSpawn) {
|
|
|
2616
2752
|
|
|
2617
2753
|
// src/recipes/svelte-5/step-gotchas.ts
|
|
2618
2754
|
import { readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
|
|
2619
|
-
import { join as
|
|
2755
|
+
import { join as join15 } from "path";
|
|
2620
2756
|
import { glob as glob2 } from "tinyglobby";
|
|
2621
2757
|
|
|
2622
2758
|
// src/recipes/svelte-5/codemods/on-event-to-handler.ts
|
|
@@ -2962,7 +3098,7 @@ async function planGotchaCodemods(cwd) {
|
|
|
2962
3098
|
const changes = [];
|
|
2963
3099
|
const relPaths = await glob2(SVELTE_GLOBS, { cwd, ignore: IGNORE2, absolute: false });
|
|
2964
3100
|
for (const rel of relPaths) {
|
|
2965
|
-
const path =
|
|
3101
|
+
const path = join15(cwd, rel);
|
|
2966
3102
|
const before = await readFile12(path, "utf-8");
|
|
2967
3103
|
const after = CODEMODS.reduce((s, fn) => fn(s), before);
|
|
2968
3104
|
if (after !== before) changes.push({ rel, after });
|
|
@@ -2972,7 +3108,7 @@ async function planGotchaCodemods(cwd) {
|
|
|
2972
3108
|
async function applyGotchaCodemods(cwd) {
|
|
2973
3109
|
const changes = await planGotchaCodemods(cwd);
|
|
2974
3110
|
for (const c of changes) {
|
|
2975
|
-
await writeFile6(
|
|
3111
|
+
await writeFile6(join15(cwd, c.rel), c.after, "utf-8");
|
|
2976
3112
|
}
|
|
2977
3113
|
return { filesChanged: changes.length };
|
|
2978
3114
|
}
|
|
@@ -2996,7 +3132,7 @@ async function verifyMigration(cwd, spawn2 = defaultSpawn) {
|
|
|
2996
3132
|
|
|
2997
3133
|
// src/recipes/svelte-5/step-summary.ts
|
|
2998
3134
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
2999
|
-
import { join as
|
|
3135
|
+
import { join as join16 } from "path";
|
|
3000
3136
|
async function writeMigrationSummary(input) {
|
|
3001
3137
|
const lines = [
|
|
3002
3138
|
`# Svelte 4 \u2192 5 migration summary`,
|
|
@@ -3013,7 +3149,7 @@ async function writeMigrationSummary(input) {
|
|
|
3013
3149
|
`- Verify Playwright a11y tests still pass.`
|
|
3014
3150
|
];
|
|
3015
3151
|
const content = lines.join("\n") + "\n";
|
|
3016
|
-
const path =
|
|
3152
|
+
const path = join16(input.cwd, "MIGRATION_SVELTE_5.md");
|
|
3017
3153
|
await writeFile7(path, content, "utf-8");
|
|
3018
3154
|
return path;
|
|
3019
3155
|
}
|
|
@@ -3021,7 +3157,7 @@ async function writeMigrationSummary(input) {
|
|
|
3021
3157
|
// src/recipes/svelte-5/index.ts
|
|
3022
3158
|
async function alreadyOnSvelte5(cwd) {
|
|
3023
3159
|
try {
|
|
3024
|
-
const pkg = await readPackageJson(
|
|
3160
|
+
const pkg = await readPackageJson(join17(cwd, "package.json"));
|
|
3025
3161
|
const v = pkg.devDependencies?.svelte ?? pkg.dependencies?.svelte;
|
|
3026
3162
|
return !!v && /^\^?5\./.test(v);
|
|
3027
3163
|
} catch {
|
|
@@ -3116,7 +3252,7 @@ import { resolve as resolve6 } from "path";
|
|
|
3116
3252
|
|
|
3117
3253
|
// src/recipes/convert-to-pnpm.ts
|
|
3118
3254
|
import { rm as rm3, stat as stat3 } from "fs/promises";
|
|
3119
|
-
import { join as
|
|
3255
|
+
import { join as join18 } from "path";
|
|
3120
3256
|
|
|
3121
3257
|
// src/recipes/convert-to-pnpm/script-rewrites.ts
|
|
3122
3258
|
function rewriteScriptForPnpm(script) {
|
|
@@ -3149,9 +3285,9 @@ async function exists2(path) {
|
|
|
3149
3285
|
async function convertToPnpm(site, opts = {}) {
|
|
3150
3286
|
const spawn2 = opts.spawn ?? defaultSpawn;
|
|
3151
3287
|
const pnpmVersion = opts.pnpmVersion ?? DEFAULT_PNPM_VERSION;
|
|
3152
|
-
const pnpmLockPath =
|
|
3153
|
-
const npmLockPath =
|
|
3154
|
-
const yarnLockPath =
|
|
3288
|
+
const pnpmLockPath = join18(site.path, "pnpm-lock.yaml");
|
|
3289
|
+
const npmLockPath = join18(site.path, "package-lock.json");
|
|
3290
|
+
const yarnLockPath = join18(site.path, "yarn.lock");
|
|
3155
3291
|
return withRecipe({
|
|
3156
3292
|
name: "convert-to-pnpm",
|
|
3157
3293
|
site,
|
|
@@ -3174,7 +3310,7 @@ async function convertToPnpm(site, opts = {}) {
|
|
|
3174
3310
|
if (hasYarnLock) await rm3(yarnLockPath, { force: true });
|
|
3175
3311
|
const sourceLock = hasNpmLock ? "package-lock.json" : "yarn.lock";
|
|
3176
3312
|
await commit2(`chore(pnpm): remove ${sourceLock}`);
|
|
3177
|
-
const pkgPath =
|
|
3313
|
+
const pkgPath = join18(cwd, "package.json");
|
|
3178
3314
|
const pkg = await readPackageJson(pkgPath);
|
|
3179
3315
|
const next = { ...pkg, packageManager: `pnpm@${pnpmVersion}` };
|
|
3180
3316
|
if (pkg.scripts && typeof pkg.scripts === "object") {
|
|
@@ -3187,7 +3323,7 @@ async function convertToPnpm(site, opts = {}) {
|
|
|
3187
3323
|
}
|
|
3188
3324
|
await writePackageJson(pkgPath, next);
|
|
3189
3325
|
await commit2("chore(pnpm): pin packageManager + rewrite npm scripts");
|
|
3190
|
-
await rm3(
|
|
3326
|
+
await rm3(join18(cwd, "node_modules"), { recursive: true, force: true });
|
|
3191
3327
|
const installResult = await spawn2("pnpm", ["install"], { cwd, streaming: true });
|
|
3192
3328
|
if (installResult.code !== 0) {
|
|
3193
3329
|
return { kind: "failed", notes: `pnpm install failed (exit ${installResult.code})` };
|
|
@@ -3228,19 +3364,19 @@ import { resolve as resolve7 } from "path";
|
|
|
3228
3364
|
|
|
3229
3365
|
// src/recipes/onboard.ts
|
|
3230
3366
|
import { stat as stat4 } from "fs/promises";
|
|
3231
|
-
import { join as
|
|
3367
|
+
import { join as join20 } from "path";
|
|
3232
3368
|
|
|
3233
3369
|
// src/util/self-version.ts
|
|
3234
|
-
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
3370
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
3235
3371
|
import { fileURLToPath } from "url";
|
|
3236
|
-
import { dirname, join as
|
|
3372
|
+
import { dirname, join as join19 } from "path";
|
|
3237
3373
|
function selfPackageVersion(callerImportMetaUrl) {
|
|
3238
3374
|
try {
|
|
3239
3375
|
let dir = dirname(fileURLToPath(callerImportMetaUrl));
|
|
3240
3376
|
while (true) {
|
|
3241
|
-
const candidate =
|
|
3377
|
+
const candidate = join19(dir, "package.json");
|
|
3242
3378
|
if (existsSync2(candidate)) {
|
|
3243
|
-
const raw =
|
|
3379
|
+
const raw = readFileSync2(candidate, "utf-8");
|
|
3244
3380
|
const pkg = JSON.parse(raw);
|
|
3245
3381
|
if (pkg.name === "@reddoorla/maintenance") {
|
|
3246
3382
|
return pkg.version ?? "0.0.0";
|
|
@@ -3297,13 +3433,13 @@ async function onboard(site, opts = {}) {
|
|
|
3297
3433
|
name: "onboard",
|
|
3298
3434
|
site,
|
|
3299
3435
|
plan: async () => {
|
|
3300
|
-
if (!await exists3(
|
|
3436
|
+
if (!await exists3(join20(site.path, "pnpm-lock.yaml"))) {
|
|
3301
3437
|
return {
|
|
3302
3438
|
kind: "failed",
|
|
3303
3439
|
notes: "no pnpm-lock.yaml at site root \u2014 run convert-to-pnpm first"
|
|
3304
3440
|
};
|
|
3305
3441
|
}
|
|
3306
|
-
const pkgPath =
|
|
3442
|
+
const pkgPath = join20(site.path, "package.json");
|
|
3307
3443
|
const pkg = await readPackageJson(pkgPath);
|
|
3308
3444
|
const toAdd = [];
|
|
3309
3445
|
if (!isDeclared(pkg, PACKAGE_NAME)) {
|
|
@@ -3323,7 +3459,7 @@ async function onboard(site, opts = {}) {
|
|
|
3323
3459
|
return { kind: "apply", plan: { pkg, toAdd } };
|
|
3324
3460
|
},
|
|
3325
3461
|
apply: async ({ pkg, toAdd }, { commit: commit2, cwd }) => {
|
|
3326
|
-
const pkgPath =
|
|
3462
|
+
const pkgPath = join20(cwd, "package.json");
|
|
3327
3463
|
let next = pkg;
|
|
3328
3464
|
for (const dep of toAdd) {
|
|
3329
3465
|
next = bumpDep(next, dep.name, dep.version);
|
|
@@ -3392,7 +3528,7 @@ import { resolve as resolve8 } from "path";
|
|
|
3392
3528
|
|
|
3393
3529
|
// src/recipes/svelte-codemods.ts
|
|
3394
3530
|
import { writeFile as writeFile8 } from "fs/promises";
|
|
3395
|
-
import { join as
|
|
3531
|
+
import { join as join21 } from "path";
|
|
3396
3532
|
async function svelteCodemods(site) {
|
|
3397
3533
|
return withRecipe({
|
|
3398
3534
|
name: "svelte-codemods",
|
|
@@ -3406,7 +3542,7 @@ async function svelteCodemods(site) {
|
|
|
3406
3542
|
},
|
|
3407
3543
|
apply: async (changes, { commit: commit2, cwd }) => {
|
|
3408
3544
|
for (const c of changes) {
|
|
3409
|
-
await writeFile8(
|
|
3545
|
+
await writeFile8(join21(cwd, c.rel), c.after, "utf-8");
|
|
3410
3546
|
}
|
|
3411
3547
|
await commit2(`refactor(svelte5): apply codemods (${changes.length} files)`);
|
|
3412
3548
|
return { kind: "ok" };
|
|
@@ -3633,7 +3769,7 @@ import { resolve as resolve9 } from "path";
|
|
|
3633
3769
|
|
|
3634
3770
|
// src/recipes/a11y-fixtures-page/index.ts
|
|
3635
3771
|
import { access, mkdir as mkdir3, writeFile as writeFile10 } from "fs/promises";
|
|
3636
|
-
import { dirname as dirname4, join as
|
|
3772
|
+
import { dirname as dirname4, join as join23 } from "path";
|
|
3637
3773
|
|
|
3638
3774
|
// src/recipes/a11y-fixtures-page/template.ts
|
|
3639
3775
|
var A11Y_FIXTURES_PAGE_RELATIVE = "src/routes/dev/a11y-fixtures/+page.svelte";
|
|
@@ -3684,7 +3820,7 @@ async function fileExists(path) {
|
|
|
3684
3820
|
}
|
|
3685
3821
|
}
|
|
3686
3822
|
async function a11yFixturesPage(site) {
|
|
3687
|
-
const target =
|
|
3823
|
+
const target = join23(site.path, A11Y_FIXTURES_PAGE_RELATIVE);
|
|
3688
3824
|
return withRecipe({
|
|
3689
3825
|
name: "a11y-fixtures-page",
|
|
3690
3826
|
site,
|
|
@@ -3791,15 +3927,15 @@ async function runInitCommand(site, opts) {
|
|
|
3791
3927
|
}
|
|
3792
3928
|
|
|
3793
3929
|
// src/cli/version.ts
|
|
3794
|
-
import { readFileSync as
|
|
3795
|
-
import { dirname as dirname5, join as
|
|
3930
|
+
import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
|
|
3931
|
+
import { dirname as dirname5, join as join24 } from "path";
|
|
3796
3932
|
function resolvePackageVersion(fromDir) {
|
|
3797
3933
|
try {
|
|
3798
3934
|
let dir = fromDir;
|
|
3799
3935
|
while (true) {
|
|
3800
|
-
const candidate =
|
|
3936
|
+
const candidate = join24(dir, "package.json");
|
|
3801
3937
|
if (existsSync4(candidate)) {
|
|
3802
|
-
const raw =
|
|
3938
|
+
const raw = readFileSync3(candidate, "utf-8");
|
|
3803
3939
|
const pkg = JSON.parse(raw);
|
|
3804
3940
|
if (pkg.name === "@reddoorla/maintenance") {
|
|
3805
3941
|
return pkg.version ?? "unknown";
|
|
@@ -3815,6 +3951,7 @@ function resolvePackageVersion(fromDir) {
|
|
|
3815
3951
|
}
|
|
3816
3952
|
|
|
3817
3953
|
// src/cli/bin.ts
|
|
3954
|
+
loadCredentialsIntoEnv();
|
|
3818
3955
|
var here = dirname6(fileURLToPath3(import.meta.url));
|
|
3819
3956
|
var version = resolvePackageVersion(here);
|
|
3820
3957
|
var AUDIT_DESCRIPTIONS = {
|