From eea8d242e0a91f0ec26915392b9a9b73d5be3045 Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Tue, 29 Sep 2026 15:12:52 -0400 Subject: [PATCH] refactor(cli): adjust phase meta handling and update documentation comments --- apps/cli/sync.ts | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/cli/sync.ts b/apps/cli/sync.ts index 8d6a534..b5472a5 100755 --- a/apps/cli/sync.ts +++ b/apps/cli/sync.ts @@ -30,13 +30,15 @@ * its file sits under in `work/1///` instead. * * Topics nest under their README PHASE: `(01-linear-structures)/tree-dfs/`. - * The phase folder is a Blume `(group)` — a sidebar section with its own - * script-owned `meta.ts`, adding no route segment — while the topic folder is - * a real segment (`/tree-dfs/invert-binary-tree`), so a hand-written - * `index.mdx` in it is the topic's landing page at `/tree-dfs` and Blume links - * the sidebar group row to it. Sync never writes or moves an `index.mdx`, and - * never removes a folder that still holds one. An unplanned category group has - * no phase and sits at the content root. + * The phase folder is a Blume `(group)` — a sidebar section adding no route + * segment — while the topic folder is a real segment + * (`/tree-dfs/invert-binary-tree`), so a hand-written `index.mdx` in it is the + * topic's landing page at `/tree-dfs` and Blume links the sidebar group row to + * it. Sync never writes or moves an `index.mdx`, and never removes a folder + * that still holds one. A phase folder's `meta.ts` is written once, when + * missing, then hand-owned (its title is yours to rename); a topic's is + * script-owned. An unplanned category group has no phase and sits at the + * content root. * * Only the first-solve bucket is read: work/3 and work/7 hold blind re-solves * of problems whose page already exists (see work.ts), and a fresh scaffold @@ -309,7 +311,13 @@ function phaseDir(phase: Phase): string { return `(${String(phase.order).padStart(2, "0")}-${slugify(phase.name)})`; } -/** Blume `(group)` meta for a phase: the overview page's heading, in phase order. */ +/** + * Blume `(group)` meta for a phase: the overview page's heading, in phase + * order. Written only when the folder has none — the title is hand-owned after + * that. Nothing is lost by never rewriting it: the order and name it is built + * from are also the folder name (`phaseDir`), so a README change to either + * lands in a new folder that gets a fresh meta. + */ function phaseMeta(phase: Phase): string { return `import { defineMeta } from "blume";\n\nexport default defineMeta({ title: ${JSON.stringify(`Phase ${phase.order}: ${phase.name}`)}, order: ${phase.order} });\n`; } @@ -727,10 +735,18 @@ for (const tag of guideTags) { report.push([`tag ${tag.slug}`, `guides/${tag.slug}.mdx`, "created"]); } -// Script-owned folder metas — one per live phase and topic folder, plus -// guides/ — rewritten only when they differ. +// Phase metas: created when missing (an empty file counts as missing), never +// rewritten, so a renamed phase title survives every sync. +for (const [dir, phase] of phases) { + const file = Bun.file(join(DOCS, dir, "meta.ts")); + if ((await file.exists()) && file.size > 0) continue; + await Bun.write(file, phaseMeta(phase)); + report.push([`phase ${phase.order}`, `${dir}/meta.ts`, "created"]); +} + +// Script-owned folder metas — one per live topic folder, plus guides/ — +// rewritten only when they differ. const metas: [label: string, dir: string, meta: string][] = [ - ...[...phases].map(([dir, phase]): [string, string, string] => [`phase ${phase.order}`, dir, phaseMeta(phase)]), ...[...groups].map(([dir, topic]): [string, string, string] => [`topic ${topic.order ?? "-"}`, dir, groupMeta(topic)]), ...(guideTags.length ? [["guides", "guides", GUIDES_META] as [string, string, string]] : []), ];