diff --git a/.changeset/fix-zh-cn-roadmap-duplicate.md b/.changeset/fix-zh-cn-roadmap-duplicate.md new file mode 100644 index 0000000000..03fa5aaf60 --- /dev/null +++ b/.changeset/fix-zh-cn-roadmap-duplicate.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Restore the Simplified and Traditional Chinese labels for duplicate roadmap reports. +category: fix +dev: Adds the missing report.roadmapDuplicate.title key to the zh-CN and zh-TW catalogs. diff --git a/packages/i18n/locales/zh-CN/app.json b/packages/i18n/locales/zh-CN/app.json index 0272460f49..62766bffe3 100644 --- a/packages/i18n/locales/zh-CN/app.json +++ b/packages/i18n/locales/zh-CN/app.json @@ -9176,6 +9176,9 @@ "title": "已在路线图中", "message": "此报告与已经规划的功能相匹配。" }, + "roadmapDuplicate": { + "title": "已在路线图中 — 添加您的数据点?" + }, "targetLabel": "提交目标", "targetInherit": "使用已配置的操作目标", "targetIssue": "GitHub 议题", diff --git a/packages/i18n/locales/zh-TW/app.json b/packages/i18n/locales/zh-TW/app.json index 93b482f36f..96686188e9 100644 --- a/packages/i18n/locales/zh-TW/app.json +++ b/packages/i18n/locales/zh-TW/app.json @@ -9176,6 +9176,9 @@ "title": "已在路線圖中", "message": "此報告與已規劃的功能相符。" }, + "roadmapDuplicate": { + "title": "已在路線圖中 — 新增您的資料點?" + }, "targetLabel": "提交目標", "targetInherit": "使用設定的操作目標", "targetIssue": "GitHub 議題", diff --git a/scripts/__tests__/changeset-schema.test.mjs b/scripts/__tests__/changeset-schema.test.mjs index e28c814173..5e59fdbfde 100644 --- a/scripts/__tests__/changeset-schema.test.mjs +++ b/scripts/__tests__/changeset-schema.test.mjs @@ -4,6 +4,7 @@ import assert from "node:assert/strict"; import { parseChangesetBody, parseChangesetFile, + parseChangesetChangelogEntries, validateChangeset, MAX_SUMMARY_LENGTH, CATEGORIES, @@ -151,3 +152,24 @@ test("handles file without frontmatter gracefully", () => { assert.equal(result.frontmatter, ""); assert.equal(result.parsed.summary, "No frontmatter."); }); + +// --- parseChangesetChangelogEntries --- + +test("preserves multiline labeled fields from Changesets changelog bullets", () => { + const notes = [ + "### Patch Changes", + "", + "- 831ed4c: summary: Restore Chinese roadmap duplicate labels.", + " category: fix", + " dev: Restores zh-CN and zh-TW catalog entries.", + ].join("\n"); + + assert.deepEqual(parseChangesetChangelogEntries(notes), [ + { + summary: "Restore Chinese roadmap duplicate labels.", + category: "fix", + dev: "Restores zh-CN and zh-TW catalog entries.", + legacy: false, + }, + ]); +}); diff --git a/scripts/ci-distill-release-notes.mjs b/scripts/ci-distill-release-notes.mjs index 97eb967507..a28664076a 100644 --- a/scripts/ci-distill-release-notes.mjs +++ b/scripts/ci-distill-release-notes.mjs @@ -16,7 +16,7 @@ import { readFileSync, writeFileSync, existsSync } from "node:fs"; import { join } from "node:path"; -import { parseChangesetBody } from "./lib/changeset-schema.mjs"; +import { parseChangesetChangelogEntries } from "./lib/changeset-schema.mjs"; import { distillReleaseNotes } from "./lib/distill-release-notes.mjs"; import { extractVersionNotes, replaceVersionSection } from "./lib/extract-version-notes.mjs"; @@ -43,34 +43,14 @@ if (!existsSync(CHANGELOG_PATH)) { */ function extractVersionEntries(ver) { const cliChangelogPath = join("packages", "cli", "CHANGELOG.md"); - const entries = []; if (!existsSync(cliChangelogPath)) { - return entries; + return []; } const raw = readFileSync(cliChangelogPath, "utf8"); const notes = extractVersionNotes(raw, ver); - - for (const line of notes.split(/\r?\n/)) { - const bulletMatch = line.match(/^-\s+(.*)/); - if (!bulletMatch) continue; - - const body = bulletMatch[1].trim(); - - if (body.includes("summary:") || body.includes("category:")) { - const parsed = parseChangesetBody(body); - if (parsed) entries.push(parsed); - } else { - entries.push({ - summary: body.split("\n")[0].trim(), - category: "internal", - legacy: true, - }); - } - } - - return entries; + return parseChangesetChangelogEntries(notes); } const entries = extractVersionEntries(version); diff --git a/scripts/lib/changeset-schema.mjs b/scripts/lib/changeset-schema.mjs index 50cadf3d37..34ee9f8d3d 100644 --- a/scripts/lib/changeset-schema.mjs +++ b/scripts/lib/changeset-schema.mjs @@ -79,6 +79,53 @@ export function parseChangesetBody(body) { }; } +/** + * FNXC:Changelog 2026-07-19-21:40: + * Changesets renders each release entry as a commit-prefixed bullet followed by indented labeled fields. Release-note distillation must parse the complete bullet and remove only the generated commit prefix so `category` and `dev` are not lost or mislabeled as Internal. + * + * @param {string} notes - A version section from a Changesets package changelog. + * @returns {Array<{summary: string, category: string, dev?: string, legacy: boolean}>} + */ +export function parseChangesetChangelogEntries(notes) { + if (!notes || !notes.trim()) { + return []; + } + + const bodies = []; + let current = null; + + const flush = () => { + if (current?.length) { + bodies.push(current.join("\n")); + } + current = null; + }; + + for (const line of notes.split(/\r?\n/)) { + const bulletMatch = line.match(/^-\s+(.*)$/); + if (bulletMatch) { + flush(); + current = [bulletMatch[1].trimEnd()]; + continue; + } + + if (current && /^\s+\S/.test(line)) { + current.push(line.trim()); + continue; + } + + if (current && line.trim()) { + flush(); + } + } + flush(); + + return bodies + .map((body) => body.replace(/^[0-9a-f]{7,40}:\s*(?=(?:summary|category|dev):)/i, "")) + .map((body) => parseChangesetBody(body)) + .filter(Boolean); +} + /** * Extract `key: value` labeled fields from the changeset body. * `dev` allows multi-line content until the next labeled field or EOF.