/** * FNXC:ReleaseChangelog 2026-07-12-00:00: * The root CHANGELOG.md is regenerated by scripts/release.mjs on every release, so pruning old release notes by hand would be reverted. * Keep the archive cutoff in generator-owned pure logic so current release notes stay in CHANGELOG.md and older notes are durably split into CHANGELOG-archive.md. * * FNXC:ReleaseChangelog 2026-07-13-22:55: * Raise the archive cutoff from 0.50.0 to 0.60.0 so CHANGELOG.md keeps only 0.60.x+ and everything below 0.60 moves into CHANGELOG-archive.md. */ export const CHANGELOG_ARCHIVE_CUTOFF = "0.60.0"; export const CHANGELOG_ARCHIVE_FILE = "CHANGELOG-archive.md"; /** * Partition version keys while preserving the source changelog order inside each bucket. * Versions greater than or equal to the cutoff remain in the current changelog; versions below it, including non-parseable keys treated as 0.0.0, move to the archive. * * @param {string[]} versionOrder * @param {string} cutoff * @returns {{ current: string[], archived: string[] }} */ export function partitionVersionsByCutoff(versionOrder, cutoff = CHANGELOG_ARCHIVE_CUTOFF) { const current = []; const archived = []; for (const version of versionOrder) { if (compareSemver(version, cutoff) >= 0) { current.push(version); } else { archived.push(version); } } return { current, archived }; } /** * Return the stable archive pointer appended to the current root changelog. * * @param {string} archiveFile * @returns {string} */ export function archivePointerLine(archiveFile = CHANGELOG_ARCHIVE_FILE) { return `> Older releases (before ${CHANGELOG_ARCHIVE_CUTOFF}) are archived in [\`${archiveFile}\`](./${archiveFile}).`; } /** Compare two semver-ish version strings ("0.2.5", "0.4.0 (pre-release)"). */ function compareSemver(a, b) { const pa = parseVersionKey(a); const pb = parseVersionKey(b); for (let i = 0; i < 3; i++) { if (pa[i] !== pb[i]) return pa[i] - pb[i]; } return 0; } function parseVersionKey(key) { const m = key.match(/^(\d+)\.(\d+)\.(\d+)/); if (!m) return [0, 0, 0]; return [Number(m[1]), Number(m[2]), Number(m[3])]; }