@reddoorla/maintenance 0.15.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 +136 -77
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.js +29 -6
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/index.js +21 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -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,6 +989,7 @@ 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";
|
|
@@ -971,7 +1029,7 @@ var defaultSpawn = (cmd, args, opts = {}) => new Promise((resolve10, reject) =>
|
|
|
971
1029
|
|
|
972
1030
|
// src/audits/deps.ts
|
|
973
1031
|
import { readFile } from "fs/promises";
|
|
974
|
-
import { join } from "path";
|
|
1032
|
+
import { join as join2 } from "path";
|
|
975
1033
|
|
|
976
1034
|
// src/util/site.ts
|
|
977
1035
|
function siteLabel(site) {
|
|
@@ -1038,7 +1096,7 @@ function compareSemver(actual, baseline) {
|
|
|
1038
1096
|
return "same";
|
|
1039
1097
|
}
|
|
1040
1098
|
async function depsAudit(ctx) {
|
|
1041
|
-
const pkgPath =
|
|
1099
|
+
const pkgPath = join2(ctx.site.path, "package.json");
|
|
1042
1100
|
let pkgRaw;
|
|
1043
1101
|
try {
|
|
1044
1102
|
pkgRaw = await readFile(pkgPath, "utf-8");
|
|
@@ -1084,7 +1142,7 @@ async function depsAudit(ctx) {
|
|
|
1084
1142
|
// src/audits/lint.ts
|
|
1085
1143
|
import { existsSync } from "fs";
|
|
1086
1144
|
import { readFile as readFile2 } from "fs/promises";
|
|
1087
|
-
import { join as
|
|
1145
|
+
import { join as join3 } from "path";
|
|
1088
1146
|
import { ESLint } from "eslint";
|
|
1089
1147
|
import { check as prettierCheck, resolveConfig as prettierResolveConfig } from "prettier";
|
|
1090
1148
|
import { glob } from "tinyglobby";
|
|
@@ -1095,7 +1153,7 @@ async function listFiles(cwd) {
|
|
|
1095
1153
|
}
|
|
1096
1154
|
async function lintAudit(ctx) {
|
|
1097
1155
|
const { site } = ctx;
|
|
1098
|
-
const configPath =
|
|
1156
|
+
const configPath = join3(site.path, "eslint.config.js");
|
|
1099
1157
|
if (!existsSync(configPath)) {
|
|
1100
1158
|
return {
|
|
1101
1159
|
audit: "lint",
|
|
@@ -1115,7 +1173,7 @@ async function lintAudit(ctx) {
|
|
|
1115
1173
|
const eslintWarnings = eslintResults.reduce((n, r) => n + r.warningCount, 0);
|
|
1116
1174
|
const prettierUnformatted = [];
|
|
1117
1175
|
for (const rel of relFiles) {
|
|
1118
|
-
const absForResolve =
|
|
1176
|
+
const absForResolve = join3(site.path, rel);
|
|
1119
1177
|
const source = await readFile2(absForResolve, "utf-8");
|
|
1120
1178
|
const options = await prettierResolveConfig(absForResolve) ?? {};
|
|
1121
1179
|
const ok = await prettierCheck(source, { ...options, filepath: absForResolve });
|
|
@@ -1279,7 +1337,7 @@ async function securityAudit(ctx) {
|
|
|
1279
1337
|
// src/audits/lighthouse.ts
|
|
1280
1338
|
import { readFile as readFile4, writeFile, mkdtemp, rm, readdir } from "fs/promises";
|
|
1281
1339
|
import { tmpdir } from "os";
|
|
1282
|
-
import { join as
|
|
1340
|
+
import { join as join5 } from "path";
|
|
1283
1341
|
|
|
1284
1342
|
// src/configs/lighthouse.ts
|
|
1285
1343
|
var lighthouseConfig = {
|
|
@@ -1314,11 +1372,11 @@ var lighthouseConfig = {
|
|
|
1314
1372
|
|
|
1315
1373
|
// src/audits/util/site-config.ts
|
|
1316
1374
|
import { readFile as readFile3 } from "fs/promises";
|
|
1317
|
-
import { join as
|
|
1375
|
+
import { join as join4 } from "path";
|
|
1318
1376
|
async function readSiteConfig(sitePath) {
|
|
1319
1377
|
let raw;
|
|
1320
1378
|
try {
|
|
1321
|
-
raw = await readFile3(
|
|
1379
|
+
raw = await readFile3(join4(sitePath, "package.json"), "utf-8");
|
|
1322
1380
|
} catch {
|
|
1323
1381
|
return {};
|
|
1324
1382
|
}
|
|
@@ -1379,7 +1437,7 @@ async function readLhrEntries(resultsDir) {
|
|
|
1379
1437
|
const entries = [];
|
|
1380
1438
|
for (const f of files) {
|
|
1381
1439
|
if (!f.startsWith("lhr-") || !f.endsWith(".json")) continue;
|
|
1382
|
-
const lhr = await readJsonMaybe(
|
|
1440
|
+
const lhr = await readJsonMaybe(join5(resultsDir, f));
|
|
1383
1441
|
if (!lhr || !lhr.categories) continue;
|
|
1384
1442
|
const summary = {};
|
|
1385
1443
|
for (const [k, v] of Object.entries(lhr.categories)) {
|
|
@@ -1433,10 +1491,10 @@ async function lighthouseAudit(ctx) {
|
|
|
1433
1491
|
}
|
|
1434
1492
|
}
|
|
1435
1493
|
};
|
|
1436
|
-
const configDir = await mkdtemp(
|
|
1437
|
-
const configPath =
|
|
1494
|
+
const configDir = await mkdtemp(join5(tmpdir(), "reddoor-lhci-"));
|
|
1495
|
+
const configPath = join5(configDir, "lighthouserc.json");
|
|
1438
1496
|
await writeFile(configPath, JSON.stringify(resolvedConfig), "utf-8");
|
|
1439
|
-
const resultsDir =
|
|
1497
|
+
const resultsDir = join5(site.path, ".lighthouseci");
|
|
1440
1498
|
await rm(resultsDir, { recursive: true, force: true });
|
|
1441
1499
|
let raw;
|
|
1442
1500
|
try {
|
|
@@ -1471,7 +1529,7 @@ async function lighthouseAudit(ctx) {
|
|
|
1471
1529
|
summary: `lighthouse: no lhr-*.json written (exit ${raw.code})${raw.stderr ? ` \u2014 ${raw.stderr.slice(0, 200)}` : ""}`
|
|
1472
1530
|
};
|
|
1473
1531
|
}
|
|
1474
|
-
const assertionResults = await readJsonMaybe(
|
|
1532
|
+
const assertionResults = await readJsonMaybe(join5(resultsDir, "assertion-results.json")) ?? [];
|
|
1475
1533
|
const failed = assertionResults.filter((a) => !a.passed);
|
|
1476
1534
|
const assertions = failed.map((a) => ({
|
|
1477
1535
|
category: categoryFromAssertion(a),
|
|
@@ -1498,7 +1556,7 @@ async function lighthouseAudit(ctx) {
|
|
|
1498
1556
|
|
|
1499
1557
|
// src/audits/a11y.ts
|
|
1500
1558
|
import { readFile as readFile5, writeFile as writeFile2, mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
|
|
1501
|
-
import { join as
|
|
1559
|
+
import { join as join6 } from "path";
|
|
1502
1560
|
|
|
1503
1561
|
// src/configs/playwright-a11y.ts
|
|
1504
1562
|
import { defineConfig, devices } from "@playwright/test";
|
|
@@ -1623,14 +1681,14 @@ async function a11yAudit(ctx) {
|
|
|
1623
1681
|
const spawn2 = ctx.spawn ?? defaultSpawn;
|
|
1624
1682
|
const site = ctx.site;
|
|
1625
1683
|
const label = siteLabel(site);
|
|
1626
|
-
const specDir = await mkdtemp2(
|
|
1627
|
-
const specPath =
|
|
1684
|
+
const specDir = await mkdtemp2(join6(site.path, ".reddoor-a11y-spec-"));
|
|
1685
|
+
const specPath = join6(specDir, "a11y.spec.ts");
|
|
1628
1686
|
await writeFile2(specPath, buildSpec(), "utf-8");
|
|
1629
1687
|
const port = await findFreePort();
|
|
1630
|
-
const configPath =
|
|
1688
|
+
const configPath = join6(specDir, "playwright.config.ts");
|
|
1631
1689
|
await writeFile2(configPath, buildPlaywrightConfig(port, site.path), "utf-8");
|
|
1632
|
-
const resultsPath =
|
|
1633
|
-
await rm2(
|
|
1690
|
+
const resultsPath = join6(site.path, RESULTS_REL);
|
|
1691
|
+
await rm2(join6(site.path, ".reddoor-a11y"), { recursive: true, force: true });
|
|
1634
1692
|
let raw;
|
|
1635
1693
|
try {
|
|
1636
1694
|
raw = await spawn2(
|
|
@@ -1806,7 +1864,7 @@ async function resolveSites(input) {
|
|
|
1806
1864
|
|
|
1807
1865
|
// src/cli/fleet/clone-if-needed.ts
|
|
1808
1866
|
import { stat, readdir as readdir2, mkdir } from "fs/promises";
|
|
1809
|
-
import { isAbsolute as isAbsolute2, join as
|
|
1867
|
+
import { isAbsolute as isAbsolute2, join as join7 } from "path";
|
|
1810
1868
|
function deriveNameFromRepoUrl(repoUrl) {
|
|
1811
1869
|
const slash = repoUrl.split("/").pop() ?? repoUrl;
|
|
1812
1870
|
return slash.replace(/\.git$/, "");
|
|
@@ -1847,7 +1905,7 @@ async function cloneIfNeeded(site, opts) {
|
|
|
1847
1905
|
const name = site.name ?? deriveNameFromRepoUrl(site.repoUrl);
|
|
1848
1906
|
assertSafeName(name);
|
|
1849
1907
|
assertSafeRepoUrl(site.repoUrl);
|
|
1850
|
-
const target =
|
|
1908
|
+
const target = join7(opts.workdir, name);
|
|
1851
1909
|
await mkdir(opts.workdir, { recursive: true });
|
|
1852
1910
|
if (await isNonEmptyDir(target)) {
|
|
1853
1911
|
return { ...site, name, path: target };
|
|
@@ -2009,11 +2067,11 @@ ${formatWriteSummary(writeSummary)}`;
|
|
|
2009
2067
|
|
|
2010
2068
|
// src/cli/commands/sync-configs.ts
|
|
2011
2069
|
import { readFile as readFile9 } from "fs/promises";
|
|
2012
|
-
import { join as
|
|
2070
|
+
import { join as join10, resolve as resolve3 } from "path";
|
|
2013
2071
|
|
|
2014
2072
|
// src/recipes/sync-configs.ts
|
|
2015
2073
|
import { readFile as readFile8, writeFile as writeFile3 } from "fs/promises";
|
|
2016
|
-
import { join as
|
|
2074
|
+
import { join as join9 } from "path";
|
|
2017
2075
|
|
|
2018
2076
|
// src/recipes/sync-configs/templates.ts
|
|
2019
2077
|
var eslint = {
|
|
@@ -2286,13 +2344,13 @@ async function readMaybe(path) {
|
|
|
2286
2344
|
async function planTemplateDiffs(cwd, templates) {
|
|
2287
2345
|
const diffs = [];
|
|
2288
2346
|
for (const t of templates) {
|
|
2289
|
-
const existing = await readMaybe(
|
|
2347
|
+
const existing = await readMaybe(join9(cwd, t.path));
|
|
2290
2348
|
if (existing !== t.contents) diffs.push(t);
|
|
2291
2349
|
}
|
|
2292
2350
|
return diffs;
|
|
2293
2351
|
}
|
|
2294
2352
|
async function planGitignore(cwd) {
|
|
2295
|
-
const existing = await readMaybe(
|
|
2353
|
+
const existing = await readMaybe(join9(cwd, ".gitignore"));
|
|
2296
2354
|
const merge = mergeGitignore(existing, CANONICAL_GITIGNORE_ENTRIES);
|
|
2297
2355
|
const tracked = await listTrackedFiles(cwd);
|
|
2298
2356
|
const toUntrack = findTrackedArtifacts(tracked, CANONICAL_GITIGNORE_ENTRIES);
|
|
@@ -2300,7 +2358,7 @@ async function planGitignore(cwd) {
|
|
|
2300
2358
|
return { kind: "apply", content: merge.content, toUntrack, added: merge.added };
|
|
2301
2359
|
}
|
|
2302
2360
|
async function applyGitignore(cwd, plan) {
|
|
2303
|
-
await writeFile3(
|
|
2361
|
+
await writeFile3(join9(cwd, ".gitignore"), plan.content, "utf-8");
|
|
2304
2362
|
if (plan.toUntrack.length > 0) {
|
|
2305
2363
|
await removeFromIndex(cwd, plan.toUntrack);
|
|
2306
2364
|
}
|
|
@@ -2323,7 +2381,7 @@ async function syncConfigs(site, opts = {}) {
|
|
|
2323
2381
|
},
|
|
2324
2382
|
apply: async ({ templateDiffs, gitignorePlan }, { commit: commit2 }) => {
|
|
2325
2383
|
for (const t of templateDiffs) {
|
|
2326
|
-
await writeFile3(
|
|
2384
|
+
await writeFile3(join9(site.path, t.path), t.contents, "utf-8");
|
|
2327
2385
|
await commit2(`chore: sync ${t.config} config from @reddoorla/maintenance`);
|
|
2328
2386
|
}
|
|
2329
2387
|
if (gitignorePlan.kind === "apply") {
|
|
@@ -2352,7 +2410,7 @@ function parseOnly2(value) {
|
|
|
2352
2410
|
async function dryPlanGitignore(cwd) {
|
|
2353
2411
|
let existing;
|
|
2354
2412
|
try {
|
|
2355
|
-
existing = await readFile9(
|
|
2413
|
+
existing = await readFile9(join10(cwd, ".gitignore"), "utf-8");
|
|
2356
2414
|
} catch {
|
|
2357
2415
|
return "would create .gitignore";
|
|
2358
2416
|
}
|
|
@@ -2367,7 +2425,7 @@ async function dryPlan(cwd, which) {
|
|
|
2367
2425
|
for (const t of templateTargets) {
|
|
2368
2426
|
let existing = "";
|
|
2369
2427
|
try {
|
|
2370
|
-
existing = await readFile9(
|
|
2428
|
+
existing = await readFile9(join10(cwd, t.path), "utf-8");
|
|
2371
2429
|
} catch {
|
|
2372
2430
|
}
|
|
2373
2431
|
if (existing !== t.contents) lines.push(`would update ${t.path} (config: ${t.config})`);
|
|
@@ -2415,7 +2473,7 @@ import { resolve as resolve4 } from "path";
|
|
|
2415
2473
|
|
|
2416
2474
|
// src/recipes/bump-deps.ts
|
|
2417
2475
|
import { stat as stat2 } from "fs/promises";
|
|
2418
|
-
import { join as
|
|
2476
|
+
import { join as join11 } from "path";
|
|
2419
2477
|
async function exists(path) {
|
|
2420
2478
|
try {
|
|
2421
2479
|
await stat2(path);
|
|
@@ -2444,10 +2502,10 @@ async function bumpDeps(site, opts = {}) {
|
|
|
2444
2502
|
// land on top of whatever else was in the tree.
|
|
2445
2503
|
checkTreeFirst: true,
|
|
2446
2504
|
plan: async () => {
|
|
2447
|
-
const hasPnpmLock = await exists(
|
|
2505
|
+
const hasPnpmLock = await exists(join11(site.path, "pnpm-lock.yaml"));
|
|
2448
2506
|
if (!hasPnpmLock) {
|
|
2449
|
-
const hasNpmLock = await exists(
|
|
2450
|
-
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"));
|
|
2451
2509
|
if (hasNpmLock || hasYarnLock) {
|
|
2452
2510
|
const competing = hasNpmLock ? "package-lock.json" : "yarn.lock";
|
|
2453
2511
|
return {
|
|
@@ -2517,7 +2575,7 @@ async function runBumpDepsCommand(site, opts) {
|
|
|
2517
2575
|
import { resolve as resolve5 } from "path";
|
|
2518
2576
|
|
|
2519
2577
|
// src/recipes/svelte-5/index.ts
|
|
2520
|
-
import { join as
|
|
2578
|
+
import { join as join17 } from "path";
|
|
2521
2579
|
|
|
2522
2580
|
// src/util/pkg.ts
|
|
2523
2581
|
import { readFile as readFile10, writeFile as writeFile4 } from "fs/promises";
|
|
@@ -2566,7 +2624,7 @@ function bumpDep(pkg, name, version2, opts = {}) {
|
|
|
2566
2624
|
}
|
|
2567
2625
|
|
|
2568
2626
|
// src/recipes/svelte-5/step-bump-versions.ts
|
|
2569
|
-
import { join as
|
|
2627
|
+
import { join as join12 } from "path";
|
|
2570
2628
|
var SVELTE_5_VERSIONS = {
|
|
2571
2629
|
svelte: "^5.55.5",
|
|
2572
2630
|
"@sveltejs/kit": "^2.59.0",
|
|
@@ -2579,7 +2637,7 @@ var SVELTE_5_VERSIONS = {
|
|
|
2579
2637
|
"typescript-svelte-plugin": "^0.3.52"
|
|
2580
2638
|
};
|
|
2581
2639
|
async function bumpToSvelte5Versions(cwd) {
|
|
2582
|
-
const pkgPath =
|
|
2640
|
+
const pkgPath = join12(cwd, "package.json");
|
|
2583
2641
|
const pkg = await readPackageJson(pkgPath);
|
|
2584
2642
|
let next = pkg;
|
|
2585
2643
|
for (const [name, version2] of Object.entries(SVELTE_5_VERSIONS)) {
|
|
@@ -2592,7 +2650,7 @@ async function bumpToSvelte5Versions(cwd) {
|
|
|
2592
2650
|
|
|
2593
2651
|
// src/recipes/svelte-5/step-svelte-config.ts
|
|
2594
2652
|
import { readFile as readFile11, writeFile as writeFile5 } from "fs/promises";
|
|
2595
|
-
import { join as
|
|
2653
|
+
import { join as join13 } from "path";
|
|
2596
2654
|
var VITE_PLUGIN_PKG = "@sveltejs/vite-plugin-svelte";
|
|
2597
2655
|
var IMPORT_FROM_VITE_PLUGIN = new RegExp(
|
|
2598
2656
|
String.raw`^import\s+\{\s*([^}]+?)\s*\}\s+from\s+["']` + VITE_PLUGIN_PKG.replace(/[/]/g, "\\/") + String.raw`["'];?[ \t]*\n`,
|
|
@@ -2633,7 +2691,7 @@ function dropPreprocessKey(source) {
|
|
|
2633
2691
|
return source.slice(0, m.index) + source.slice(tailIdx).replace(new RegExp(`^${indent}\\n`), "");
|
|
2634
2692
|
}
|
|
2635
2693
|
async function migrateSvelteConfig(cwd) {
|
|
2636
|
-
const path =
|
|
2694
|
+
const path = join13(cwd, "svelte.config.js");
|
|
2637
2695
|
let src;
|
|
2638
2696
|
try {
|
|
2639
2697
|
src = await readFile11(path, "utf-8");
|
|
@@ -2670,9 +2728,9 @@ async function runSvelteMigrate(cwd, spawn2 = defaultSpawn) {
|
|
|
2670
2728
|
}
|
|
2671
2729
|
|
|
2672
2730
|
// src/recipes/svelte-5/step-tailwind-upgrade.ts
|
|
2673
|
-
import { join as
|
|
2731
|
+
import { join as join14 } from "path";
|
|
2674
2732
|
async function upgradeTailwind(cwd, spawn2 = defaultSpawn) {
|
|
2675
|
-
const pkg = await readPackageJson(
|
|
2733
|
+
const pkg = await readPackageJson(join14(cwd, "package.json"));
|
|
2676
2734
|
const tailwindVersion = pkg.devDependencies?.tailwindcss ?? pkg.dependencies?.tailwindcss;
|
|
2677
2735
|
if (!tailwindVersion) return { ran: false, reason: "tailwindcss not installed" };
|
|
2678
2736
|
if (/^\^?4\./.test(tailwindVersion)) return { ran: false, reason: "already on tailwind 4.x" };
|
|
@@ -2694,7 +2752,7 @@ async function upgradeTailwind(cwd, spawn2 = defaultSpawn) {
|
|
|
2694
2752
|
|
|
2695
2753
|
// src/recipes/svelte-5/step-gotchas.ts
|
|
2696
2754
|
import { readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
|
|
2697
|
-
import { join as
|
|
2755
|
+
import { join as join15 } from "path";
|
|
2698
2756
|
import { glob as glob2 } from "tinyglobby";
|
|
2699
2757
|
|
|
2700
2758
|
// src/recipes/svelte-5/codemods/on-event-to-handler.ts
|
|
@@ -3040,7 +3098,7 @@ async function planGotchaCodemods(cwd) {
|
|
|
3040
3098
|
const changes = [];
|
|
3041
3099
|
const relPaths = await glob2(SVELTE_GLOBS, { cwd, ignore: IGNORE2, absolute: false });
|
|
3042
3100
|
for (const rel of relPaths) {
|
|
3043
|
-
const path =
|
|
3101
|
+
const path = join15(cwd, rel);
|
|
3044
3102
|
const before = await readFile12(path, "utf-8");
|
|
3045
3103
|
const after = CODEMODS.reduce((s, fn) => fn(s), before);
|
|
3046
3104
|
if (after !== before) changes.push({ rel, after });
|
|
@@ -3050,7 +3108,7 @@ async function planGotchaCodemods(cwd) {
|
|
|
3050
3108
|
async function applyGotchaCodemods(cwd) {
|
|
3051
3109
|
const changes = await planGotchaCodemods(cwd);
|
|
3052
3110
|
for (const c of changes) {
|
|
3053
|
-
await writeFile6(
|
|
3111
|
+
await writeFile6(join15(cwd, c.rel), c.after, "utf-8");
|
|
3054
3112
|
}
|
|
3055
3113
|
return { filesChanged: changes.length };
|
|
3056
3114
|
}
|
|
@@ -3074,7 +3132,7 @@ async function verifyMigration(cwd, spawn2 = defaultSpawn) {
|
|
|
3074
3132
|
|
|
3075
3133
|
// src/recipes/svelte-5/step-summary.ts
|
|
3076
3134
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
3077
|
-
import { join as
|
|
3135
|
+
import { join as join16 } from "path";
|
|
3078
3136
|
async function writeMigrationSummary(input) {
|
|
3079
3137
|
const lines = [
|
|
3080
3138
|
`# Svelte 4 \u2192 5 migration summary`,
|
|
@@ -3091,7 +3149,7 @@ async function writeMigrationSummary(input) {
|
|
|
3091
3149
|
`- Verify Playwright a11y tests still pass.`
|
|
3092
3150
|
];
|
|
3093
3151
|
const content = lines.join("\n") + "\n";
|
|
3094
|
-
const path =
|
|
3152
|
+
const path = join16(input.cwd, "MIGRATION_SVELTE_5.md");
|
|
3095
3153
|
await writeFile7(path, content, "utf-8");
|
|
3096
3154
|
return path;
|
|
3097
3155
|
}
|
|
@@ -3099,7 +3157,7 @@ async function writeMigrationSummary(input) {
|
|
|
3099
3157
|
// src/recipes/svelte-5/index.ts
|
|
3100
3158
|
async function alreadyOnSvelte5(cwd) {
|
|
3101
3159
|
try {
|
|
3102
|
-
const pkg = await readPackageJson(
|
|
3160
|
+
const pkg = await readPackageJson(join17(cwd, "package.json"));
|
|
3103
3161
|
const v = pkg.devDependencies?.svelte ?? pkg.dependencies?.svelte;
|
|
3104
3162
|
return !!v && /^\^?5\./.test(v);
|
|
3105
3163
|
} catch {
|
|
@@ -3194,7 +3252,7 @@ import { resolve as resolve6 } from "path";
|
|
|
3194
3252
|
|
|
3195
3253
|
// src/recipes/convert-to-pnpm.ts
|
|
3196
3254
|
import { rm as rm3, stat as stat3 } from "fs/promises";
|
|
3197
|
-
import { join as
|
|
3255
|
+
import { join as join18 } from "path";
|
|
3198
3256
|
|
|
3199
3257
|
// src/recipes/convert-to-pnpm/script-rewrites.ts
|
|
3200
3258
|
function rewriteScriptForPnpm(script) {
|
|
@@ -3227,9 +3285,9 @@ async function exists2(path) {
|
|
|
3227
3285
|
async function convertToPnpm(site, opts = {}) {
|
|
3228
3286
|
const spawn2 = opts.spawn ?? defaultSpawn;
|
|
3229
3287
|
const pnpmVersion = opts.pnpmVersion ?? DEFAULT_PNPM_VERSION;
|
|
3230
|
-
const pnpmLockPath =
|
|
3231
|
-
const npmLockPath =
|
|
3232
|
-
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");
|
|
3233
3291
|
return withRecipe({
|
|
3234
3292
|
name: "convert-to-pnpm",
|
|
3235
3293
|
site,
|
|
@@ -3252,7 +3310,7 @@ async function convertToPnpm(site, opts = {}) {
|
|
|
3252
3310
|
if (hasYarnLock) await rm3(yarnLockPath, { force: true });
|
|
3253
3311
|
const sourceLock = hasNpmLock ? "package-lock.json" : "yarn.lock";
|
|
3254
3312
|
await commit2(`chore(pnpm): remove ${sourceLock}`);
|
|
3255
|
-
const pkgPath =
|
|
3313
|
+
const pkgPath = join18(cwd, "package.json");
|
|
3256
3314
|
const pkg = await readPackageJson(pkgPath);
|
|
3257
3315
|
const next = { ...pkg, packageManager: `pnpm@${pnpmVersion}` };
|
|
3258
3316
|
if (pkg.scripts && typeof pkg.scripts === "object") {
|
|
@@ -3265,7 +3323,7 @@ async function convertToPnpm(site, opts = {}) {
|
|
|
3265
3323
|
}
|
|
3266
3324
|
await writePackageJson(pkgPath, next);
|
|
3267
3325
|
await commit2("chore(pnpm): pin packageManager + rewrite npm scripts");
|
|
3268
|
-
await rm3(
|
|
3326
|
+
await rm3(join18(cwd, "node_modules"), { recursive: true, force: true });
|
|
3269
3327
|
const installResult = await spawn2("pnpm", ["install"], { cwd, streaming: true });
|
|
3270
3328
|
if (installResult.code !== 0) {
|
|
3271
3329
|
return { kind: "failed", notes: `pnpm install failed (exit ${installResult.code})` };
|
|
@@ -3306,19 +3364,19 @@ import { resolve as resolve7 } from "path";
|
|
|
3306
3364
|
|
|
3307
3365
|
// src/recipes/onboard.ts
|
|
3308
3366
|
import { stat as stat4 } from "fs/promises";
|
|
3309
|
-
import { join as
|
|
3367
|
+
import { join as join20 } from "path";
|
|
3310
3368
|
|
|
3311
3369
|
// src/util/self-version.ts
|
|
3312
|
-
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
3370
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
3313
3371
|
import { fileURLToPath } from "url";
|
|
3314
|
-
import { dirname, join as
|
|
3372
|
+
import { dirname, join as join19 } from "path";
|
|
3315
3373
|
function selfPackageVersion(callerImportMetaUrl) {
|
|
3316
3374
|
try {
|
|
3317
3375
|
let dir = dirname(fileURLToPath(callerImportMetaUrl));
|
|
3318
3376
|
while (true) {
|
|
3319
|
-
const candidate =
|
|
3377
|
+
const candidate = join19(dir, "package.json");
|
|
3320
3378
|
if (existsSync2(candidate)) {
|
|
3321
|
-
const raw =
|
|
3379
|
+
const raw = readFileSync2(candidate, "utf-8");
|
|
3322
3380
|
const pkg = JSON.parse(raw);
|
|
3323
3381
|
if (pkg.name === "@reddoorla/maintenance") {
|
|
3324
3382
|
return pkg.version ?? "0.0.0";
|
|
@@ -3375,13 +3433,13 @@ async function onboard(site, opts = {}) {
|
|
|
3375
3433
|
name: "onboard",
|
|
3376
3434
|
site,
|
|
3377
3435
|
plan: async () => {
|
|
3378
|
-
if (!await exists3(
|
|
3436
|
+
if (!await exists3(join20(site.path, "pnpm-lock.yaml"))) {
|
|
3379
3437
|
return {
|
|
3380
3438
|
kind: "failed",
|
|
3381
3439
|
notes: "no pnpm-lock.yaml at site root \u2014 run convert-to-pnpm first"
|
|
3382
3440
|
};
|
|
3383
3441
|
}
|
|
3384
|
-
const pkgPath =
|
|
3442
|
+
const pkgPath = join20(site.path, "package.json");
|
|
3385
3443
|
const pkg = await readPackageJson(pkgPath);
|
|
3386
3444
|
const toAdd = [];
|
|
3387
3445
|
if (!isDeclared(pkg, PACKAGE_NAME)) {
|
|
@@ -3401,7 +3459,7 @@ async function onboard(site, opts = {}) {
|
|
|
3401
3459
|
return { kind: "apply", plan: { pkg, toAdd } };
|
|
3402
3460
|
},
|
|
3403
3461
|
apply: async ({ pkg, toAdd }, { commit: commit2, cwd }) => {
|
|
3404
|
-
const pkgPath =
|
|
3462
|
+
const pkgPath = join20(cwd, "package.json");
|
|
3405
3463
|
let next = pkg;
|
|
3406
3464
|
for (const dep of toAdd) {
|
|
3407
3465
|
next = bumpDep(next, dep.name, dep.version);
|
|
@@ -3470,7 +3528,7 @@ import { resolve as resolve8 } from "path";
|
|
|
3470
3528
|
|
|
3471
3529
|
// src/recipes/svelte-codemods.ts
|
|
3472
3530
|
import { writeFile as writeFile8 } from "fs/promises";
|
|
3473
|
-
import { join as
|
|
3531
|
+
import { join as join21 } from "path";
|
|
3474
3532
|
async function svelteCodemods(site) {
|
|
3475
3533
|
return withRecipe({
|
|
3476
3534
|
name: "svelte-codemods",
|
|
@@ -3484,7 +3542,7 @@ async function svelteCodemods(site) {
|
|
|
3484
3542
|
},
|
|
3485
3543
|
apply: async (changes, { commit: commit2, cwd }) => {
|
|
3486
3544
|
for (const c of changes) {
|
|
3487
|
-
await writeFile8(
|
|
3545
|
+
await writeFile8(join21(cwd, c.rel), c.after, "utf-8");
|
|
3488
3546
|
}
|
|
3489
3547
|
await commit2(`refactor(svelte5): apply codemods (${changes.length} files)`);
|
|
3490
3548
|
return { kind: "ok" };
|
|
@@ -3711,7 +3769,7 @@ import { resolve as resolve9 } from "path";
|
|
|
3711
3769
|
|
|
3712
3770
|
// src/recipes/a11y-fixtures-page/index.ts
|
|
3713
3771
|
import { access, mkdir as mkdir3, writeFile as writeFile10 } from "fs/promises";
|
|
3714
|
-
import { dirname as dirname4, join as
|
|
3772
|
+
import { dirname as dirname4, join as join23 } from "path";
|
|
3715
3773
|
|
|
3716
3774
|
// src/recipes/a11y-fixtures-page/template.ts
|
|
3717
3775
|
var A11Y_FIXTURES_PAGE_RELATIVE = "src/routes/dev/a11y-fixtures/+page.svelte";
|
|
@@ -3762,7 +3820,7 @@ async function fileExists(path) {
|
|
|
3762
3820
|
}
|
|
3763
3821
|
}
|
|
3764
3822
|
async function a11yFixturesPage(site) {
|
|
3765
|
-
const target =
|
|
3823
|
+
const target = join23(site.path, A11Y_FIXTURES_PAGE_RELATIVE);
|
|
3766
3824
|
return withRecipe({
|
|
3767
3825
|
name: "a11y-fixtures-page",
|
|
3768
3826
|
site,
|
|
@@ -3869,15 +3927,15 @@ async function runInitCommand(site, opts) {
|
|
|
3869
3927
|
}
|
|
3870
3928
|
|
|
3871
3929
|
// src/cli/version.ts
|
|
3872
|
-
import { readFileSync as
|
|
3873
|
-
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";
|
|
3874
3932
|
function resolvePackageVersion(fromDir) {
|
|
3875
3933
|
try {
|
|
3876
3934
|
let dir = fromDir;
|
|
3877
3935
|
while (true) {
|
|
3878
|
-
const candidate =
|
|
3936
|
+
const candidate = join24(dir, "package.json");
|
|
3879
3937
|
if (existsSync4(candidate)) {
|
|
3880
|
-
const raw =
|
|
3938
|
+
const raw = readFileSync3(candidate, "utf-8");
|
|
3881
3939
|
const pkg = JSON.parse(raw);
|
|
3882
3940
|
if (pkg.name === "@reddoorla/maintenance") {
|
|
3883
3941
|
return pkg.version ?? "unknown";
|
|
@@ -3893,6 +3951,7 @@ function resolvePackageVersion(fromDir) {
|
|
|
3893
3951
|
}
|
|
3894
3952
|
|
|
3895
3953
|
// src/cli/bin.ts
|
|
3954
|
+
loadCredentialsIntoEnv();
|
|
3896
3955
|
var here = dirname6(fileURLToPath3(import.meta.url));
|
|
3897
3956
|
var version = resolvePackageVersion(here);
|
|
3898
3957
|
var AUDIT_DESCRIPTIONS = {
|