fix(updater): 修正版本标签比较逻辑以符合semver规范

重新实现版本比较函数,正确处理各类版本标签的优先级,匹配项目定义的semver比较规则。
This commit is contained in:
2026-08-31 03:44:56 +08:00
parent 53cde460e5
commit c13acd0c23
2 changed files with 23 additions and 12 deletions
File diff suppressed because one or more lines are too long
+22 -11
View File
@@ -99,31 +99,42 @@ function getMirrors(): string[] {
/** /**
* 比较两个版本 tag(如 v1.2.1-13 / v1.2.1-beta.14 / v1.2.0-2608271921),返回 a - b。 * 比较两个版本 tag(如 v1.2.1-13 / v1.2.1-beta.14 / v1.2.0-2608271921),返回 a - b。
* 项目版本为 {base}-{buildId}base 按 X.Y.Z 数值比较buildId 按数值比较(而非字符串)。 * 项目版本为 {base}-{buildId}base 按 X.Y.Z 数值比较buildId 按 semver 规则:
* - beta.N 视为大于同 base 的任意数字 buildId(与 semver 一致:数字 < 字母) * - 无 buildId(稳定版)> 任意 prerelease
* - 无 buildId 的稳定版视为大于同 base 的任意 prerelease(与 semver 一致) * - 字母标识(beta.N)> 数字标识(N)——与 semver 一致:数字标识永远低于字母标识,
* 且不受数字大小影响(任何 beta.N 都大于任何 -N)
* - 同标识类型按数值比较
*/ */
function compareVersionTags(a: string, b: string): number { function compareVersionTags(a: string, b: string): number {
const parse = (t: string): { base: number[]; build: number } => { const parse = (t: string): { base: number[]; pre: { kind: 0 | 1; num: number } | null } => {
const s = t.replace(/^v/i, ''); const s = t.replace(/^v/i, '');
const [base, buildStr = ''] = s.split('-'); const [base, buildStr = ''] = s.split('-');
const nums = base.split('.').map((n) => parseInt(n, 10) || 0); const nums = base.split('.').map((n) => parseInt(n, 10) || 0);
while (nums.length < 3) nums.push(0); while (nums.length < 3) nums.push(0);
let build: number; let pre: { kind: 0 | 1; num: number } | null = null;
if (buildStr === '') { if (buildStr !== '') {
build = Number.MAX_SAFE_INTEGER;
} else {
const beta = /^beta\.(\d+)$/i.exec(buildStr); const beta = /^beta\.(\d+)$/i.exec(buildStr);
build = beta ? 1_000_000 + parseInt(beta[1], 10) : parseInt(buildStr, 10) || 0; // kind: 1 = 字母标识(beta),0 = 数字标识(数字优先级低于字母)
pre = beta
? { kind: 1, num: parseInt(beta[1], 10) || 0 }
: { kind: 0, num: parseInt(buildStr, 10) || 0 };
} }
return { base: nums, build }; return { base: nums, pre };
}; };
const pa = parse(a); const pa = parse(a);
const pb = parse(b); const pb = parse(b);
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
if (pa.base[i] !== pb.base[i]) return pa.base[i] - pb.base[i]; if (pa.base[i] !== pb.base[i]) return pa.base[i] - pb.base[i];
} }
return pa.build - pb.build; // 稳定版(无 prerelease> 任意 prerelease
if (pa.pre !== null && pb.pre === null) return -1;
if (pa.pre === null && pb.pre !== null) return 1;
if (pa.pre === null && pb.pre === null) return 0;
// 上面已覆盖全部 null 组合,此处仅用于类型收窄(运行时不可达)
if (pa.pre === null || pb.pre === null) return 0;
// 字母标识 > 数字标识(与数字大小无关)
if (pa.pre.kind !== pb.pre.kind) return pa.pre.kind - pb.pre.kind;
return pa.pre.num - pb.pre.num;
} }
/** /**