vrc-get/vrc-get-gui/lib/version.ts

167 lines
4.2 KiB
TypeScript

import type { TauriVersion } from "@/lib/bindings";
function comparePrereleaseSegment(a: string, b: string) {
if (a === b) return 0;
const aIsNum = !!a.match(/^\d+$/);
const bIsNum = !!b.match(/^\d+$/);
if (aIsNum) {
if (bIsNum) {
const aNum = Number.parseInt(a, 10);
const bNum = Number.parseInt(b, 10);
if (aNum < bNum) return -1;
if (aNum > bNum) return 1;
return 0;
} else {
return -1;
}
} else {
if (!bIsNum) {
// the js does < > in unicode code point order, which is the same as ASCII order
if (a < b) return -1;
if (a > b) return 1;
return 0;
} else {
return 1;
}
}
}
export function compareVersion(a: TauriVersion, b: TauriVersion) {
if (a.major < b.major) return -1;
if (a.major > b.major) return 1;
if (a.minor < b.minor) return -1;
if (a.minor > b.minor) return 1;
if (a.patch < b.patch) return -1;
if (a.patch > b.patch) return 1;
// fast path: exactly the same prerelease
if (a.pre === b.pre) return 0;
// if either has no prerelease, it comes later
if (a.pre === "") return 1;
if (b.pre === "") return -1;
const aPrerelease = a.pre.split(".");
const bPrerelease = b.pre.split(".");
for (let i = 0; i < Math.min(aPrerelease.length, bPrerelease.length); i++) {
const cmp = comparePrereleaseSegment(aPrerelease[i], bPrerelease[i]);
if (cmp !== 0) return cmp;
}
if (aPrerelease.length < bPrerelease.length) return -1;
if (aPrerelease.length > bPrerelease.length) return 1;
return 0;
}
export function toVersionString(
version: TauriVersion,
): `${number}.${number}.${number}${`-${string}` | ""}${`+${string}` | ""}` {
const versionString: `${number}.${number}.${number}` = `${version.major}.${version.minor}.${version.patch}`;
const withPre: `${number}.${number}.${number}${`-${string}` | ""}` =
version.pre ? `${versionString}-${version.pre}` : versionString;
return version.build ? `${withPre}+${version.build}` : withPre;
}
export function compareUnityVersion(a: [number, number], b: [number, number]) {
if (a[0] < b[0]) return -1;
if (a[0] > b[0]) return 1;
if (a[1] < b[1]) return -1;
if (a[1] > b[1]) return 1;
return 0;
}
// This ignores china version changes
export function compareUnityVersionString(a: string, b: string): 0 | 1 | -1 {
if (a === b) return 0;
const aParsed = parseUnityVersion(a);
const bParsed = parseUnityVersion(b);
if (!aParsed && !bParsed) {
const cmp = a.localeCompare(b);
return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
} else if (!aParsed) {
return 1;
} else if (!bParsed) {
return -1;
}
if (aParsed.major < bParsed.major) return -1;
if (aParsed.major > bParsed.major) return 1;
if (aParsed.minor < bParsed.minor) return -1;
if (aParsed.minor > bParsed.minor) return 1;
if (aParsed.patch < bParsed.patch) return -1;
if (aParsed.patch > bParsed.patch) return 1;
const channelCmp = compareUnityChannel(aParsed.channel, bParsed.channel);
if (channelCmp !== 0) return channelCmp;
if (aParsed.increment < bParsed.increment) return -1;
if (aParsed.increment > bParsed.increment) return 1;
return 0;
}
interface UnityVersion {
major: number;
minor: number;
patch: number;
channel: "a" | "b" | "f" | "c" | "p" | "x";
increment: number;
chinaIncrement: number | null;
}
export function parseUnityVersion(version: string): UnityVersion | null {
let match = version.match(/^(\d+)\.(\d+)\.(\d+)([abfcpx])(\d+)(?:c(\d+))?$/);
if (!match) {
match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
if (!match) {
return null;
}
}
return {
major: Number.parseInt(match[1], 10),
minor: Number.parseInt(match[2], 10),
patch: Number.parseInt(match[3], 10),
channel: (match[4] || "f") as UnityVersion["channel"],
increment: Number.parseInt(match[5] || "1", 10),
chinaIncrement: match[6] ? Number.parseInt(match[6], 10) : null,
};
}
function compareUnityChannel(
aIn: UnityVersion["channel"],
bIn: UnityVersion["channel"],
) {
const a = aIn === "c" ? "f" : aIn;
const b = bIn === "c" ? "f" : bIn;
if (a === b) return 0;
if (a === "a") return -1;
if (b === "a") return 1;
if (a === "b") return -1;
if (b === "b") return 1;
if (a === "f") return -1;
if (b === "f") return 1;
if (a === "p") return 1;
if (b === "p") return -1;
if (a === "x") return -1;
if (b === "x") return 1;
return 0;
}