// One-shot migration: rewrite /blog/ → /blog// // across every .md and .ts file in content/ + src/, using ALL_POSTS // as the single source of truth for each post's date. // // Sorts replacements by slug length DESCENDING so longer slugs // substitute first — prevents the prefix-collision footgun where // /blog/foo would match inside /blog/foo-bar before /blog/foo-bar // got its turn. // // Safe to re-run: replacement looks for `/blog/` literal, and // after one pass each occurrence becomes `/blog//` — // which doesn't contain `/blog/` as a substring (the 7th char // differs). No double-prefixing. import { Glob } from "bun"; import { ALL_POSTS } from "../src/a31_blog.ts"; const root = "/var/home/scri/Documents/tdd.md"; const replacements: Array<[string, string]> = ALL_POSTS .map((p) => { const yyyymm = p.date.slice(0, 7); return [`/blog/${p.slug}`, `/blog/${yyyymm}/${p.slug}`] as [string, string]; }) // Longest first to avoid /blog/foo matching inside /blog/foo-bar. .sort((a, b) => b[0].length - a[0].length); const targets: string[] = []; for await (const path of new Glob("content/**/*.md").scan({ cwd: root })) { targets.push(path); } for await (const path of new Glob("src/**/*.ts").scan({ cwd: root })) { // Don't migrate the helper itself or its sibling test — they // legitimately reference the old shape (regex pattern + test cases). if (path === "src/b32_blog_date_url_redirect.ts") continue; if (path === "src/b32_blog_date_url_redirect.test.ts") continue; targets.push(path); } for await (const path of new Glob("goals/*.md").scan({ cwd: root })) { // Don't touch the migrate-historical-goals or this PR's goal file — // those describe historical state and would drift. if (path === "goals/blog-date-prefix.md") continue; targets.push(path); } let totalFilesChanged = 0; let totalReplacements = 0; for (const target of targets) { const fullPath = `${root}/${target}`; const original = await Bun.file(fullPath).text(); let modified = original; let fileReplacements = 0; for (const [oldStr, newStr] of replacements) { const before = modified; modified = modified.replaceAll(oldStr, newStr); if (modified !== before) { // Count how many replacements happened on THIS pair. const occurrences = before.split(oldStr).length - 1; fileReplacements += occurrences; } } if (modified !== original) { await Bun.write(fullPath, modified); totalFilesChanged += 1; totalReplacements += fileReplacements; console.log(` ${target}: ${fileReplacements} substitutions`); } } console.log(`\nDone. ${totalFilesChanged} files modified, ${totalReplacements} substitutions.`);