summaryrefslogtreecommitdiffhomepage
path: root/packages/kernel/src/host/version.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/kernel/src/host/version.ts')
-rw-r--r--packages/kernel/src/host/version.ts52
1 files changed, 52 insertions, 0 deletions
diff --git a/packages/kernel/src/host/version.ts b/packages/kernel/src/host/version.ts
new file mode 100644
index 0000000..0d62a3b
--- /dev/null
+++ b/packages/kernel/src/host/version.ts
@@ -0,0 +1,52 @@
+interface SemVer {
+ readonly major: number;
+ readonly minor: number;
+ readonly patch: number;
+}
+
+function parseSemVer(version: string): SemVer {
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
+ if (!match) throw new Error(`Invalid semver: "${version}"`);
+ return {
+ major: Number(match[1]),
+ minor: Number(match[2]),
+ patch: Number(match[3]),
+ };
+}
+
+function gte(a: SemVer, b: SemVer): boolean {
+ if (a.major !== b.major) return a.major > b.major;
+ if (a.minor !== b.minor) return a.minor > b.minor;
+ return a.patch >= b.patch;
+}
+
+export function isApiVersionCompatible(range: string, kernelVersion: string): boolean {
+ if (range === "*") return true;
+
+ const kernel = parseSemVer(kernelVersion);
+
+ if (range.startsWith("^")) {
+ const min = parseSemVer(range.slice(1));
+ if (!gte(kernel, min)) return false;
+ if (min.major === 0) {
+ return kernel.major === 0 && kernel.minor === min.minor;
+ }
+ return kernel.major === min.major;
+ }
+
+ if (range.startsWith("~")) {
+ const min = parseSemVer(range.slice(1));
+ if (!gte(kernel, min)) return false;
+ return kernel.major === min.major && kernel.minor === min.minor;
+ }
+
+ if (range.startsWith(">=")) {
+ const min = parseSemVer(range.slice(2));
+ return gte(kernel, min);
+ }
+
+ const exact = parseSemVer(range);
+ return (
+ kernel.major === exact.major && kernel.minor === exact.minor && kernel.patch === exact.patch
+ );
+}