Skip to content

Commit 28fe86d

Browse files
committed
fix: semantic version selection
1 parent a8a5d89 commit 28fe86d

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

src/store/version.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ interface NpmRegistryPackageMetadata {
1313
versions?: Record<string, unknown>;
1414
}
1515

16+
interface ParsedVersion {
17+
major: number;
18+
minor: number;
19+
patch: number;
20+
prerelease: string[];
21+
}
22+
1623
export function isDeprecatedRspackVersion(version: string) {
1724
return deprecatedRspackVersions.includes(version as (typeof deprecatedRspackVersions)[number]);
1825
}
@@ -24,12 +31,82 @@ function getEnabledRspackVersions(versions: string[]) {
2431
}
2532

2633
function compareVersionStrings(a: string, b: string) {
34+
const parsedA = parseVersion(a);
35+
const parsedB = parseVersion(b);
36+
if (parsedA && parsedB) {
37+
return compareParsedVersions(parsedB, parsedA);
38+
}
39+
40+
return compareVersionNames(a, b);
41+
}
42+
43+
function compareVersionNames(a: string, b: string) {
2744
return b.localeCompare(a, undefined, {
2845
numeric: true,
2946
sensitivity: "base",
3047
});
3148
}
3249

50+
function parseVersion(version: string): ParsedVersion | null {
51+
const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?(?:\+.*)?$/);
52+
if (!match) {
53+
return null;
54+
}
55+
56+
return {
57+
major: Number(match[1]),
58+
minor: Number(match[2]),
59+
patch: Number(match[3]),
60+
prerelease: match[4]?.split(".") ?? [],
61+
};
62+
}
63+
64+
function compareParsedVersions(a: ParsedVersion, b: ParsedVersion) {
65+
const releaseDiff = a.major - b.major || a.minor - b.minor || a.patch - b.patch;
66+
if (releaseDiff !== 0) {
67+
return releaseDiff;
68+
}
69+
70+
if (a.prerelease.length === 0 && b.prerelease.length === 0) {
71+
return 0;
72+
}
73+
if (a.prerelease.length === 0) {
74+
return 1;
75+
}
76+
if (b.prerelease.length === 0) {
77+
return -1;
78+
}
79+
80+
const length = Math.max(a.prerelease.length, b.prerelease.length);
81+
for (let i = 0; i < length; i++) {
82+
const itemA = a.prerelease[i];
83+
const itemB = b.prerelease[i];
84+
if (itemA === undefined) return -1;
85+
if (itemB === undefined) return 1;
86+
87+
const numberA = getPrereleaseNumber(itemA);
88+
const numberB = getPrereleaseNumber(itemB);
89+
if (numberA !== null && numberB !== null) {
90+
const diff = numberA - numberB;
91+
if (diff !== 0) return diff;
92+
continue;
93+
}
94+
if (numberA !== null) return -1;
95+
if (numberB !== null) return 1;
96+
97+
const diff = itemA.localeCompare(itemB);
98+
if (diff !== 0) {
99+
return diff;
100+
}
101+
}
102+
103+
return 0;
104+
}
105+
106+
function getPrereleaseNumber(value: string) {
107+
return /^\d+$/.test(value) ? Number(value) : null;
108+
}
109+
33110
function sortVersionsByPublishedTime(
34111
versions: string[],
35112
publishedTime: Record<string, string> | undefined,

0 commit comments

Comments
 (0)