testResolveRepointsDependents
The same, with edits that overlap: the class is a conflict, labelled by side. The code using the conflicted class through what's between uses this side's, so the other side's code that needs its own doesn't typecheck: it's to do (not left using versions nothing names). Resolving the conflict to the other side re-derives it, and this side's code, against the one kept.
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 testResolveRepointsDependents = () => { const dir = tempDir("merge resolve"); const tcm = (...args: string[]) => okIn(dir, ...args); const update = (code: string) => { fs.writeFileSync(path.join(dir, "scratch.ts"), `// tcm: namespace lib\n${code}\n`); tcm("update"); }; tcm("init"); update(`export class Store {\n a(): number {\n return 1;\n }\n}`); update(`import { Store } from "#codebase/lib"; export class Codebase { store = new Store(); } export const render = (cb: Codebase) => cb.store.a(); export const main = () => render(new Codebase());`); tcm("branch", "b"); tcm("branch", "m"); tcm("switch", "m"); update(`export class Store {\n a(): number {\n return 100;\n }\n}`); tcm("switch", "b"); update( `export class Store {\n a(): number {\n return 2;\n }\n y(): number {\n return 3;\n }\n}`, ); update( `import { Codebase } from "#codebase/lib";\nexport const render = (cb: Codebase) => cb.store.a() + cb.store.y();`, ); tcm("switch", "m"); const merged = tcmIn(dir, "merge", "b"); assert.equal(merged.status, 1, "a conflict makes merge exit non-zero"); assert.doesNotMatch(merged.out, /merged as text/); const line = /conflict lib\.Store: (\S+) \((ours|theirs): (m|b)\) vs (\S+) \((ours|theirs): (m|b)\)/.exec( merged.out, ); assert.ok(line, merged.out); assert.notEqual(line[2], line[5], "one is each side's"); const theirs = line[2] === "theirs" ? line[1]! : line[4]!; assert.match(merged.out, /no longer typecheck after the merge: .*lib\.render/); const todo = tcm("todo"); assert.match(todo, /conflict lib\.Store/); assert.match(todo, /needs fixing lib\.render: Property 'y' does not exist/); assert.doesNotMatch(todo, /unnamed version/); const resolved = tcm("resolve", "lib.Store", theirs); assert.match(resolved, /updated/, "what used main's Store is re-derived against b's"); assert.equal(tcm("run", "lib.main").trim(), "5"); const after = tcm("todo"); assert.doesNotMatch(after, /unnamed version/); assert.match(after, /nothing to do/); }