@reddoorla/maintenance 0.5.0 → 0.6.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 CHANGED
@@ -10,7 +10,7 @@ import { resolve as resolve2 } from "path";
10
10
 
11
11
  // src/audits/util/spawn.ts
12
12
  import { spawn } from "child_process";
13
- var defaultSpawn = (cmd, args, opts = {}) => new Promise((resolve8, reject) => {
13
+ var defaultSpawn = (cmd, args, opts = {}) => new Promise((resolve9, reject) => {
14
14
  const streaming = opts.streaming === true;
15
15
  const child = spawn(cmd, [...args], {
16
16
  cwd: opts.cwd,
@@ -33,7 +33,7 @@ var defaultSpawn = (cmd, args, opts = {}) => new Promise((resolve8, reject) => {
33
33
  });
34
34
  child.on("close", (code) => {
35
35
  if (timer) clearTimeout(timer);
36
- resolve8({ code: code ?? -1, stdout, stderr });
36
+ resolve9({ code: code ?? -1, stdout, stderr });
37
37
  });
38
38
  });
39
39
 
@@ -1508,23 +1508,41 @@ function removeDollarRestProps(source) {
1508
1508
  return next;
1509
1509
  }
1510
1510
 
1511
+ // src/recipes/svelte-5/codemods/state-effect-sync.ts
1512
+ var PATTERN = /let\s+(\w+)\s*=\s*\$state\(\s*([^)]+?)\s*\)\s*;[ \t\r\n]*\$effect\(\s*\(\s*\)\s*=>\s*\{\s*\w+\s*;\s*\1\s*=\s*([^;}]+?)\s*\}\s*\)\s*;?/g;
1513
+ function stateEffectSyncToDerived(source) {
1514
+ return source.replace(PATTERN, (full, name, initExpr, effectExpr) => {
1515
+ if (initExpr.trim() !== effectExpr.trim()) return full;
1516
+ return `let ${name} = $derived(${initExpr.trim()});`;
1517
+ });
1518
+ }
1519
+
1511
1520
  // src/recipes/svelte-5/step-gotchas.ts
1512
1521
  var SVELTE_GLOBS = ["src/**/*.svelte"];
1513
1522
  var IGNORE2 = ["node_modules/**", ".svelte-kit/**", "build/**"];
1514
- var CODEMODS = [onEventToHandler, exportLetToProps, removeDollarRestProps];
1515
- async function applyGotchaCodemods(cwd) {
1516
- let filesChanged = 0;
1523
+ var CODEMODS = [
1524
+ onEventToHandler,
1525
+ exportLetToProps,
1526
+ removeDollarRestProps,
1527
+ stateEffectSyncToDerived
1528
+ ];
1529
+ async function planGotchaCodemods(cwd) {
1530
+ const changes = [];
1517
1531
  const relPaths = await glob2(SVELTE_GLOBS, { cwd, ignore: IGNORE2, absolute: false });
1518
1532
  for (const rel of relPaths) {
1519
1533
  const path = join11(cwd, rel);
1520
1534
  const before = await readFile10(path, "utf-8");
1521
1535
  const after = CODEMODS.reduce((s, fn) => fn(s), before);
1522
- if (after !== before) {
1523
- await writeFile6(path, after, "utf-8");
1524
- filesChanged += 1;
1525
- }
1536
+ if (after !== before) changes.push({ rel, after });
1537
+ }
1538
+ return changes;
1539
+ }
1540
+ async function applyGotchaCodemods(cwd) {
1541
+ const changes = await planGotchaCodemods(cwd);
1542
+ for (const c of changes) {
1543
+ await writeFile6(join11(cwd, c.rel), c.after, "utf-8");
1526
1544
  }
1527
- return { filesChanged };
1545
+ return { filesChanged: changes.length };
1528
1546
  }
1529
1547
 
1530
1548
  // src/recipes/svelte-5/step-verify.ts
@@ -1968,12 +1986,79 @@ async function runOnboardCommand(site, opts) {
1968
1986
  return { output, code };
1969
1987
  }
1970
1988
 
1989
+ // src/cli/commands/svelte-codemods.ts
1990
+ import { resolve as resolve8 } from "path";
1991
+
1992
+ // src/recipes/svelte-codemods.ts
1993
+ import { writeFile as writeFile8 } from "fs/promises";
1994
+ import { join as join16 } from "path";
1995
+ function siteLabel11(site) {
1996
+ return site.name ?? site.path;
1997
+ }
1998
+ async function svelteCodemods(site) {
1999
+ const label = siteLabel11(site);
2000
+ const changes = await planGotchaCodemods(site.path);
2001
+ if (changes.length === 0) {
2002
+ return {
2003
+ recipe: "svelte-codemods",
2004
+ site: label,
2005
+ status: "noop",
2006
+ commits: [],
2007
+ notes: "no codemod targets matched"
2008
+ };
2009
+ }
2010
+ if (!await isWorkingTreeClean(site.path)) {
2011
+ throw new Error(`refusing to run: working tree is not clean at ${site.path}`);
2012
+ }
2013
+ const branch = branchName("svelte-codemods");
2014
+ await createBranch(site.path, branch);
2015
+ for (const c of changes) {
2016
+ await writeFile8(join16(site.path, c.rel), c.after, "utf-8");
2017
+ }
2018
+ const sha = await commit(
2019
+ site.path,
2020
+ `refactor(svelte5): apply codemods (${changes.length} files)`
2021
+ );
2022
+ return {
2023
+ recipe: "svelte-codemods",
2024
+ site: label,
2025
+ status: "applied",
2026
+ commits: sha ? [sha] : [],
2027
+ notes: `branch: ${branch}`
2028
+ };
2029
+ }
2030
+
2031
+ // src/cli/commands/svelte-codemods.ts
2032
+ function formatResult6(r) {
2033
+ if (r.status === "noop") return `[${r.site}] noop: ${r.notes ?? ""}`;
2034
+ if (r.status === "failed") return `[${r.site}] failed: ${r.notes ?? ""}`;
2035
+ return `[${r.site}] applied: ${r.commits.length} commit(s)
2036
+ ${r.notes ?? ""}`;
2037
+ }
2038
+ async function runSvelteCodemodsCommand(site, opts) {
2039
+ const cwd = opts.cwd ? resolve8(opts.cwd) : process.cwd();
2040
+ let sites = await resolveSites({
2041
+ ...site !== void 0 ? { site } : {},
2042
+ ...opts.fleet !== void 0 ? { fleet: opts.fleet } : {},
2043
+ cwd
2044
+ });
2045
+ if (opts.fleet) {
2046
+ const workdir = opts.workdir ?? `${process.env.HOME ?? ""}/.reddoor-maint/sites`;
2047
+ sites = await Promise.all(sites.map((s) => cloneIfNeeded(s, { workdir })));
2048
+ }
2049
+ const results = [];
2050
+ for (const s of sites) results.push(await svelteCodemods(s));
2051
+ const output = results.map(formatResult6).join("\n");
2052
+ const code = results.some((r) => r.status === "failed") ? 1 : 0;
2053
+ return { output, code };
2054
+ }
2055
+
1971
2056
  // src/cli/version.ts
1972
2057
  import { readFileSync } from "fs";
1973
- import { join as join16 } from "path";
2058
+ import { join as join17 } from "path";
1974
2059
  function resolvePackageVersion(fromDir) {
1975
2060
  try {
1976
- const raw = readFileSync(join16(fromDir, "..", "..", "package.json"), "utf-8");
2061
+ const raw = readFileSync(join17(fromDir, "..", "..", "package.json"), "utf-8");
1977
2062
  const pkg = JSON.parse(raw);
1978
2063
  return pkg.version ?? "unknown";
1979
2064
  } catch {
@@ -1995,6 +2080,7 @@ var RECIPE_DESCRIPTIONS = {
1995
2080
  "sync-configs": "Overwrite a site's canonical configs to match @reddoorla/maintenance.",
1996
2081
  "bump-deps": "Bump dependencies and commit the lockfile change.",
1997
2082
  "svelte-4-to-5": "Run the 7-commit Svelte 4 \u2192 5 upgrade recipe.",
2083
+ "svelte-codemods": "Apply Svelte 5 gotcha codemods to an already-migrated site (state_referenced_locally, etc.).",
1998
2084
  "convert-to-pnpm": "Convert an npm/yarn site to pnpm (lockfile, packageManager, scripts).",
1999
2085
  onboard: "Install @reddoorla/maintenance + audit deps on a site (preferred first step)."
2000
2086
  };
@@ -2079,6 +2165,19 @@ cli.command(
2079
2165
  }
2080
2166
  }
2081
2167
  );
2168
+ 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(
2169
+ async (site, opts) => {
2170
+ try {
2171
+ const { output, code } = await runSvelteCodemodsCommand(site, opts);
2172
+ console.log(output);
2173
+ process.exit(code);
2174
+ } catch (err) {
2175
+ const e = err;
2176
+ console.error(opts.verbose ? e.stack ?? e.message : e.message ?? String(err));
2177
+ process.exit(e.exitCode ?? 1);
2178
+ }
2179
+ }
2180
+ );
2082
2181
  cli.command(
2083
2182
  "onboard [site]",
2084
2183
  "Install @reddoorla/maintenance + audit deps on a site (run after convert-to-pnpm)."