Implement semver version checking (#1560)
This commit is contained in:
parent
4992d7bd17
commit
400a6776e4
|
@ -20,6 +20,8 @@ import Modals from "../ui/modals";
|
||||||
import UpdaterPanel from "../ui/updater";
|
import UpdaterPanel from "../ui/updater";
|
||||||
import DiscordModules from "./discordmodules";
|
import DiscordModules from "./discordmodules";
|
||||||
|
|
||||||
|
import {comparator as semverComparator, regex as semverRegex} from "../structs/semver";
|
||||||
|
|
||||||
const React = DiscordModules.React;
|
const React = DiscordModules.React;
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,24 +136,6 @@ export class CoreUpdater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const semverRegex = /^[0-9]+\.[0-9]+\.[0-9]+$/;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This works on basic semantic versioning e.g. "1.0.0".
|
|
||||||
*
|
|
||||||
* @param {string} currentVersion
|
|
||||||
* @param {string} content
|
|
||||||
* @returns {boolean} whether there is an update
|
|
||||||
*/
|
|
||||||
function semverComparator(currentVersion, remoteVersion) {
|
|
||||||
currentVersion = currentVersion.split(".").map((e) => {return parseInt(e);});
|
|
||||||
remoteVersion = remoteVersion.split(".").map((e) => {return parseInt(e);});
|
|
||||||
|
|
||||||
if (remoteVersion[0] > currentVersion[0]) return true;
|
|
||||||
else if (remoteVersion[0] == currentVersion[0] && remoteVersion[1] > currentVersion[1]) return true;
|
|
||||||
else if (remoteVersion[0] == currentVersion[0] && remoteVersion[1] == currentVersion[1] && remoteVersion[2] > currentVersion[2]) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AddonUpdater {
|
class AddonUpdater {
|
||||||
|
@ -195,9 +179,9 @@ class AddonUpdater {
|
||||||
if (this.pending.includes(filename)) return;
|
if (this.pending.includes(filename)) return;
|
||||||
const info = this.cache[path.basename(filename)];
|
const info = this.cache[path.basename(filename)];
|
||||||
if (!info) return;
|
if (!info) return;
|
||||||
let hasUpdate = info.update > currentVersion;
|
let hasUpdate = info.version > currentVersion;
|
||||||
if (semverRegex.test(info.version) && semverRegex.test(currentVersion)) {
|
if (semverRegex.test(info.version) && semverRegex.test(currentVersion)) {
|
||||||
hasUpdate = semverComparator(currentVersion, info.version);
|
hasUpdate = semverComparator(currentVersion, info.version) > 0;
|
||||||
}
|
}
|
||||||
if (!hasUpdate) return;
|
if (!hasUpdate) return;
|
||||||
this.pending.push(filename);
|
this.pending.push(filename);
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
// "Official" regex from https://semver.org/
|
||||||
|
export const regex = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
||||||
|
|
||||||
|
|
||||||
|
// Some of the code here adapted from https://github.com/npm/node-semver
|
||||||
|
const numeric = /^[0-9]+$/;
|
||||||
|
function compare(a, b) {
|
||||||
|
const anum = numeric.test(a);
|
||||||
|
const bnum = numeric.test(b);
|
||||||
|
|
||||||
|
if (anum && bnum) {
|
||||||
|
a = +a;
|
||||||
|
b = +b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a === b) return 0;
|
||||||
|
else if (anum && !bnum) return -1;
|
||||||
|
else if (bnum && !anum) return 1;
|
||||||
|
else if (a < b) return -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenize(pre) {
|
||||||
|
return pre.split(".").map((id) => {
|
||||||
|
if (!numeric.test(id)) return id;
|
||||||
|
const num = +id; // convert to number and check if valid
|
||||||
|
if (num >= 0 && num < Number.MAX_SAFE_INTEGER) return num;
|
||||||
|
return id; // Unsafe number => keep as string
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareTokens(a, b) {
|
||||||
|
const atokens = tokenize(a);
|
||||||
|
const btokens = tokenize(b);
|
||||||
|
|
||||||
|
// Compare token by token whether it's a string or number
|
||||||
|
for (let index = 0; ; index++) {
|
||||||
|
const x = atokens[index];
|
||||||
|
const y = btokens[index];
|
||||||
|
if (x === undefined && y === undefined) return 0;
|
||||||
|
else if (y === undefined) return 1;
|
||||||
|
else if (x === undefined) return -1;
|
||||||
|
else if (x === y) continue;
|
||||||
|
return compare(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function preCompare(a, b) {
|
||||||
|
// Having a prerelease makes it a "lower" version
|
||||||
|
if (a.length && !b.length) return -1;
|
||||||
|
else if (!a.length && b.length) return 1;
|
||||||
|
else if (!a.length && !b.length) return 0;
|
||||||
|
return compareTokens(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This works on semantic versioning e.g. "1.0.0".
|
||||||
|
*
|
||||||
|
* @param {string} currentVersion
|
||||||
|
* @param {string} remoteVersion
|
||||||
|
* @returns {number} 0 indicates equal, -1 indicates left hand greater, 1 indicates right hand greater
|
||||||
|
*/
|
||||||
|
export function comparator(currentVersion, remoteVersion) {
|
||||||
|
const current = regex.exec(currentVersion);
|
||||||
|
const remote = regex.exec(remoteVersion);
|
||||||
|
|
||||||
|
// Raw match is at [0] so major starts at [1]
|
||||||
|
// This compares only the major, minor, and patch levels
|
||||||
|
const versionCompare = compare(remote[1], current[1]) || compare(remote[2], current[2]) || compare(remote[3], current[3]);
|
||||||
|
|
||||||
|
// Also need to check prerelease and build info
|
||||||
|
const prereleaseCompare = preCompare(remote[4] ?? "", current[4] ?? "");
|
||||||
|
const buildCompare = compareTokens(remote[5] ?? "", current[5] ?? "");
|
||||||
|
|
||||||
|
return versionCompare || prereleaseCompare || buildCompare;
|
||||||
|
}
|
Loading…
Reference in New Issue