#!/usr/bin/env node /** * Single source of truth for the app version: content/changelog.md. * * Parses the topmost `## X.Y.Z — ` heading and propagates it to: * - src/lib/version.ts (APP_VERSION, shown in the UI sidebar) * - package.json ("version" field) * * Runs automatically via the `predev` / `prebuild` npm hooks, so the * sidebar version, package.json, and the changelog can never drift. * To cut a release, just add a new `## X.Y.Z — ` section at the * top of content/changelog.md. */ import { readFileSync, writeFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, join } from "node:path"; const root = join(dirname(fileURLToPath(import.meta.url)), ".."); const changelogPath = join(root, "content", "changelog.md"); const versionTsPath = join(root, "src", "lib", "version.ts"); const pkgPath = join(root, "package.json"); const changelog = readFileSync(changelogPath, "utf-8"); const match = changelog.match( /^##\s+(\d+\.\d+\.\d+)(?:\s+[—-]\s+(\d{4}-\d{2}-\d{2}))?/m, ); if (!match) { console.error( `[sync-version] No "## X.Y.Z" heading found in ${changelogPath}`, ); process.exit(1); } const version = match[1]; const versionDate = match[2] ?? ""; // --- src/lib/version.ts (generated; do not edit by hand) --------------- const versionTs = `// AUTO-GENERATED by scripts/sync-version.mjs from content/changelog.md. // Do not edit by hand — change the top "## X.Y.Z" heading in the changelog. export const APP_VERSION = "${version}"; export const APP_VERSION_DATE = "${versionDate}"; `; let tsChanged = false; try { tsChanged = readFileSync(versionTsPath, "utf-8") !== versionTs; } catch { tsChanged = true; } if (tsChanged) writeFileSync(versionTsPath, versionTs); // --- package.json "version" ------------------------------------------- const pkgRaw = readFileSync(pkgPath, "utf-8"); const pkg = JSON.parse(pkgRaw); const pkgChanged = pkg.version !== version; if (pkgChanged) { pkg.version = version; writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n"); } if (tsChanged || pkgChanged) { console.log( `[sync-version] Synced to ${version} (` + `${tsChanged ? "version.ts" : ""}` + `${tsChanged && pkgChanged ? " + " : ""}` + `${pkgChanged ? "package.json" : ""}).`, ); } else { console.log(`[sync-version] Already at ${version}.`); }