mergeScratch
Three-way merge of a definition's text as a scratch file holds it (tcm edit's, without its namespace line): its
imports as a set, what either side imports (an import nothing uses is harmless; one missing isn't), and its code
by lines (mergeLines), conflicts marked. imports: what it imports, one name an import; stretches: where
each side's changes are in body, the code after them.
import { mergeLines } from "#codebase/tcmts/cli/merge"; import type { MarkerLabels, Merged } from "#codebase/tcmts/cli/merge"; import { groupImports } from "#codebase/tcmts/loader"; export function mergeScratch( base: string, ours: string, theirs: string, labels?: MarkerLabels, ): Merged { const split = (text: string) => { const lines = text.split("\n"); const imports: string[] = []; let i = 0; for (; i < lines.length; i++) { if (lines[i] === "") continue; if (!lines[i]!.startsWith("import ")) break; let statement = lines[i]!; while (!statement.trimEnd().endsWith(";") && i + 1 < lines.length) statement += `\n${lines[++i]}`; // (one import a name: grouped again below, as `tcm edit` groups them) const m = /^import (type )?\{([\s\S]*)\} from ("[^"]*");$/.exec(statement.trim()); if (!m) imports.push(statement.trim()); else for (const n of m[2]!.split(",").map((s) => s.trim())) if (n) imports.push(`import ${m[1] ?? ""}{ ${n} } from ${m[3]};`); } return { imports, body: lines.slice(i) }; }; const [b, o, t] = [base, ours, theirs].map(split); const imports = [...new Set([...o!.imports, ...t!.imports])]; const grouped = groupImports(imports); const { lines, ...body } = mergeLines(b!.body, o!.body, t!.body, labels); return { text: [...grouped, ...(grouped.length ? [""] : []), ...lines].join("\n"), body: lines, imports, ...body, }; }
uses
- tcmts.cli.merge.MarkerLabels
- tcmts.cli.merge.Merged
- tcmts.cli.merge.mergeLines
- tcmts.loader.groupImports