From e59d78e571df2122ab76e4311d7897348c5f7f5c Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Tue, 1 Sep 2026 14:21:50 -0400 Subject: [PATCH] feat(cli): preserve custom sections after solution during docs sync --- apps/cli/sync.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/cli/sync.ts b/apps/cli/sync.ts index d8ec742..023d43c 100755 --- a/apps/cli/sync.ts +++ b/apps/cli/sync.ts @@ -359,6 +359,24 @@ function ensureLabel(page: string, h: Header): string { return page.replace(/^sidebar:$/m, `sidebar:\n${label}`); } +/** + * Offset just past the script-owned `## Solution` section: the next top-level + * heading that is not inside a code fence, or end of file. Sections a human + * appends after the solution (`## Explanation`, …) survive regeneration. + */ +function solutionEnd(page: string, from: number): number { + const lines = page.slice(from).split("\n"); + let offset = from + lines[0]!.length + 1; // past the '## Solution' line itself + let fenced = false; + for (let i = 1; i < lines.length; i++) { + const line = lines[i]!; + if (line.startsWith("```")) fenced = !fenced; + else if (!fenced && line.startsWith("## ")) return offset; + offset += line.length + 1; + } + return page.length; +} + // Existing docs pages, keyed by leetcode number from the frontmatter title. const pages = new Map(); // num -> path relative to DOCS for (const rel of (await Array.fromAsync(new Bun.Glob("**/*.mdx").scan(DOCS))).sort()) { @@ -386,7 +404,9 @@ for (const sol of ordered) { report.push([workRef, existing, "ERROR: no '## Solution' heading"]); continue; } - const next = ensureLabel(page.slice(0, at) + solutionSection(sol), sol.header); + const tail = page.slice(solutionEnd(page, at)); + const body = page.slice(0, at) + solutionSection(sol) + (tail ? `\n${tail}` : ""); + const next = ensureLabel(body, sol.header); const actions: string[] = []; if (existing !== name) { await rename(join(DOCS, existing), join(DOCS, name));