testPatchSaysPlacesAsTheViewNumbersThem
Where tcm patch says a problem is (the checker's error, the line nearest an edit it can't find), it's the line as
tcm view numbers the definition, the edits made: with imports above it, a doc, its first line edited, an import
it added, or (--patches) written with definitions from another namespace, which puts a // tcm: path line among
its own.
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 testPatchSaysPlacesAsTheViewNumbersThem = () => { const dir = tempDir("patch places"); const ok = (...args: string[]) => okIn(dir, ...args); const fails = (...args: string[]) => { const r = tcmIn(dir, ...args); assert.notEqual(r.status, 0, r.out); return r.out; }; ok("init"); fs.writeFileSync( path.join(dir, "m.ts"), `// tcm: namespace m\nimport { basename, join } from "node:path";\n\n/** doc */\nexport const f = (x: string): string => join(x, "a");\n` + `export const tools = [\n { name: "a", run: (x: string): string => join(x, "a"), other: (x: string): string => basename(x) },\n];\n` + `export const h = (x: number): number => {\n return x + 1;\n};\n` + `export const listed = [\n {\n name: "a",\n },\n] as const;\n`, ); fs.writeFileSync(path.join(dir, "n.ts"), `// tcm: namespace n\nexport const z = 1;\n`); ok("add", "m.ts", "n.ts"); for (const f of ["m.ts", "n.ts"]) fs.rmSync(path.join(dir, f)); // (as viewed: f's code is its line 6, tools' `run` its line 6, h's `return` its line 2, listed's `name` its line 3) assert.match(ok("view", "m.f", "--lines", "6"), /6 export const f/); assert.match(ok("view", "m.tools", "--lines", "6"), /6 +run: /); // the first line edited, with a doc and imports above it assert.match( fails("patch", "m.f", "--old", 'join(x, "a")', "--new", "join(x, 1)"), /m\.f:6:\d+ - error TS2345/, ); // an import it adds is a line above the code const added = fails("patch", "m.h", "--old", "x + 1", "--new", 'x + basename("s")'); assert.match(added, /import \{ basename \} from "node:path"/); assert.match(added, /m\.h:2:\d+ - error TS\d+/); // written with another namespace's definition: its lines aren't the note's assert.match( fails( "patch", "--patches", JSON.stringify([ { name: "m.listed", edits: [{ old: 'name: "a"', new: "name: y" }] }, { name: "n.z", edits: [{ old: "1", new: "2" }] }, ]), ), /m\.listed:3:\d+ - error TS2304/, ); // what's nearest an edit that isn't there, either way for (const out of [ fails("patch", "m.tools", "--old", "nope(x, a)", "--new", "1"), fails( "patch", "--patches", JSON.stringify([{ name: "m.tools", edits: [{ old: "nope(x, a)", new: "1" }] }]), ), ]) assert.match(out, /the nearest line is 6: "run: /); assert.match(ok("view", "n.z"), /z = 1/); }