// ============================================================ // bump-version.mjs — 版本号管理与 CHANGELOG 模板生成 // // 用法: // node build/scripts/bump-version.mjs [--no-changelog] // node build/scripts/bump-version.mjs set // node build/scripts/bump-version.mjs pre // // 示例: // node build/scripts/bump-version.mjs patch # 0.0.28 → 0.0.29 // node build/scripts/bump-version.mjs minor # 0.0.28 → 0.1.0 // node build/scripts/bump-version.mjs set 1.0.0 # 直接设置版本 // node build/scripts/bump-version.mjs pre beta # 0.0.29 → 0.0.29-beta.1 // ============================================================ import { readFileSync, writeFileSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = join(__dirname, '..', '..'); const args = process.argv.slice(2); const command = args[0]; const arg1 = args[1]; const noChangelog = args.includes('--no-changelog'); if (!command) { console.error('用法: node build/scripts/bump-version.mjs [value]'); console.error('示例: node build/scripts/bump-version.mjs patch'); console.error(' node build/scripts/bump-version.mjs set 1.0.0'); console.error(' node build/scripts/bump-version.mjs pre beta'); process.exit(1); } const pkgPath = join(ROOT, 'package.json'); const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')); const oldVersion = pkg.version; // ---------- 版本计算 ---------- function parseSemver(v) { const match = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/); if (!match) throw new Error(`无效的版本号格式: ${v}`); return { major: parseInt(match[1]), minor: parseInt(match[2]), patch: parseInt(match[3]), pre: match[4] || null, }; } let newVersion; switch (command) { case 'major': case 'minor': case 'patch': { const sv = parseSemver(oldVersion); if (command === 'major') { sv.major++; sv.minor = 0; sv.patch = 0; } else if (command === 'minor') { sv.minor++; sv.patch = 0; } else { sv.patch++; } sv.pre = null; newVersion = `${sv.major}.${sv.minor}.${sv.patch}`; break; } case 'set': { if (!arg1) { console.error('用法: node build/scripts/bump-version.mjs set '); process.exit(1); } // 基本格式校验 if (!/^\d+\.\d+\.\d+(-.+)?$/.test(arg1)) { console.error(`无效的版本号: ${arg1}`); process.exit(1); } newVersion = arg1; break; } case 'pre': { if (!arg1 || !['beta', 'alpha'].includes(arg1)) { console.error('用法: node build/scripts/bump-version.mjs pre '); process.exit(1); } const sv = parseSemver(oldVersion); // 如果当前版本已有预发布后缀,递增进位号 if (sv.pre) { const match = sv.pre.match(new RegExp(`^${arg1}\\.(\\d+)$`)); if (match) { const num = parseInt(match[1]) + 1; newVersion = `${sv.major}.${sv.minor}.${sv.patch}-${arg1}.${num}`; } else { // 不同预发布类型,重新开始 newVersion = `${sv.major}.${sv.minor}.${sv.patch}-${arg1}.1`; } } else { // 纯 semver → 首次预发布:自动升 patch 再加后缀 sv.patch++; newVersion = `${sv.major}.${sv.minor}.${sv.patch}-${arg1}.1`; } break; } default: console.error(`未知命令: ${command}。支持: major | minor | patch | set | pre `); process.exit(1); } // ---------- 更新 package.json ---------- pkg.version = newVersion; writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8'); console.log(`✅ package.json: ${oldVersion} → ${newVersion}`); // ---------- 更新 shared/constants/version.ts(由 import pkg 动态读取,无需修改) ---------- console.log(' shared/constants/version.ts 自动读取 package.json,无需手动同步'); // ---------- 更新 CHANGELOG.md ---------- if (!noChangelog) { const changelogPath = join(ROOT, 'CHANGELOG.md'); try { let changelog = readFileSync(changelogPath, 'utf-8'); const today = new Date().toISOString().slice(0, 10); const entry = `## ${newVersion}(${today})\n\n**更新内容待补充**\n\n---\n\n`; // 在第一个 ## 之前插入新版本条目 const firstHeaderMatch = changelog.match(/^##\s/m); if (firstHeaderMatch) { const insertAt = firstHeaderMatch.index; changelog = changelog.slice(0, insertAt) + entry + changelog.slice(insertAt); writeFileSync(changelogPath, changelog, 'utf-8'); console.log(`✅ CHANGELOG.md: 已添加 v${newVersion} 模板条目`); } else { console.warn('⚠️ CHANGELOG.md 格式异常,未找到 ## 版本标题'); } } catch { console.warn('⚠️ CHANGELOG.md 不存在,跳过更新'); } } console.log(`\n版本已更新: ${oldVersion} → ${newVersion}`);