fix(app): preserve provisional syntax at cached reveal boundaries

This commit is contained in:
Mohamed Boudra
2026-10-15 15:32:02 +02:00
parent eedf916023
commit d42e0ca00c
2 changed files with 25 additions and 3 deletions
@@ -77,6 +77,16 @@ describe("source-preserving prose", () => {
expect(prepare(blocks, true, length)).toBe(prepareProse(blocks, noFiles, true, length));
}
});
it.each([
["A ||literal|| and escaped \\* text.", 2, "A "],
["Use `README.md` and example.com. Later.", 4, "Use "],
["[unresolved label] later.", 12, "unresolved "],
["[unresolved label] later.", 19, "unresolved label "],
] as const)("keeps cached reveal boundaries literal: %s", (source, length, expected) => {
const prepare = createProsePreparer((text) => text === "README.md");
prepare([source], true, source.length);
expect(prepare([source], true, length)).toBe(expected);
});
it("changes only prose pipes", () => {
expect(prepareProse(["Keep ||literal|| and `a || b` and [a|b](https://x/a|b)."], noFiles)).toBe(
"Keep \\|\\|literal\\|\\| and `a || b` and [a\\|b](https://x/a|b).",
@@ -368,25 +368,37 @@ function compileBlock(
edits.push({ ...edit, start: positions[edit.start]!, end: positions[edit.end]! });
}
const rendered = applyEdits(text, edits);
return { text: rendered, cuts, offsets: preparedOffsets(cuts, edits) };
}
function preparedOffsets(cuts: number[], edits: Edit[]): number[] {
const offsets: number[] = [];
let editIndex = 0;
let delta = 0;
for (const cut of cuts) {
while (editIndex < edits.length && edits[editIndex]!.end <= cut) {
while (
editIndex < edits.length &&
edits[editIndex]!.end <= cut &&
edits[editIndex]!.start < cut
) {
const edit = edits[editIndex++]!;
delta += edit.text.length - (edit.end - edit.start);
}
offsets.push(cut + delta);
}
return { text: rendered, cuts, offsets };
return offsets;
}
function paragraphCuts(source: string, trace: InlineTrace): number[] {
const cuts: number[] = [];
let depth = 0;
// A bracket can remain a provisional reference/link even after its closing bracket.
// Keep that suffix together until the block settles.
const bracket = source.indexOf("[");
const stableEnd = bracket < 0 ? source.length : bracket;
for (const span of trace.spans) {
if (span.insideLink) continue;
if (depth === 0 && span.tokens.length === 0 && source[span.start] !== "&") {
for (let i = span.start; i < span.end; i++) if (source[i] === " ") cuts.push(i + 1);
for (let i = span.start; i < span.end; i++)
if (i < stableEnd && source[i] === " ") cuts.push(i + 1);
}
for (const token of span.tokens) depth += token.nesting;
}