@reddoorla/maintenance 0.6.5 → 0.6.7
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 +221 -208
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/audit.js +12 -21
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +162 -127
- package/dist/index.js.map +1 -1
- package/dist/recipes/sync-configs.d.ts +1 -1
- package/dist/recipes/sync-configs.js +19 -5
- package/dist/recipes/sync-configs.js.map +1 -1
- package/dist/{sync-configs-DRmSAnfV.d.ts → sync-configs-pMPW4wTq.d.ts} +7 -1
- package/dist/util/git.js +2 -3
- package/dist/util/git.js.map +1 -1
- package/dist/util/pkg.js +11 -1
- package/dist/util/pkg.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/bin.js
CHANGED
|
@@ -41,6 +41,11 @@ var defaultSpawn = (cmd, args, opts = {}) => new Promise((resolve9, reject) => {
|
|
|
41
41
|
import { readFile } from "fs/promises";
|
|
42
42
|
import { join } from "path";
|
|
43
43
|
|
|
44
|
+
// src/util/site.ts
|
|
45
|
+
function siteLabel(site) {
|
|
46
|
+
return site.name ?? site.path;
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
// src/configs/baseline-versions.ts
|
|
45
50
|
var baselineVersions = {
|
|
46
51
|
// SvelteKit core
|
|
@@ -81,9 +86,6 @@ var baselineVersions = {
|
|
|
81
86
|
};
|
|
82
87
|
|
|
83
88
|
// src/audits/deps.ts
|
|
84
|
-
function siteLabel(site) {
|
|
85
|
-
return site.name ?? site.path;
|
|
86
|
-
}
|
|
87
89
|
function stripCaret(range) {
|
|
88
90
|
return range.replace(/^[\^~]/, "");
|
|
89
91
|
}
|
|
@@ -156,9 +158,6 @@ import { check as prettierCheck, resolveConfig as prettierResolveConfig } from "
|
|
|
156
158
|
import { glob } from "tinyglobby";
|
|
157
159
|
var TARGET_GLOBS = ["**/*.{ts,js,svelte}"];
|
|
158
160
|
var IGNORE = ["node_modules/**", "dist/**", ".svelte-kit/**", "build/**", ".netlify/**"];
|
|
159
|
-
function siteLabel2(site) {
|
|
160
|
-
return site.name ?? site.path;
|
|
161
|
-
}
|
|
162
161
|
async function listFiles(cwd) {
|
|
163
162
|
return glob(TARGET_GLOBS, { cwd, ignore: IGNORE, absolute: false });
|
|
164
163
|
}
|
|
@@ -168,7 +167,7 @@ async function lintAudit(ctx) {
|
|
|
168
167
|
if (!existsSync(configPath)) {
|
|
169
168
|
return {
|
|
170
169
|
audit: "lint",
|
|
171
|
-
site:
|
|
170
|
+
site: siteLabel(site),
|
|
172
171
|
status: "skip",
|
|
173
172
|
summary: "no eslint config at site root"
|
|
174
173
|
};
|
|
@@ -194,7 +193,7 @@ async function lintAudit(ctx) {
|
|
|
194
193
|
const summary = status === "pass" ? `lint clean across ${relFiles.length} files` : `${eslintErrors} eslint errors, ${eslintWarnings} warnings, ${prettierUnformatted.length} unformatted`;
|
|
195
194
|
return {
|
|
196
195
|
audit: "lint",
|
|
197
|
-
site:
|
|
196
|
+
site: siteLabel(site),
|
|
198
197
|
status,
|
|
199
198
|
summary,
|
|
200
199
|
details: {
|
|
@@ -207,9 +206,6 @@ async function lintAudit(ctx) {
|
|
|
207
206
|
}
|
|
208
207
|
|
|
209
208
|
// src/audits/security.ts
|
|
210
|
-
function siteLabel3(site) {
|
|
211
|
-
return site.name ?? site.path;
|
|
212
|
-
}
|
|
213
209
|
function classify(v) {
|
|
214
210
|
if (v.critical > 0 || v.high > 0) return "fail";
|
|
215
211
|
if (v.moderate > 0 || v.low > 0) return "warn";
|
|
@@ -295,7 +291,8 @@ async function runAuditTool(spawn2, cmd, args, cwd) {
|
|
|
295
291
|
if (errEnvelope && typeof errEnvelope === "object") {
|
|
296
292
|
return { kind: "error", reason: errEnvelope.code ?? "error envelope returned" };
|
|
297
293
|
}
|
|
298
|
-
|
|
294
|
+
const vulnsMeta = parsed.metadata?.vulnerabilities;
|
|
295
|
+
if (!vulnsMeta || Object.keys(vulnsMeta).length === 0) {
|
|
299
296
|
return { kind: "error", reason: "no metadata.vulnerabilities in output" };
|
|
300
297
|
}
|
|
301
298
|
return { kind: "ok", parsed };
|
|
@@ -303,7 +300,7 @@ async function runAuditTool(spawn2, cmd, args, cwd) {
|
|
|
303
300
|
async function securityAudit(ctx) {
|
|
304
301
|
const spawn2 = ctx.spawn ?? defaultSpawn;
|
|
305
302
|
const site = ctx.site;
|
|
306
|
-
const label =
|
|
303
|
+
const label = siteLabel(site);
|
|
307
304
|
let used = "pnpm audit";
|
|
308
305
|
let result = await runAuditTool(spawn2, "pnpm", ["audit", "--json", "--prod"], site.path);
|
|
309
306
|
if (result.kind !== "ok") {
|
|
@@ -384,9 +381,6 @@ var lighthouseConfig = {
|
|
|
384
381
|
};
|
|
385
382
|
|
|
386
383
|
// src/audits/lighthouse.ts
|
|
387
|
-
function siteLabel4(site) {
|
|
388
|
-
return site.name ?? site.path;
|
|
389
|
-
}
|
|
390
384
|
async function readJsonMaybe(path) {
|
|
391
385
|
try {
|
|
392
386
|
const raw = await readFile3(path, "utf-8");
|
|
@@ -424,7 +418,7 @@ function messageForAssertion(a) {
|
|
|
424
418
|
async function lighthouseAudit(ctx) {
|
|
425
419
|
const spawn2 = ctx.spawn ?? defaultSpawn;
|
|
426
420
|
const site = ctx.site;
|
|
427
|
-
const label =
|
|
421
|
+
const label = siteLabel(site);
|
|
428
422
|
const configDir = await mkdtemp(join3(tmpdir(), "reddoor-lhci-"));
|
|
429
423
|
const configPath = join3(configDir, "lighthouserc.json");
|
|
430
424
|
await writeFile(configPath, JSON.stringify(lighthouseConfig), "utf-8");
|
|
@@ -522,9 +516,6 @@ var playwrightA11yConfig = defineConfig({
|
|
|
522
516
|
|
|
523
517
|
// src/audits/a11y.ts
|
|
524
518
|
var RESULTS_REL = ".reddoor-a11y/results.json";
|
|
525
|
-
function siteLabel5(site) {
|
|
526
|
-
return site.name ?? site.path;
|
|
527
|
-
}
|
|
528
519
|
async function readJsonMaybe2(path) {
|
|
529
520
|
try {
|
|
530
521
|
const raw = await readFile4(path, "utf-8");
|
|
@@ -582,7 +573,7 @@ test("a11y across configured routes", async ({ page }) => {
|
|
|
582
573
|
async function a11yAudit(ctx) {
|
|
583
574
|
const spawn2 = ctx.spawn ?? defaultSpawn;
|
|
584
575
|
const site = ctx.site;
|
|
585
|
-
const label =
|
|
576
|
+
const label = siteLabel(site);
|
|
586
577
|
const specDir = await mkdtemp2(join4(tmpdir2(), "reddoor-a11y-spec-"));
|
|
587
578
|
const specPath = join4(specDir, "a11y.spec.ts");
|
|
588
579
|
await writeFile2(specPath, buildSpec(), "utf-8");
|
|
@@ -1007,9 +998,8 @@ async function git(cwd, args) {
|
|
|
1007
998
|
return exec("git", args, { cwd, env: process.env });
|
|
1008
999
|
}
|
|
1009
1000
|
function branchName(recipe, when = /* @__PURE__ */ new Date()) {
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
return `maint/${recipe}-${trimmed}`;
|
|
1001
|
+
const compact = when.toISOString().replace(/[-:.]/g, "");
|
|
1002
|
+
return `maint/${recipe}-${compact}`;
|
|
1013
1003
|
}
|
|
1014
1004
|
async function isWorkingTreeClean(cwd) {
|
|
1015
1005
|
const { stdout } = await git(cwd, ["status", "--porcelain"]);
|
|
@@ -1040,8 +1030,16 @@ async function commit(cwd, message) {
|
|
|
1040
1030
|
|
|
1041
1031
|
// src/recipes/sync-configs.ts
|
|
1042
1032
|
var GITIGNORE_CONFIG = "gitignore";
|
|
1043
|
-
|
|
1044
|
-
|
|
1033
|
+
var ALL_CONFIG_NAMES = [
|
|
1034
|
+
"lighthouse",
|
|
1035
|
+
"eslint",
|
|
1036
|
+
"prettier",
|
|
1037
|
+
"playwright-a11y",
|
|
1038
|
+
"svelte",
|
|
1039
|
+
"gitignore"
|
|
1040
|
+
];
|
|
1041
|
+
function isConfigName(value) {
|
|
1042
|
+
return ALL_CONFIG_NAMES.includes(value);
|
|
1045
1043
|
}
|
|
1046
1044
|
async function readMaybe(path) {
|
|
1047
1045
|
try {
|
|
@@ -1073,7 +1071,7 @@ async function applyGitignore(cwd, plan) {
|
|
|
1073
1071
|
}
|
|
1074
1072
|
}
|
|
1075
1073
|
async function syncConfigs(site, opts = {}) {
|
|
1076
|
-
const label =
|
|
1074
|
+
const label = siteLabel(site);
|
|
1077
1075
|
const requested = opts.which ?? ALL_TEMPLATES.map((t) => t.config).concat(GITIGNORE_CONFIG);
|
|
1078
1076
|
const templateNames = requested.filter((c) => c !== GITIGNORE_CONFIG);
|
|
1079
1077
|
const templates = templatesByName(templateNames);
|
|
@@ -1119,12 +1117,34 @@ async function syncConfigs(site, opts = {}) {
|
|
|
1119
1117
|
|
|
1120
1118
|
// src/cli/commands/sync-configs.ts
|
|
1121
1119
|
function parseOnly2(value) {
|
|
1122
|
-
|
|
1120
|
+
if (!value) return void 0;
|
|
1121
|
+
const names = value.split(",").map((s) => s.trim());
|
|
1122
|
+
for (const n of names) {
|
|
1123
|
+
if (!isConfigName(n)) {
|
|
1124
|
+
throw Object.assign(
|
|
1125
|
+
new Error(`unknown config in --only: "${n}". Valid: ${ALL_CONFIG_NAMES.join(", ")}`),
|
|
1126
|
+
{ exitCode: 2 }
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
return names;
|
|
1131
|
+
}
|
|
1132
|
+
async function dryPlanGitignore(cwd) {
|
|
1133
|
+
let existing;
|
|
1134
|
+
try {
|
|
1135
|
+
existing = await readFile7(join7(cwd, ".gitignore"), "utf-8");
|
|
1136
|
+
} catch {
|
|
1137
|
+
return "would create .gitignore";
|
|
1138
|
+
}
|
|
1139
|
+
const merge = mergeGitignore(existing, CANONICAL_GITIGNORE_ENTRIES);
|
|
1140
|
+
if (merge.added.length === 0) return null;
|
|
1141
|
+
return `would update .gitignore (${merge.added.length} canonical entries to add)`;
|
|
1123
1142
|
}
|
|
1124
1143
|
async function dryPlan(cwd, which) {
|
|
1125
|
-
const
|
|
1144
|
+
const includeGitignore = which ? which.includes("gitignore") : true;
|
|
1145
|
+
const templateTargets = which ? templatesByName(which.filter((c) => c !== "gitignore")) : ALL_TEMPLATES;
|
|
1126
1146
|
const lines = [];
|
|
1127
|
-
for (const t of
|
|
1147
|
+
for (const t of templateTargets) {
|
|
1128
1148
|
let existing = "";
|
|
1129
1149
|
try {
|
|
1130
1150
|
existing = await readFile7(join7(cwd, t.path), "utf-8");
|
|
@@ -1132,6 +1152,10 @@ async function dryPlan(cwd, which) {
|
|
|
1132
1152
|
}
|
|
1133
1153
|
if (existing !== t.contents) lines.push(`would update ${t.path} (config: ${t.config})`);
|
|
1134
1154
|
}
|
|
1155
|
+
if (includeGitignore) {
|
|
1156
|
+
const gi = await dryPlanGitignore(cwd);
|
|
1157
|
+
if (gi) lines.push(gi);
|
|
1158
|
+
}
|
|
1135
1159
|
return lines.length === 0 ? "no changes needed" : lines.join("\n");
|
|
1136
1160
|
}
|
|
1137
1161
|
function formatResult(r) {
|
|
@@ -1170,8 +1194,15 @@ async function runSyncConfigsCommand(site, opts) {
|
|
|
1170
1194
|
import { resolve as resolve4 } from "path";
|
|
1171
1195
|
|
|
1172
1196
|
// src/recipes/bump-deps.ts
|
|
1173
|
-
|
|
1174
|
-
|
|
1197
|
+
import { stat as stat2 } from "fs/promises";
|
|
1198
|
+
import { join as join8 } from "path";
|
|
1199
|
+
async function exists(path) {
|
|
1200
|
+
try {
|
|
1201
|
+
await stat2(path);
|
|
1202
|
+
return true;
|
|
1203
|
+
} catch {
|
|
1204
|
+
return false;
|
|
1205
|
+
}
|
|
1175
1206
|
}
|
|
1176
1207
|
function outdatedFlagsForGroup(group) {
|
|
1177
1208
|
if (group === "major") return ["--latest"];
|
|
@@ -1183,9 +1214,27 @@ function upFlagsForGroup(group) {
|
|
|
1183
1214
|
return [];
|
|
1184
1215
|
}
|
|
1185
1216
|
async function bumpDeps(site, opts = {}) {
|
|
1186
|
-
const label =
|
|
1217
|
+
const label = siteLabel(site);
|
|
1187
1218
|
const group = opts.group ?? "minor";
|
|
1188
1219
|
const spawn2 = opts.spawn ?? defaultSpawn;
|
|
1220
|
+
const hasPnpmLock = await exists(join8(site.path, "pnpm-lock.yaml"));
|
|
1221
|
+
if (!hasPnpmLock) {
|
|
1222
|
+
const hasNpmLock = await exists(join8(site.path, "package-lock.json"));
|
|
1223
|
+
const hasYarnLock = await exists(join8(site.path, "yarn.lock"));
|
|
1224
|
+
if (hasNpmLock || hasYarnLock) {
|
|
1225
|
+
const competing = hasNpmLock ? "package-lock.json" : "yarn.lock";
|
|
1226
|
+
return {
|
|
1227
|
+
recipe: "bump-deps",
|
|
1228
|
+
site: label,
|
|
1229
|
+
status: "failed",
|
|
1230
|
+
commits: [],
|
|
1231
|
+
notes: `site has ${competing} but no pnpm-lock.yaml \u2014 run convert-to-pnpm first`
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
if (!await isWorkingTreeClean(site.path)) {
|
|
1236
|
+
throw new Error(`refusing to run: working tree is not clean at ${site.path}`);
|
|
1237
|
+
}
|
|
1189
1238
|
await spawn2("pnpm", ["install"], { cwd: site.path, streaming: true });
|
|
1190
1239
|
const outdated = await spawn2("pnpm", ["outdated", "--json", ...outdatedFlagsForGroup(group)], {
|
|
1191
1240
|
cwd: site.path
|
|
@@ -1206,9 +1255,6 @@ async function bumpDeps(site, opts = {}) {
|
|
|
1206
1255
|
notes: `pnpm outdated reported nothing for group=${group}`
|
|
1207
1256
|
};
|
|
1208
1257
|
}
|
|
1209
|
-
if (!await isWorkingTreeClean(site.path)) {
|
|
1210
|
-
throw new Error(`refusing to run: working tree is not clean at ${site.path}`);
|
|
1211
|
-
}
|
|
1212
1258
|
const branch = branchName("bump-deps");
|
|
1213
1259
|
await createBranch(site.path, branch);
|
|
1214
1260
|
await spawn2("pnpm", ["up", ...upFlagsForGroup(group)], {
|
|
@@ -1262,7 +1308,7 @@ async function runBumpDepsCommand(site, opts) {
|
|
|
1262
1308
|
import { resolve as resolve5 } from "path";
|
|
1263
1309
|
|
|
1264
1310
|
// src/recipes/svelte-5/index.ts
|
|
1265
|
-
import { join as
|
|
1311
|
+
import { join as join14 } from "path";
|
|
1266
1312
|
|
|
1267
1313
|
// src/util/pkg.ts
|
|
1268
1314
|
import { readFile as readFile8, writeFile as writeFile4 } from "fs/promises";
|
|
@@ -1270,8 +1316,18 @@ async function readPackageJson(path) {
|
|
|
1270
1316
|
const raw = await readFile8(path, "utf-8");
|
|
1271
1317
|
return JSON.parse(raw);
|
|
1272
1318
|
}
|
|
1319
|
+
function detectIndentFromContent(raw) {
|
|
1320
|
+
const match = raw.match(/\n([ \t]+)"/);
|
|
1321
|
+
return match ? match[1] ?? " " : " ";
|
|
1322
|
+
}
|
|
1273
1323
|
async function writePackageJson(path, pkg) {
|
|
1274
|
-
|
|
1324
|
+
let indent = " ";
|
|
1325
|
+
try {
|
|
1326
|
+
const existing = await readFile8(path, "utf-8");
|
|
1327
|
+
indent = detectIndentFromContent(existing);
|
|
1328
|
+
} catch {
|
|
1329
|
+
}
|
|
1330
|
+
const content = JSON.stringify(pkg, null, indent) + "\n";
|
|
1275
1331
|
await writeFile4(path, content, "utf-8");
|
|
1276
1332
|
}
|
|
1277
1333
|
function bumpDep(pkg, name, version2, opts = {}) {
|
|
@@ -1301,7 +1357,7 @@ function bumpDep(pkg, name, version2, opts = {}) {
|
|
|
1301
1357
|
}
|
|
1302
1358
|
|
|
1303
1359
|
// src/recipes/svelte-5/step-bump-versions.ts
|
|
1304
|
-
import { join as
|
|
1360
|
+
import { join as join9 } from "path";
|
|
1305
1361
|
var SVELTE_5_VERSIONS = {
|
|
1306
1362
|
svelte: "^5.55.5",
|
|
1307
1363
|
"@sveltejs/kit": "^2.59.0",
|
|
@@ -1314,7 +1370,7 @@ var SVELTE_5_VERSIONS = {
|
|
|
1314
1370
|
"typescript-svelte-plugin": "^0.3.52"
|
|
1315
1371
|
};
|
|
1316
1372
|
async function bumpToSvelte5Versions(cwd) {
|
|
1317
|
-
const pkgPath =
|
|
1373
|
+
const pkgPath = join9(cwd, "package.json");
|
|
1318
1374
|
const pkg = await readPackageJson(pkgPath);
|
|
1319
1375
|
let next = pkg;
|
|
1320
1376
|
for (const [name, version2] of Object.entries(SVELTE_5_VERSIONS)) {
|
|
@@ -1327,7 +1383,7 @@ async function bumpToSvelte5Versions(cwd) {
|
|
|
1327
1383
|
|
|
1328
1384
|
// src/recipes/svelte-5/step-svelte-config.ts
|
|
1329
1385
|
import { readFile as readFile9, writeFile as writeFile5 } from "fs/promises";
|
|
1330
|
-
import { join as
|
|
1386
|
+
import { join as join10 } from "path";
|
|
1331
1387
|
var VITE_PLUGIN_PKG = "@sveltejs/vite-plugin-svelte";
|
|
1332
1388
|
var IMPORT_FROM_VITE_PLUGIN = new RegExp(
|
|
1333
1389
|
String.raw`^import\s+\{\s*([^}]+?)\s*\}\s+from\s+["']` + VITE_PLUGIN_PKG.replace(/[/]/g, "\\/") + String.raw`["'];?[ \t]*\n`,
|
|
@@ -1368,7 +1424,7 @@ function dropPreprocessKey(source) {
|
|
|
1368
1424
|
return source.slice(0, m.index) + source.slice(tailIdx).replace(new RegExp(`^${indent}\\n`), "");
|
|
1369
1425
|
}
|
|
1370
1426
|
async function migrateSvelteConfig(cwd) {
|
|
1371
|
-
const path =
|
|
1427
|
+
const path = join10(cwd, "svelte.config.js");
|
|
1372
1428
|
let src;
|
|
1373
1429
|
try {
|
|
1374
1430
|
src = await readFile9(path, "utf-8");
|
|
@@ -1405,9 +1461,9 @@ async function runSvelteMigrate(cwd, spawn2 = defaultSpawn) {
|
|
|
1405
1461
|
}
|
|
1406
1462
|
|
|
1407
1463
|
// src/recipes/svelte-5/step-tailwind-upgrade.ts
|
|
1408
|
-
import { join as
|
|
1464
|
+
import { join as join11 } from "path";
|
|
1409
1465
|
async function upgradeTailwind(cwd, spawn2 = defaultSpawn) {
|
|
1410
|
-
const pkg = await readPackageJson(
|
|
1466
|
+
const pkg = await readPackageJson(join11(cwd, "package.json"));
|
|
1411
1467
|
const tailwindVersion = pkg.devDependencies?.tailwindcss ?? pkg.dependencies?.tailwindcss;
|
|
1412
1468
|
if (!tailwindVersion) return { ran: false, reason: "tailwindcss not installed" };
|
|
1413
1469
|
if (/^\^?4\./.test(tailwindVersion)) return { ran: false, reason: "already on tailwind 4.x" };
|
|
@@ -1429,12 +1485,40 @@ async function upgradeTailwind(cwd, spawn2 = defaultSpawn) {
|
|
|
1429
1485
|
|
|
1430
1486
|
// src/recipes/svelte-5/step-gotchas.ts
|
|
1431
1487
|
import { readFile as readFile10, writeFile as writeFile6 } from "fs/promises";
|
|
1432
|
-
import { join as
|
|
1488
|
+
import { join as join12 } from "path";
|
|
1433
1489
|
import { glob as glob2 } from "tinyglobby";
|
|
1434
1490
|
|
|
1435
1491
|
// src/recipes/svelte-5/codemods/on-event-to-handler.ts
|
|
1436
1492
|
var SCRIPT_BLOCK = /<script\b[^>]*>[\s\S]*?<\/script>/g;
|
|
1437
1493
|
var SIMPLE_ON_EVENT = /\bon:([a-z]+)(?=\s*=)/g;
|
|
1494
|
+
var MODIFIER_EVENT = /\bon:[a-z]+\|[a-zA-Z]+(?=\s*=)/g;
|
|
1495
|
+
function flagEventModifiers(source) {
|
|
1496
|
+
const insertions = [];
|
|
1497
|
+
let m;
|
|
1498
|
+
MODIFIER_EVENT.lastIndex = 0;
|
|
1499
|
+
while ((m = MODIFIER_EVENT.exec(source)) !== null) {
|
|
1500
|
+
const tagStart = source.lastIndexOf("<", m.index);
|
|
1501
|
+
if (tagStart === -1) continue;
|
|
1502
|
+
const prevLineEnd = tagStart - 1;
|
|
1503
|
+
if (prevLineEnd >= 0) {
|
|
1504
|
+
const prevLineStart = source.lastIndexOf("\n", prevLineEnd - 1) + 1;
|
|
1505
|
+
const prevLine = source.slice(prevLineStart, prevLineEnd + 1);
|
|
1506
|
+
if (/<!--\s*@migration-task/.test(prevLine)) continue;
|
|
1507
|
+
}
|
|
1508
|
+
const lineStart = source.lastIndexOf("\n", tagStart - 1) + 1;
|
|
1509
|
+
const indent = source.slice(lineStart, tagStart);
|
|
1510
|
+
const safeIndent = /^[ \t]*$/.test(indent) ? indent : "";
|
|
1511
|
+
insertions.push({ tagStart, indent: safeIndent, modifier: m[0] });
|
|
1512
|
+
}
|
|
1513
|
+
let out = source;
|
|
1514
|
+
for (let i = insertions.length - 1; i >= 0; i--) {
|
|
1515
|
+
const { tagStart, indent, modifier } = insertions[i];
|
|
1516
|
+
const comment = `<!-- @migration-task: Svelte 5 removed event modifier syntax (\`${modifier}\`). Rewrite inline, e.g. onclick={(e) => { e.preventDefault(); ... }}. -->
|
|
1517
|
+
${indent}`;
|
|
1518
|
+
out = out.slice(0, tagStart) + comment + out.slice(tagStart);
|
|
1519
|
+
}
|
|
1520
|
+
return out;
|
|
1521
|
+
}
|
|
1438
1522
|
function onEventToHandler(source) {
|
|
1439
1523
|
const masked = [];
|
|
1440
1524
|
const placeholder = (i) => ` SCRIPT_${i} `;
|
|
@@ -1442,8 +1526,9 @@ function onEventToHandler(source) {
|
|
|
1442
1526
|
masked.push(match);
|
|
1443
1527
|
return placeholder(masked.length - 1);
|
|
1444
1528
|
});
|
|
1445
|
-
|
|
1446
|
-
|
|
1529
|
+
let processed = intermediate.replace(SIMPLE_ON_EVENT, (_full, name) => `on${name}`);
|
|
1530
|
+
processed = flagEventModifiers(processed);
|
|
1531
|
+
let out = processed;
|
|
1447
1532
|
masked.forEach((blk, i) => {
|
|
1448
1533
|
out = out.replace(placeholder(i), blk);
|
|
1449
1534
|
});
|
|
@@ -1493,6 +1578,22 @@ function exportLetToProps(source) {
|
|
|
1493
1578
|
return source.replace(SCRIPT_BLOCK2, (full) => full.replace(inner, body));
|
|
1494
1579
|
}
|
|
1495
1580
|
|
|
1581
|
+
// src/util/svelte-source.ts
|
|
1582
|
+
function findStringEnd(source, openIdx) {
|
|
1583
|
+
const quote = source[openIdx];
|
|
1584
|
+
let i = openIdx + 1;
|
|
1585
|
+
while (i < source.length) {
|
|
1586
|
+
const ch = source[i];
|
|
1587
|
+
if (ch === "\\") {
|
|
1588
|
+
i += 2;
|
|
1589
|
+
continue;
|
|
1590
|
+
}
|
|
1591
|
+
if (ch === quote) return i;
|
|
1592
|
+
i++;
|
|
1593
|
+
}
|
|
1594
|
+
return -1;
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1496
1597
|
// src/recipes/svelte-5/codemods/dollar-restprops.ts
|
|
1497
1598
|
function removeInterfaceBlock(source) {
|
|
1498
1599
|
const re = /^\s*interface\s+\$\$Props\s*\{/m;
|
|
@@ -1516,20 +1617,6 @@ function removeInterfaceBlock(source) {
|
|
|
1516
1617
|
out = out.slice(0, match.index) + out.slice(endIdx);
|
|
1517
1618
|
}
|
|
1518
1619
|
}
|
|
1519
|
-
function findStringEnd(source, openIdx) {
|
|
1520
|
-
const quote = source[openIdx];
|
|
1521
|
-
let i = openIdx + 1;
|
|
1522
|
-
while (i < source.length) {
|
|
1523
|
-
const ch = source[i];
|
|
1524
|
-
if (ch === "\\") {
|
|
1525
|
-
i += 2;
|
|
1526
|
-
continue;
|
|
1527
|
-
}
|
|
1528
|
-
if (ch === quote) return i;
|
|
1529
|
-
i++;
|
|
1530
|
-
}
|
|
1531
|
-
return -1;
|
|
1532
|
-
}
|
|
1533
1620
|
function maskStringLiterals(source) {
|
|
1534
1621
|
const strings = [];
|
|
1535
1622
|
let out = "";
|
|
@@ -1606,7 +1693,8 @@ function stateEffectSyncToDerived(source) {
|
|
|
1606
1693
|
|
|
1607
1694
|
// src/recipes/svelte-5/codemods/dollar-props-class.ts
|
|
1608
1695
|
var PROPS_DESTRUCTURE = /let\s*\{([\s\S]*?)\}(\s*:\s*\{([\s\S]*?)\})?\s*=\s*\$props\(\)/;
|
|
1609
|
-
var
|
|
1696
|
+
var HAS_DOLLAR_PROPS_CLASS = /\$\$props\.class\b/;
|
|
1697
|
+
var DOLLAR_PROPS_CLASS_GLOBAL = /\$\$props\.class\b/g;
|
|
1610
1698
|
var DOLLAR_PROPS_ANY = /\$\$props\b/;
|
|
1611
1699
|
var SCRIPT_BLOCK4 = /<script\b[^>]*>[\s\S]*?<\/script>/g;
|
|
1612
1700
|
var MIGRATION_TASK = /^<!--\s*@migration-task[\s\S]*?-->\s*\n?/gm;
|
|
@@ -1628,8 +1716,7 @@ function restoreScripts(masked, blocks) {
|
|
|
1628
1716
|
}
|
|
1629
1717
|
function dollarPropsClass(source) {
|
|
1630
1718
|
const { masked } = maskScripts(source);
|
|
1631
|
-
if (!
|
|
1632
|
-
DOLLAR_PROPS_CLASS.lastIndex = 0;
|
|
1719
|
+
if (!HAS_DOLLAR_PROPS_CLASS.test(masked)) return source;
|
|
1633
1720
|
if (!PROPS_DESTRUCTURE.test(source)) return source;
|
|
1634
1721
|
let updated = source.replace(PROPS_DESTRUCTURE, (full, body, typeAnno, typeBody) => {
|
|
1635
1722
|
if (/\bclass\s*:/.test(body)) return full;
|
|
@@ -1643,7 +1730,7 @@ function dollarPropsClass(source) {
|
|
|
1643
1730
|
return `let { ${newBody} } = $props()`;
|
|
1644
1731
|
});
|
|
1645
1732
|
const reMasked = maskScripts(updated);
|
|
1646
|
-
const templateRewritten = reMasked.masked.replace(
|
|
1733
|
+
const templateRewritten = reMasked.masked.replace(DOLLAR_PROPS_CLASS_GLOBAL, IDENT);
|
|
1647
1734
|
updated = restoreScripts(templateRewritten, reMasked.blocks);
|
|
1648
1735
|
const stripped = updated.replace(MIGRATION_TASK, "");
|
|
1649
1736
|
if (!DOLLAR_PROPS_ANY.test(stripped)) {
|
|
@@ -1662,7 +1749,7 @@ function findMatchingClose(source, openIdx) {
|
|
|
1662
1749
|
while (i < source.length) {
|
|
1663
1750
|
const ch = source[i];
|
|
1664
1751
|
if (ch === '"' || ch === "'" || ch === "`") {
|
|
1665
|
-
const closeStr =
|
|
1752
|
+
const closeStr = findStringEnd(source, i);
|
|
1666
1753
|
if (closeStr === -1) return -1;
|
|
1667
1754
|
i = closeStr + 1;
|
|
1668
1755
|
continue;
|
|
@@ -1676,20 +1763,6 @@ function findMatchingClose(source, openIdx) {
|
|
|
1676
1763
|
}
|
|
1677
1764
|
return -1;
|
|
1678
1765
|
}
|
|
1679
|
-
function findStringClose(source, openIdx) {
|
|
1680
|
-
const quote = source[openIdx];
|
|
1681
|
-
let i = openIdx + 1;
|
|
1682
|
-
while (i < source.length) {
|
|
1683
|
-
const ch = source[i];
|
|
1684
|
-
if (ch === "\\") {
|
|
1685
|
-
i += 2;
|
|
1686
|
-
continue;
|
|
1687
|
-
}
|
|
1688
|
-
if (ch === quote) return i;
|
|
1689
|
-
i++;
|
|
1690
|
-
}
|
|
1691
|
-
return -1;
|
|
1692
|
-
}
|
|
1693
1766
|
var MIGRATION_MARKER = "// @migration-task: $effect won't trigger UI updates on plain `let` bindings \u2014 refine mutated locals to $state or split into per-variable $derived.";
|
|
1694
1767
|
function transformBlocks(body) {
|
|
1695
1768
|
const out = [];
|
|
@@ -1744,7 +1817,7 @@ async function planGotchaCodemods(cwd) {
|
|
|
1744
1817
|
const changes = [];
|
|
1745
1818
|
const relPaths = await glob2(SVELTE_GLOBS, { cwd, ignore: IGNORE2, absolute: false });
|
|
1746
1819
|
for (const rel of relPaths) {
|
|
1747
|
-
const path =
|
|
1820
|
+
const path = join12(cwd, rel);
|
|
1748
1821
|
const before = await readFile10(path, "utf-8");
|
|
1749
1822
|
const after = CODEMODS.reduce((s, fn) => fn(s), before);
|
|
1750
1823
|
if (after !== before) changes.push({ rel, after });
|
|
@@ -1754,7 +1827,7 @@ async function planGotchaCodemods(cwd) {
|
|
|
1754
1827
|
async function applyGotchaCodemods(cwd) {
|
|
1755
1828
|
const changes = await planGotchaCodemods(cwd);
|
|
1756
1829
|
for (const c of changes) {
|
|
1757
|
-
await writeFile6(
|
|
1830
|
+
await writeFile6(join12(cwd, c.rel), c.after, "utf-8");
|
|
1758
1831
|
}
|
|
1759
1832
|
return { filesChanged: changes.length };
|
|
1760
1833
|
}
|
|
@@ -1778,7 +1851,7 @@ async function verifyMigration(cwd, spawn2 = defaultSpawn) {
|
|
|
1778
1851
|
|
|
1779
1852
|
// src/recipes/svelte-5/step-summary.ts
|
|
1780
1853
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
1781
|
-
import { join as
|
|
1854
|
+
import { join as join13 } from "path";
|
|
1782
1855
|
async function writeMigrationSummary(input) {
|
|
1783
1856
|
const lines = [
|
|
1784
1857
|
`# Svelte 4 \u2192 5 migration summary`,
|
|
@@ -1795,18 +1868,15 @@ async function writeMigrationSummary(input) {
|
|
|
1795
1868
|
`- Verify Playwright a11y tests still pass.`
|
|
1796
1869
|
];
|
|
1797
1870
|
const content = lines.join("\n") + "\n";
|
|
1798
|
-
const path =
|
|
1871
|
+
const path = join13(input.cwd, "MIGRATION_SVELTE_5.md");
|
|
1799
1872
|
await writeFile7(path, content, "utf-8");
|
|
1800
1873
|
return path;
|
|
1801
1874
|
}
|
|
1802
1875
|
|
|
1803
1876
|
// src/recipes/svelte-5/index.ts
|
|
1804
|
-
function siteLabel8(site) {
|
|
1805
|
-
return site.name ?? site.path;
|
|
1806
|
-
}
|
|
1807
1877
|
async function alreadyOnSvelte5(cwd) {
|
|
1808
1878
|
try {
|
|
1809
|
-
const pkg = await readPackageJson(
|
|
1879
|
+
const pkg = await readPackageJson(join14(cwd, "package.json"));
|
|
1810
1880
|
const v = pkg.devDependencies?.svelte ?? pkg.dependencies?.svelte;
|
|
1811
1881
|
return !!v && /^\^?5\./.test(v);
|
|
1812
1882
|
} catch {
|
|
@@ -1814,7 +1884,7 @@ async function alreadyOnSvelte5(cwd) {
|
|
|
1814
1884
|
}
|
|
1815
1885
|
}
|
|
1816
1886
|
async function upgradeSvelte4to5(site, opts = {}) {
|
|
1817
|
-
const label =
|
|
1887
|
+
const label = siteLabel(site);
|
|
1818
1888
|
const spawn2 = opts.spawn ?? defaultSpawn;
|
|
1819
1889
|
if (await alreadyOnSvelte5(site.path)) {
|
|
1820
1890
|
return {
|
|
@@ -1923,8 +1993,8 @@ async function runUpgradeCommand(upgradeName, site, opts = {}) {
|
|
|
1923
1993
|
import { resolve as resolve6 } from "path";
|
|
1924
1994
|
|
|
1925
1995
|
// src/recipes/convert-to-pnpm.ts
|
|
1926
|
-
import { rm as rm3, stat as
|
|
1927
|
-
import { join as
|
|
1996
|
+
import { rm as rm3, stat as stat3 } from "fs/promises";
|
|
1997
|
+
import { join as join15 } from "path";
|
|
1928
1998
|
|
|
1929
1999
|
// src/recipes/convert-to-pnpm/script-rewrites.ts
|
|
1930
2000
|
function rewriteScriptForPnpm(script) {
|
|
@@ -1946,25 +2016,22 @@ function rewriteScriptsForPnpm(scripts) {
|
|
|
1946
2016
|
|
|
1947
2017
|
// src/recipes/convert-to-pnpm.ts
|
|
1948
2018
|
var DEFAULT_PNPM_VERSION = "10.33.1";
|
|
1949
|
-
async function
|
|
2019
|
+
async function exists2(path) {
|
|
1950
2020
|
try {
|
|
1951
|
-
await
|
|
2021
|
+
await stat3(path);
|
|
1952
2022
|
return true;
|
|
1953
2023
|
} catch {
|
|
1954
2024
|
return false;
|
|
1955
2025
|
}
|
|
1956
2026
|
}
|
|
1957
|
-
function siteLabel9(site) {
|
|
1958
|
-
return site.name ?? site.path;
|
|
1959
|
-
}
|
|
1960
2027
|
async function convertToPnpm(site, opts = {}) {
|
|
1961
|
-
const label =
|
|
2028
|
+
const label = siteLabel(site);
|
|
1962
2029
|
const spawn2 = opts.spawn ?? defaultSpawn;
|
|
1963
2030
|
const pnpmVersion = opts.pnpmVersion ?? DEFAULT_PNPM_VERSION;
|
|
1964
|
-
const pnpmLockPath =
|
|
1965
|
-
const npmLockPath =
|
|
1966
|
-
const yarnLockPath =
|
|
1967
|
-
if (await
|
|
2031
|
+
const pnpmLockPath = join15(site.path, "pnpm-lock.yaml");
|
|
2032
|
+
const npmLockPath = join15(site.path, "package-lock.json");
|
|
2033
|
+
const yarnLockPath = join15(site.path, "yarn.lock");
|
|
2034
|
+
if (await exists2(pnpmLockPath)) {
|
|
1968
2035
|
return {
|
|
1969
2036
|
recipe: "convert-to-pnpm",
|
|
1970
2037
|
site: label,
|
|
@@ -1973,8 +2040,8 @@ async function convertToPnpm(site, opts = {}) {
|
|
|
1973
2040
|
notes: "site already has pnpm-lock.yaml"
|
|
1974
2041
|
};
|
|
1975
2042
|
}
|
|
1976
|
-
const hasNpmLock = await
|
|
1977
|
-
const hasYarnLock = await
|
|
2043
|
+
const hasNpmLock = await exists2(npmLockPath);
|
|
2044
|
+
const hasYarnLock = await exists2(yarnLockPath);
|
|
1978
2045
|
if (!hasNpmLock && !hasYarnLock) {
|
|
1979
2046
|
return {
|
|
1980
2047
|
recipe: "convert-to-pnpm",
|
|
@@ -1995,7 +2062,7 @@ async function convertToPnpm(site, opts = {}) {
|
|
|
1995
2062
|
const sourceLock = hasNpmLock ? "package-lock.json" : "yarn.lock";
|
|
1996
2063
|
const lockSha = await commit(site.path, `chore(pnpm): remove ${sourceLock}`);
|
|
1997
2064
|
if (lockSha) shas.push(lockSha);
|
|
1998
|
-
const pkgPath =
|
|
2065
|
+
const pkgPath = join15(site.path, "package.json");
|
|
1999
2066
|
const pkg = await readPackageJson(pkgPath);
|
|
2000
2067
|
const next = { ...pkg, packageManager: `pnpm@${pnpmVersion}` };
|
|
2001
2068
|
if (pkg.scripts && typeof pkg.scripts === "object") {
|
|
@@ -2009,7 +2076,7 @@ async function convertToPnpm(site, opts = {}) {
|
|
|
2009
2076
|
await writePackageJson(pkgPath, next);
|
|
2010
2077
|
const pkgSha = await commit(site.path, "chore(pnpm): pin packageManager + rewrite npm scripts");
|
|
2011
2078
|
if (pkgSha) shas.push(pkgSha);
|
|
2012
|
-
await rm3(
|
|
2079
|
+
await rm3(join15(site.path, "node_modules"), { recursive: true, force: true });
|
|
2013
2080
|
const installResult = await spawn2("pnpm", ["install"], {
|
|
2014
2081
|
cwd: site.path,
|
|
2015
2082
|
streaming: true
|
|
@@ -2063,17 +2130,17 @@ async function runConvertToPnpmCommand(site, opts) {
|
|
|
2063
2130
|
import { resolve as resolve7 } from "path";
|
|
2064
2131
|
|
|
2065
2132
|
// src/recipes/onboard.ts
|
|
2066
|
-
import { stat as
|
|
2067
|
-
import { join as
|
|
2133
|
+
import { stat as stat4 } from "fs/promises";
|
|
2134
|
+
import { join as join17 } from "path";
|
|
2068
2135
|
|
|
2069
2136
|
// src/util/self-version.ts
|
|
2070
2137
|
import { readFileSync } from "fs";
|
|
2071
2138
|
import { fileURLToPath } from "url";
|
|
2072
|
-
import { dirname, join as
|
|
2139
|
+
import { dirname, join as join16 } from "path";
|
|
2073
2140
|
function selfPackageVersion(callerImportMetaUrl) {
|
|
2074
2141
|
try {
|
|
2075
2142
|
const here2 = dirname(fileURLToPath(callerImportMetaUrl));
|
|
2076
|
-
const raw = readFileSync(
|
|
2143
|
+
const raw = readFileSync(join16(here2, "..", "..", "package.json"), "utf-8");
|
|
2077
2144
|
const pkg = JSON.parse(raw);
|
|
2078
2145
|
return pkg.version ?? "0.0.0";
|
|
2079
2146
|
} catch {
|
|
@@ -2086,33 +2153,41 @@ function selfCaretRange(callerImportMetaUrl) {
|
|
|
2086
2153
|
|
|
2087
2154
|
// src/recipes/onboard.ts
|
|
2088
2155
|
var PACKAGE_NAME = "@reddoorla/maintenance";
|
|
2089
|
-
var
|
|
2090
|
-
lighthouse: [
|
|
2091
|
-
a11y: [
|
|
2092
|
-
{ name: "@playwright/test", version: "^1.59.1" },
|
|
2093
|
-
{ name: "@axe-core/playwright", version: "^4.11.3" }
|
|
2094
|
-
]
|
|
2156
|
+
var AUDIT_DEP_NAMES = {
|
|
2157
|
+
lighthouse: ["@lhci/cli"],
|
|
2158
|
+
a11y: ["@playwright/test", "@axe-core/playwright"]
|
|
2095
2159
|
};
|
|
2096
|
-
|
|
2160
|
+
var AUDIT_DEPS = Object.fromEntries(
|
|
2161
|
+
Object.entries(AUDIT_DEP_NAMES).map(([audit, names]) => [
|
|
2162
|
+
audit,
|
|
2163
|
+
names.map((name) => {
|
|
2164
|
+
const version2 = baselineVersions[name];
|
|
2165
|
+
if (!version2) {
|
|
2166
|
+
throw new Error(
|
|
2167
|
+
`baseline-versions is missing audit dep "${name}" \u2014 add it to src/configs/baseline-versions.ts`
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
return { name, version: version2 };
|
|
2171
|
+
})
|
|
2172
|
+
])
|
|
2173
|
+
);
|
|
2174
|
+
async function exists3(path) {
|
|
2097
2175
|
try {
|
|
2098
|
-
await
|
|
2176
|
+
await stat4(path);
|
|
2099
2177
|
return true;
|
|
2100
2178
|
} catch {
|
|
2101
2179
|
return false;
|
|
2102
2180
|
}
|
|
2103
2181
|
}
|
|
2104
|
-
function siteLabel10(site) {
|
|
2105
|
-
return site.name ?? site.path;
|
|
2106
|
-
}
|
|
2107
2182
|
function isDeclared(pkg, name) {
|
|
2108
2183
|
return Boolean(pkg.dependencies?.[name] ?? pkg.devDependencies?.[name]);
|
|
2109
2184
|
}
|
|
2110
2185
|
async function onboard(site, opts = {}) {
|
|
2111
|
-
const label =
|
|
2186
|
+
const label = siteLabel(site);
|
|
2112
2187
|
const spawn2 = opts.spawn ?? defaultSpawn;
|
|
2113
2188
|
const audits = opts.audits ?? ["lighthouse", "a11y"];
|
|
2114
2189
|
const packageVersion = opts.packageVersion ?? selfCaretRange(import.meta.url);
|
|
2115
|
-
if (!await
|
|
2190
|
+
if (!await exists3(join17(site.path, "pnpm-lock.yaml"))) {
|
|
2116
2191
|
return {
|
|
2117
2192
|
recipe: "onboard",
|
|
2118
2193
|
site: label,
|
|
@@ -2121,7 +2196,7 @@ async function onboard(site, opts = {}) {
|
|
|
2121
2196
|
notes: "no pnpm-lock.yaml at site root \u2014 run convert-to-pnpm first"
|
|
2122
2197
|
};
|
|
2123
2198
|
}
|
|
2124
|
-
const pkgPath =
|
|
2199
|
+
const pkgPath = join17(site.path, "package.json");
|
|
2125
2200
|
const pkg = await readPackageJson(pkgPath);
|
|
2126
2201
|
const toAdd = [];
|
|
2127
2202
|
if (!isDeclared(pkg, PACKAGE_NAME)) {
|
|
@@ -2225,12 +2300,9 @@ import { resolve as resolve8 } from "path";
|
|
|
2225
2300
|
|
|
2226
2301
|
// src/recipes/svelte-codemods.ts
|
|
2227
2302
|
import { writeFile as writeFile8 } from "fs/promises";
|
|
2228
|
-
import { join as
|
|
2229
|
-
function siteLabel11(site) {
|
|
2230
|
-
return site.name ?? site.path;
|
|
2231
|
-
}
|
|
2303
|
+
import { join as join18 } from "path";
|
|
2232
2304
|
async function svelteCodemods(site) {
|
|
2233
|
-
const label =
|
|
2305
|
+
const label = siteLabel(site);
|
|
2234
2306
|
const changes = await planGotchaCodemods(site.path);
|
|
2235
2307
|
if (changes.length === 0) {
|
|
2236
2308
|
return {
|
|
@@ -2247,7 +2319,7 @@ async function svelteCodemods(site) {
|
|
|
2247
2319
|
const branch = branchName("svelte-codemods");
|
|
2248
2320
|
await createBranch(site.path, branch);
|
|
2249
2321
|
for (const c of changes) {
|
|
2250
|
-
await writeFile8(
|
|
2322
|
+
await writeFile8(join18(site.path, c.rel), c.after, "utf-8");
|
|
2251
2323
|
}
|
|
2252
2324
|
const sha = await commit(
|
|
2253
2325
|
site.path,
|
|
@@ -2289,10 +2361,10 @@ async function runSvelteCodemodsCommand(site, opts) {
|
|
|
2289
2361
|
|
|
2290
2362
|
// src/cli/version.ts
|
|
2291
2363
|
import { readFileSync as readFileSync2 } from "fs";
|
|
2292
|
-
import { join as
|
|
2364
|
+
import { join as join19 } from "path";
|
|
2293
2365
|
function resolvePackageVersion(fromDir) {
|
|
2294
2366
|
try {
|
|
2295
|
-
const raw = readFileSync2(
|
|
2367
|
+
const raw = readFileSync2(join19(fromDir, "..", "..", "package.json"), "utf-8");
|
|
2296
2368
|
const pkg = JSON.parse(raw);
|
|
2297
2369
|
return pkg.version ?? "unknown";
|
|
2298
2370
|
} catch {
|
|
@@ -2318,6 +2390,17 @@ var RECIPE_DESCRIPTIONS = {
|
|
|
2318
2390
|
"convert-to-pnpm": "Convert an npm/yarn site to pnpm (lockfile, packageManager, scripts).",
|
|
2319
2391
|
onboard: "Install @reddoorla/maintenance + audit deps on a site (preferred first step)."
|
|
2320
2392
|
};
|
|
2393
|
+
async function runOrExit(fn, opts) {
|
|
2394
|
+
try {
|
|
2395
|
+
const { output, code } = await fn();
|
|
2396
|
+
console.log(output);
|
|
2397
|
+
process.exit(code);
|
|
2398
|
+
} catch (err) {
|
|
2399
|
+
const e = err;
|
|
2400
|
+
console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
|
|
2401
|
+
process.exit(e.exitCode ?? 1);
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2321
2404
|
var cli = cac("reddoor-maint");
|
|
2322
2405
|
cli.option("--cwd <path>", "Override working directory (default: process.cwd())");
|
|
2323
2406
|
cli.option("--verbose", "Verbose output (full stack on errors)");
|
|
@@ -2332,101 +2415,31 @@ cli.command("list-recipes", "Print the available recipes.").action(() => {
|
|
|
2332
2415
|
}
|
|
2333
2416
|
});
|
|
2334
2417
|
cli.command("audit [site]", "Run audits against a site (default: cwd).").option("--only <names>", "Comma-separated audit names (e.g. deps,lighthouse)").option("--json", "Machine-readable JSON output").option("--fleet <inventory>", "Inventory file (.json or .mjs/.js); aggregates across sites").option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
2335
|
-
async (site, opts) =>
|
|
2336
|
-
try {
|
|
2337
|
-
const { output, code } = await runAuditCommand(site, opts);
|
|
2338
|
-
console.log(output);
|
|
2339
|
-
process.exit(code);
|
|
2340
|
-
} catch (err) {
|
|
2341
|
-
const e = err;
|
|
2342
|
-
console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
|
|
2343
|
-
process.exit(e.exitCode ?? 1);
|
|
2344
|
-
}
|
|
2345
|
-
}
|
|
2418
|
+
async (site, opts) => runOrExit(() => runAuditCommand(site, opts), opts)
|
|
2346
2419
|
);
|
|
2347
2420
|
cli.command("sync-configs [site]", "Sync canonical configs into a site.").option("--only <names>", "Comma-separated config names (e.g. eslint,prettier)").option("--dry", "Print diff without writing").option("--fleet <inventory>", "Inventory file (.json or .mjs/.js)").option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
2348
|
-
async (site, opts) =>
|
|
2349
|
-
try {
|
|
2350
|
-
const { output, code } = await runSyncConfigsCommand(site, opts);
|
|
2351
|
-
console.log(output);
|
|
2352
|
-
process.exit(code);
|
|
2353
|
-
} catch (err) {
|
|
2354
|
-
const e = err;
|
|
2355
|
-
console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
|
|
2356
|
-
process.exit(e.exitCode ?? 1);
|
|
2357
|
-
}
|
|
2358
|
-
}
|
|
2421
|
+
async (site, opts) => runOrExit(() => runSyncConfigsCommand(site, opts), opts)
|
|
2359
2422
|
);
|
|
2360
2423
|
cli.command("bump-deps [site]", "Bump dependencies.").option("--group <group>", "patch | minor | major", { default: "minor" }).option("--fleet <inventory>", "Inventory file (.json or .mjs/.js)").option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
2361
|
-
async (site, opts) =>
|
|
2362
|
-
try {
|
|
2363
|
-
const { output, code } = await runBumpDepsCommand(site, opts);
|
|
2364
|
-
console.log(output);
|
|
2365
|
-
process.exit(code);
|
|
2366
|
-
} catch (err) {
|
|
2367
|
-
const e = err;
|
|
2368
|
-
console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
|
|
2369
|
-
process.exit(e.exitCode ?? 1);
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2424
|
+
async (site, opts) => runOrExit(() => runBumpDepsCommand(site, opts), opts)
|
|
2372
2425
|
);
|
|
2373
2426
|
cli.command("upgrade <upgrade> [site]", "Run a named upgrade recipe (svelte-4-to-5).").example("reddoor-maint upgrade svelte-4-to-5 ./my-site").option("--fleet <inventory>", "Inventory file (.json or .mjs/.js)").option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
2374
|
-
async (upgrade, site, opts) =>
|
|
2375
|
-
try {
|
|
2376
|
-
const { output, code } = await runUpgradeCommand(upgrade, site, opts);
|
|
2377
|
-
console.log(output);
|
|
2378
|
-
process.exit(code);
|
|
2379
|
-
} catch (err) {
|
|
2380
|
-
const e = err;
|
|
2381
|
-
console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
|
|
2382
|
-
process.exit(e.exitCode ?? 1);
|
|
2383
|
-
}
|
|
2384
|
-
}
|
|
2427
|
+
async (upgrade, site, opts) => runOrExit(() => runUpgradeCommand(upgrade, site, opts), opts)
|
|
2385
2428
|
);
|
|
2386
2429
|
cli.command(
|
|
2387
2430
|
"convert-to-pnpm [site]",
|
|
2388
2431
|
"Convert an npm/yarn site to pnpm (lockfile, packageManager, scripts)."
|
|
2389
2432
|
).option("--fleet <inventory>", "Inventory file (.json or .mjs/.js)").option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
2390
|
-
async (site, opts) =>
|
|
2391
|
-
try {
|
|
2392
|
-
const { output, code } = await runConvertToPnpmCommand(site, opts);
|
|
2393
|
-
console.log(output);
|
|
2394
|
-
process.exit(code);
|
|
2395
|
-
} catch (err) {
|
|
2396
|
-
const e = err;
|
|
2397
|
-
console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
|
|
2398
|
-
process.exit(e.exitCode ?? 1);
|
|
2399
|
-
}
|
|
2400
|
-
}
|
|
2433
|
+
async (site, opts) => runOrExit(() => runConvertToPnpmCommand(site, opts), opts)
|
|
2401
2434
|
);
|
|
2402
2435
|
cli.command("svelte-codemods [site]", "Apply Svelte 5 gotcha codemods to an already-migrated site.").option("--fleet <inventory>", "Inventory file (.json or .mjs/.js)").option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
2403
|
-
async (site, opts) =>
|
|
2404
|
-
try {
|
|
2405
|
-
const { output, code } = await runSvelteCodemodsCommand(site, opts);
|
|
2406
|
-
console.log(output);
|
|
2407
|
-
process.exit(code);
|
|
2408
|
-
} catch (err) {
|
|
2409
|
-
const e = err;
|
|
2410
|
-
console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
|
|
2411
|
-
process.exit(e.exitCode ?? 1);
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2436
|
+
async (site, opts) => runOrExit(() => runSvelteCodemodsCommand(site, opts), opts)
|
|
2414
2437
|
);
|
|
2415
2438
|
cli.command(
|
|
2416
2439
|
"onboard [site]",
|
|
2417
2440
|
"Install @reddoorla/maintenance + audit deps on a site (run after convert-to-pnpm)."
|
|
2418
2441
|
).option("--audits <names>", "Comma-separated audit subset: lighthouse,a11y (default: both)").option("--fleet <inventory>", "Inventory file (.json or .mjs/.js)").option("--workdir <path>", "Clone target for fleet mode (default ~/.reddoor-maint/sites)").action(
|
|
2419
|
-
async (site, opts) =>
|
|
2420
|
-
try {
|
|
2421
|
-
const { output, code } = await runOnboardCommand(site, opts);
|
|
2422
|
-
console.log(output);
|
|
2423
|
-
process.exit(code);
|
|
2424
|
-
} catch (err) {
|
|
2425
|
-
const e = err;
|
|
2426
|
-
console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
|
|
2427
|
-
process.exit(e.exitCode ?? 1);
|
|
2428
|
-
}
|
|
2429
|
-
}
|
|
2442
|
+
async (site, opts) => runOrExit(() => runOnboardCommand(site, opts), opts)
|
|
2430
2443
|
);
|
|
2431
2444
|
cli.help();
|
|
2432
2445
|
cli.version(version);
|