diff --git a/apps/cli/sync.ts b/apps/cli/sync.ts index a9e0807..31a0878 100755 --- a/apps/cli/sync.ts +++ b/apps/cli/sync.ts @@ -27,7 +27,9 @@ * problem page links to it. A guide may be filed into a category `(group)` * folder (e.g. `guides/(2-algorithms)/`) — no route segment, so * `/guides/` holds — and is found there by slug; a new placeholder - * lands at the `guides/` root for a human to file (and give an `icon:`). + * lands at the `guides/` root for a human to file (and give an `icon:`, + * which every badge linking to the guide shows; sync warns while one is + * missing or shared). * * The sidebar group is the campaign TOPIC from the README table (`tree-dfs/`, * ordered by topic number via a script-owned `meta.ts`). A problem outside the @@ -777,15 +779,21 @@ for (const tag of guideTags) { // tag has no landing (`tagTarget()`). A guide whose tag a landing has since // claimed has no backlinks left. Counts move with every solved problem, so the // badge is rewritten whenever it differs; the rest of the guide is untouched. -// The same pass warns when a guide's hand-picked `icon:` is one a topic group -// owns (`TOPIC_ICONS`), so a guide row never reads as a topic row. +// The same pass checks each guide's hand-picked `icon:`, which is also the icon +// on every problem-page badge linking to the guide: it must exist, must not be +// a topic group's (`TOPIC_ICONS`), so a guide badge never reads as a topic's, +// and must not be another guide's. const topicIcons = new Set(Object.values(TOPIC_ICONS)); +const guideIcons = new Map(); // icon -> the guide that took it first for await (const rel of new Bun.Glob("guides/**/*.mdx").scan(DOCS)) { const slug = basename(rel, ".mdx"); const count = TOPIC_LANDINGS[slug] ? 0 : (tagged.get(slug) ?? 0); const page = await Bun.file(join(DOCS, rel)).text(); const icon = page.match(/^---\n[\s\S]*?\n---/)?.[0].match(/^icon: (\S+)$/m)?.[1]; - if (icon && topicIcons.has(icon)) console.warn(`${rel}: icon ${JSON.stringify(icon)} is a topic's (TOPIC_ICONS); pick another`); + if (!icon) console.warn(`${rel}: no icon; its badges render without one — file it and add \`icon:\``); + else if (topicIcons.has(icon)) console.warn(`${rel}: icon ${JSON.stringify(icon)} is a topic's (TOPIC_ICONS); pick another`); + else if (guideIcons.has(icon)) console.warn(`${rel}: icon ${JSON.stringify(icon)} is ${guideIcons.get(icon)}'s too; pick another`); + else guideIcons.set(icon, rel); const next = withBacklinkBadge(page, count); if (next === page) continue; await Bun.write(join(DOCS, rel), next);