testPatchSeveralAtOnce
tcm patch --patches changes several definitions at once and saves them together: a function's new parameter
and its caller, which neither could be on its own, with its doc comment. One that doesn't apply changes nothing, and
says what's near.
import { okIn, tcmIn, tempDir } from "#codebase/tcmts/cli/test/e2e/harness"; import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; export const testPatchSeveralAtOnce = () => { const dir = tempDir("patch several"); const ok = (...args: string[]) => okIn(dir, ...args); ok("init"); fs.writeFileSync( path.join(dir, "scratch.ts"), `// tcm: namespace lib\n/** Doubles x. */\nexport const scale = (x: number): number => x * 2;\nexport const twice = (y: number): number => scale(y);\n`, ); ok("add"); fs.rmSync(path.join(dir, "scratch.ts")); const both = JSON.stringify([ { name: "lib.scale", edits: [ { old: "(x: number): number => x * 2", new: "(x: number, by: number): number => x * by" }, { old: "Doubles x.", new: "Scales x by `by`." }, ], }, { name: "lib.twice", edits: [{ old: "scale(y)", new: "scale(y, 2)" }] }, ]); assert.match(ok("patch", "--patches", both), /~ update +lib\.scale[\s\S]*~ update +lib\.twice/); assert.equal(ok("run", "lib.twice", "21").trim(), "42"); assert.match(ok("view", "lib.scale"), /Scales x by `by`\./); assert.match(ok("todo"), /nothing to do/); // one edit that doesn't apply: nothing changes const bad = tcmIn( dir, "patch", "--patches", JSON.stringify([ { name: "lib.twice", edits: [{ old: "scale(y, 2)", new: "scale(y, 3)" }] }, { name: "lib.scale", edits: [{ old: "x * times", new: "x" }] }, ]), ); assert.notEqual(bad.status, 0); assert.match(bad.out, /lib\.scale: not found: "x \* times"/); assert.equal(ok("run", "lib.twice", "21").trim(), "42"); assert.deepEqual( fs.readdirSync(dir).filter((f) => f.startsWith("patch-")), [], ); }