Files
kandev/apps/web/scripts/generate-changelog.mjs
2026-02-26 23:08:15 +00:00

71 lines
2.0 KiB
JavaScript

/**
* Pre-build script that parses CHANGELOG.md into a JSON array of version entries
* for the changelog settings page to import at build time.
*
* Output: apps/web/generated/changelog.json
* Format: [{ version, date, notes }, ...]
*/
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const WEB_ROOT = join(__dirname, "..");
const REPO_ROOT = join(WEB_ROOT, "..", "..");
const OUTPUT_DIR = join(WEB_ROOT, "generated");
const OUTPUT_FILE = join(OUTPUT_DIR, "changelog.json");
const CHANGELOG_PATH = join(REPO_ROOT, "CHANGELOG.md");
function parseChangelog(content) {
const entries = [];
// Match version headings: ## VERSION - DATE or ## VERSION
const headerPattern = /^## (\S+?)(?:\s*-\s*(\S+))?\s*$/gm;
let match;
const headers = [];
while ((match = headerPattern.exec(content)) !== null) {
headers.push({
version: match[1],
date: match[2] || "",
index: match.index,
end: match.index + match[0].length,
});
}
for (let i = 0; i < headers.length; i++) {
const header = headers[i];
const bodyStart = header.end;
const bodyEnd = i + 1 < headers.length ? headers[i + 1].index : content.length;
const notes = content.slice(bodyStart, bodyEnd).trim();
if (header.version === "Unreleased") continue;
entries.push({
version: header.version,
date: header.date,
notes,
});
}
return entries;
}
function main() {
mkdirSync(OUTPUT_DIR, { recursive: true });
let content;
try {
content = readFileSync(CHANGELOG_PATH, "utf-8");
} catch {
writeFileSync(OUTPUT_FILE, "[]\n");
console.log("[changelog] CHANGELOG.md not found — wrote empty array");
return;
}
const entries = parseChangelog(content);
writeFileSync(OUTPUT_FILE, JSON.stringify(entries, null, 2) + "\n");
console.log(`[changelog] parsed ${entries.length} version entries`);
}
main();