fix(npm): correct pre-release version comparison
The isNewerOrEqual function was comparing pre-release strings lexicographically (e.g., "beta.2" > "beta.10" due to string comparison), causing incorrect downgrade detection. Now parses pre-release into id and numeric parts for proper numeric comparison. Fixes: beta version upgrade being treated as outdated and downgrading to stable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
6c82e54157
commit
6e1d6ff44f
2 files changed
+33
-11
No files matched your search
+17
-5
@@ -122,12 +122,18 @@ function extractZip(buffer, destDir, binaryName) {
|
||||
}
|
||||
}
|
||||
|
||||
// parseVersion splits "1.2.3-beta.1" into { nums: [1,2,3], pre: "beta.1" }
|
||||
// parseVersion splits "1.2.3-beta.1" into { nums: [1,2,3], preId: "beta", preNum: 1 }
|
||||
function parseVersion(v) {
|
||||
v = v.replace(/^v/, "").trim();
|
||||
const [base, ...rest] = v.split("-");
|
||||
const nums = base.split(".").map(Number);
|
||||
return { nums, pre: rest.join("-") };
|
||||
const preStr = rest.join("-");
|
||||
// Split pre-release into id and numeric part: "beta.1" -> ["beta", 1], "rc.2" -> ["rc", 2]
|
||||
const preMatch = preStr.match(/^([a-zA-Z]+)\.?(\d+)?$/);
|
||||
if (preMatch) {
|
||||
return { nums, preId: preMatch[1], preNum: preMatch[2] ? parseInt(preMatch[2], 10) : 0 };
|
||||
}
|
||||
return { nums, preId: preStr, preNum: 0 };
|
||||
}
|
||||
|
||||
// isNewerOrEqual returns true if installed >= expected
|
||||
@@ -141,9 +147,15 @@ function isNewerOrEqual(installed, expected) {
|
||||
if (av > bv) return true;
|
||||
if (av < bv) return false;
|
||||
}
|
||||
if (!a.pre && b.pre) return true;
|
||||
if (a.pre && !b.pre) return false;
|
||||
return a.pre >= b.pre;
|
||||
// Same base: no pre-release >= any pre-release (1.2.3 >= 1.2.3-beta.1)
|
||||
if (!a.preId && b.preId) return true;
|
||||
if (a.preId && !b.preId) return false;
|
||||
// Same pre-release type: compare numerically (beta.2 > beta.1)
|
||||
if (a.preId === b.preId) {
|
||||
return a.preNum >= b.preNum;
|
||||
}
|
||||
// Different pre-release types: compare lexicographically (rc > beta)
|
||||
return a.preId >= b.preId;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
||||
+16
-6
@@ -13,12 +13,18 @@ const binDir = path.join(__dirname, "bin");
|
||||
const ext = process.platform === "win32" ? ".exe" : "";
|
||||
const binaryPath = path.join(binDir, NAME + ext);
|
||||
|
||||
// parseVersion splits "1.2.3-beta.1" into { nums: [1,2,3], pre: "beta.1" }
|
||||
// parseVersion splits "1.2.3-beta.1" into { nums: [1,2,3], preId: "beta", preNum: 1 }
|
||||
function parseVersion(v) {
|
||||
v = v.replace(/^v/, "").trim();
|
||||
const [base, ...rest] = v.split("-");
|
||||
const nums = base.split(".").map(Number);
|
||||
return { nums, pre: rest.join("-") };
|
||||
const preStr = rest.join("-");
|
||||
// Split pre-release into id and numeric part: "beta.1" -> ["beta", 1], "rc.2" -> ["rc", 2]
|
||||
const preMatch = preStr.match(/^([a-zA-Z]+)\.?(\d+)?$/);
|
||||
if (preMatch) {
|
||||
return { nums, preId: preMatch[1], preNum: preMatch[2] ? parseInt(preMatch[2], 10) : 0 };
|
||||
}
|
||||
return { nums, preId: preStr, preNum: 0 };
|
||||
}
|
||||
|
||||
// isNewerOrEqual returns true if installed >= expected
|
||||
@@ -33,10 +39,14 @@ function isNewerOrEqual(installed, expected) {
|
||||
if (av < bv) return false;
|
||||
}
|
||||
// Same base: no pre-release >= any pre-release (1.2.3 >= 1.2.3-beta.1)
|
||||
if (!a.pre && b.pre) return true;
|
||||
if (a.pre && !b.pre) return false;
|
||||
// Both have pre-release or both don't
|
||||
return a.pre >= b.pre;
|
||||
if (!a.preId && b.preId) return true;
|
||||
if (a.preId && !b.preId) return false;
|
||||
// Same pre-release type: compare numerically (beta.2 > beta.1)
|
||||
if (a.preId === b.preId) {
|
||||
return a.preNum >= b.preNum;
|
||||
}
|
||||
// Different pre-release types: compare lexicographically (rc > beta)
|
||||
return a.preId >= b.preId;
|
||||
}
|
||||
|
||||
function needsReinstall() {
|
||||
|
||||
Reference in new issue
Block a user