From 95349ee4276450bb46f7765ff5f7ff4a442eed38 Mon Sep 17 00:00:00 2001 From: soloturn Date: Wed, 11 Nov 2026 20:32:27 +0100 Subject: [PATCH] fix: fail the build when two blog posts share a slug Slugs come from the title, and a repeat silently overwrote the earlier post. generateId now throws naming both directories. Checked with a planted duplicate. Refs #213. Co-Authored-By: soloturn --- src/content.config.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/content.config.ts b/src/content.config.ts index 9a52bea7..55ef4073 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -13,12 +13,27 @@ const issue = z.object({ url: z.string(), }); +// Slugs handed out so far, by post directory. Two posts with one slug would +// silently overwrite each other, so a repeat fails the build instead. +const blogSlugs = new Map(); + const blog = defineCollection({ // Slug = kebab-cased title, as on the Gatsby site (/blog/). loader: glob({ base: "./blog", pattern: "*/index.md", - generateId: ({ data }) => kebabCase(String(data.title)), + generateId: ({ entry, data }) => { + const slug = kebabCase(String(data.title)); + for (const [other, taken] of blogSlugs) { + if (taken === slug && other !== entry) { + throw new Error( + `Blog posts ${other} and ${entry} both map to /blog/${slug}; retitle one.`, + ); + } + } + blogSlugs.set(entry, slug); + return slug; + }, }), schema: ({ image }) => z.object({