From 988b46ff13b0a9c72802c29f3b0ce1416c894fd3 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 26 Jan 2026 10:37:20 +0000 Subject: [PATCH] Update sync-changelog.mjs Signed-off-by: Charles de Dreuille --- docs-ui/scripts/sync-changelog.mjs | 99 +++++++----------------------- 1 file changed, 23 insertions(+), 76 deletions(-) diff --git a/docs-ui/scripts/sync-changelog.mjs b/docs-ui/scripts/sync-changelog.mjs index 6b56edd84b..f49e13c5e4 100644 --- a/docs-ui/scripts/sync-changelog.mjs +++ b/docs-ui/scripts/sync-changelog.mjs @@ -13,22 +13,18 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); /** - * Compare two semantic versions. + * Compare two semantic versions for sorting. * Returns: 1 if versionA > versionB, -1 if versionA < versionB, 0 if equal - * Handles pre-release versions (e.g., "0.9.0-next.2") + * Example: compareVersions("0.11.0", "0.10.0") => 1 */ function compareVersions(versionA, versionB) { // Strip 'v' prefix if present versionA = versionA.replace(/^v/, ''); versionB = versionB.replace(/^v/, ''); - // Split into [major.minor.patch, prerelease] - const [versionABase, versionAPre] = versionA.split('-'); - const [versionBBase, versionBPre] = versionB.split('-'); - - // Compare base versions - const versionAParts = versionABase.split('.').map(Number); - const versionBParts = versionBBase.split('.').map(Number); + // Compare major.minor.patch versions + const versionAParts = versionA.split('.').map(Number); + const versionBParts = versionB.split('.').map(Number); for ( let i = 0; @@ -42,13 +38,7 @@ function compareVersions(versionA, versionB) { if (versionAPart < versionBPart) return -1; } - // If base versions equal, compare pre-release - if (!versionAPre && !versionBPre) return 0; - if (!versionAPre) return 1; // versionA is release, versionB is pre-release - if (!versionBPre) return -1; // versionA is pre-release, versionB is release - - // Both have pre-release, compare them - return versionAPre.localeCompare(versionBPre); + return 0; } /** @@ -58,15 +48,6 @@ function isNewerVersion(versionA, versionB) { return compareVersions(versionA, versionB) > 0; } -/** - * Normalize version to base version (remove pre-release suffix) - * "0.9.0-next.3" → "0.9.0" - * "0.9.0" → "0.9.0" - */ -function normalizeVersion(version) { - return version.split('-')[0]; -} - /** * Read the existing changelog.ts and find the highest version number * by scanning the changelogs/ directory for version files @@ -169,6 +150,7 @@ function getValidComponents(changelogPath) { /** * Parse CHANGELOG.md and extract entries newer than sinceVersion + * Only processes main release versions (e.g., 0.11.0), skips pre-releases (e.g., 0.11.0-next.1) */ async function parseChangelogMd(changelogPath, sinceVersion, validComponents) { const content = fs.readFileSync(changelogPath, 'utf-8'); @@ -181,23 +163,17 @@ async function parseChangelogMd(changelogPath, sinceVersion, validComponents) { // Walk through the markdown AST async function walk(node, depth = 0) { - // Version headers (## 0.9.0) + // Version headers (## 0.11.0) if (node.type === 'heading' && node.depth === 2) { const versionText = extractText(node).trim(); - // Validate that this is actually a version number (X.Y.Z or X.Y.Z-pre.N) - // Skip headings that are just markdown content within changelog entries - if (/^\d+\.\d+\.\d+/.test(versionText)) { - // Skip pre-release versions (e.g., 0.11.0-next.1, 0.9.0-alpha.2) to avoid duplicates - // While normalizeVersion() strips the suffix when writing entries, we need to skip - // pre-release sections entirely during parsing, otherwise we'd process the same - // commits twice: once from 0.11.0-next.1 and again from 0.11.0 - if (/^\d+\.\d+\.\d+-/.test(versionText)) { - currentVersion = null; - currentSection = null; - } else { - currentVersion = versionText; - currentSection = null; - } + // Only process main release versions (X.Y.Z format) + if (/^\d+\.\d+\.\d+$/.test(versionText)) { + currentVersion = versionText; + currentSection = null; + } else { + // Skip pre-release versions (e.g., 0.11.0-next.1) and non-version headings + currentVersion = null; + currentSection = null; } return; } @@ -355,7 +331,7 @@ async function parseListItem( const breaking = isBreakingChange(section, description, version); return { - version: normalizeVersion(version), + version, section, commitSha, description, @@ -374,8 +350,7 @@ async function parseListItem( */ function isBreakingChange(section, description, version) { // Parse version to determine breaking change rules based on semver - const normalizedVersion = normalizeVersion(version); - const [major] = normalizedVersion.split('.').map(Number); + const [major] = version.split('.').map(Number); // Version >= 1.0.0: Only Major Changes are breaking if (major >= 1) { @@ -444,7 +419,7 @@ async function generateVersionFiles( dryRun = false, force = false, ) { - // Group entries by normalized version + // Group entries by version const byVersion = {}; entries.forEach(entry => { const version = entry.version; @@ -887,20 +862,16 @@ async function main() { const existingContent = fs.readFileSync(changelogTsPath, 'utf-8'); // Filter to only new, non-duplicate entries - const relevantEntries = allEntries.filter(e => { - const hasComponents = e.components.length > 0 || e.components.length === 0; - const notDuplicate = !isDuplicate(e, existingContent); - return hasComponents && notDuplicate; - }); + const relevantEntries = allEntries.filter( + e => !isDuplicate(e, existingContent), + ); const duplicatesCount = allEntries.length - relevantEntries.length; if (duplicatesCount > 0) { console.log(`Skipped ${duplicatesCount} duplicate entries`); } - console.log( - `Relevant entries (with or without components): ${relevantEntries.length}`, - ); + console.log(`Relevant entries: ${relevantEntries.length}`); if (relevantEntries.length === 0) { console.log('\n✅ No new entries to sync'); @@ -926,30 +897,6 @@ async function main() { console.log(` - ${comp}: ${count} ${count === 1 ? 'entry' : 'entries'}`); }); - // Warn about unknown components - const unknownComponents = []; - allEntries.forEach(entry => { - const fullText = entry.description; - const componentMatch = fullText.match( - /Affected components?:[ \t]*([^\n]+)/i, - ); - if (componentMatch) { - const names = componentMatch[1].split(',').map(n => n.trim()); - names.forEach(name => { - if (!mapComponentName(name, validComponents)) { - unknownComponents.push(name); - } - }); - } - }); - - if (unknownComponents.length > 0) { - console.log('\n⚠️ Unknown components (skipped):'); - [...new Set(unknownComponents)].forEach(name => { - console.log(` - ${name}`); - }); - } - // Create changelogs directory if it doesn't exist const changelogsDir = path.join(__dirname, '../src/utils/changelogs'); if (!fs.existsSync(changelogsDir) && !dryRun) {