brokenLiteral
uses tcmts.cli.main.templateLiterals, which uses tcmts.core.ts.parse, which uses tcmts.core.ts.compiler, which uses process
Why an edit can't be made, if it would end or split a template literal it's inside: before and after it, the
places in before it replaced with inserted. A literal an edit is inside (its backticks left as they were) is
expected to end where it did, moved by what the edits changed, as parsing both (as file) finds; an edit that takes
in a literal's backtick changes it on purpose. Lines are numbered from from + 1.
import { templateLiterals } from "#codebase/tcmts/cli/main"; export function brokenLiteral( before: string, after: string, places: { index: number; length: number }[], inserted: string, file: string, from = 0, ): string | undefined { const by = (ps: typeof places) => ps.reduce((n, p) => n + inserted.length - p.length, 0); let now: Set<string> | undefined; for (const [a, b] of templateLiterals(before, file)) { const inside = places.filter((p) => p.index > a && p.index + p.length < b); if ( !inside.length || places.some((p) => p.index < b && p.index + p.length > a && !inside.includes(p)) ) continue; const shift = by(places.filter((p) => p.index + p.length <= a)); now ??= new Set(templateLiterals(after, file).map(([a, b]) => `${a}:${b}`)); if (now.has(`${a + shift}:${b + shift + by(inside)}`)) continue; const line = from + before.slice(0, a).split("\n").length; // (one that isn't escaped: after no backslash, or an escaped one) return /(?<!\\)(?:\\\\)*`/.test(inserted) ? `new has a bare backtick inside the template literal at line ${line}, which would end the literal there: escape it as \\\` (in JSON, "\\\\\`"), or, to end the literal, take its closing backtick into old` : /(?<!\\)(?:\\\\)*\$\{/.test(inserted) ? `new has a bare \${ inside the template literal at line ${line}, which would start a substitution there: escape it as \\\${ (in JSON, "\\\\\${")` : `the edit would change where the template literal at line ${line} ends: escape a backtick or \${ in new as \\\` or \\\${`; } return undefined; }