@gjsify/semver 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,330 @@
1
+ const NUM_RE = /^(0|[1-9]\d*)$/;
2
+ const SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)(?:-((?:[0-9A-Za-z-]+)(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
3
+ function parse(version) {
4
+ try {
5
+ return new SemVer(version);
6
+ } catch {
7
+ return null;
8
+ }
9
+ }
10
+ function valid(version) {
11
+ const v = parse(version);
12
+ return v ? v.version : null;
13
+ }
14
+ function compare(a, b) {
15
+ const av = a instanceof SemVer ? a : new SemVer(a);
16
+ const bv = b instanceof SemVer ? b : new SemVer(b);
17
+ return av.compare(bv);
18
+ }
19
+ function satisfies(version, range) {
20
+ const r = range instanceof Range ? range : new Range(range);
21
+ const v = version instanceof SemVer ? version : parse(String(version));
22
+ if (!v) return false;
23
+ return r.test(v);
24
+ }
25
+ function maxSatisfying(versions, range) {
26
+ const r = range instanceof Range ? range : new Range(range);
27
+ let best = null;
28
+ for (const raw of versions) {
29
+ const v = parse(raw);
30
+ if (!v || !r.test(v)) continue;
31
+ if (best === null || v.compare(best) > 0) best = v;
32
+ }
33
+ return best ? best.version : null;
34
+ }
35
+ function minSatisfying(versions, range) {
36
+ const r = range instanceof Range ? range : new Range(range);
37
+ let best = null;
38
+ for (const raw of versions) {
39
+ const v = parse(raw);
40
+ if (!v || !r.test(v)) continue;
41
+ if (best === null || v.compare(best) < 0) best = v;
42
+ }
43
+ return best ? best.version : null;
44
+ }
45
+ function validRange(range) {
46
+ try {
47
+ return new Range(range).format();
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+ class SemVer {
53
+ major;
54
+ minor;
55
+ patch;
56
+ prerelease;
57
+ build;
58
+ version;
59
+ constructor(version) {
60
+ const trimmed = String(version).trim().replace(/^v/, "");
61
+ const m = SEMVER_RE.exec(trimmed);
62
+ if (!m) throw new TypeError(`Invalid Version: ${version}`);
63
+ this.major = Number(m[1]);
64
+ this.minor = Number(m[2]);
65
+ this.patch = Number(m[3]);
66
+ this.prerelease = m[4] ? m[4].split(".").map((id) => NUM_RE.test(id) ? Number(id) : id) : [];
67
+ this.build = m[5] ? m[5].split(".") : [];
68
+ this.version = `${this.major}.${this.minor}.${this.patch}` + (this.prerelease.length ? `-${this.prerelease.join(".")}` : "") + (this.build.length ? `+${this.build.join(".")}` : "");
69
+ }
70
+ compare(other) {
71
+ if (this.major !== other.major) return this.major < other.major ? -1 : 1;
72
+ if (this.minor !== other.minor) return this.minor < other.minor ? -1 : 1;
73
+ if (this.patch !== other.patch) return this.patch < other.patch ? -1 : 1;
74
+ return this.comparePre(other);
75
+ }
76
+ comparePre(other) {
77
+ const a = this.prerelease;
78
+ const b = other.prerelease;
79
+ if (a.length === 0 && b.length === 0) return 0;
80
+ if (a.length === 0) return 1;
81
+ if (b.length === 0) return -1;
82
+ for (let i = 0; ; i++) {
83
+ const x = a[i];
84
+ const y = b[i];
85
+ if (x === void 0 && y === void 0) return 0;
86
+ if (y === void 0) return 1;
87
+ if (x === void 0) return -1;
88
+ if (x === y) continue;
89
+ const xn = typeof x === "number";
90
+ const yn = typeof y === "number";
91
+ if (xn && !yn) return -1;
92
+ if (!xn && yn) return 1;
93
+ return x < y ? -1 : 1;
94
+ }
95
+ }
96
+ toString() {
97
+ return this.version;
98
+ }
99
+ }
100
+ class Range {
101
+ raw;
102
+ set;
103
+ constructor(range) {
104
+ if (range instanceof Range) {
105
+ this.raw = range.raw;
106
+ this.set = range.set;
107
+ return;
108
+ }
109
+ this.raw = String(range).trim();
110
+ const sets = this.raw.split(/\s*\|\|\s*/);
111
+ const parsed = [];
112
+ for (const part of sets) {
113
+ const c = parseRangePart(part);
114
+ if (c.length === 0) {
115
+ throw new TypeError(`Invalid range: ${this.raw}`);
116
+ }
117
+ parsed.push(c);
118
+ }
119
+ if (parsed.length === 0) {
120
+ throw new TypeError(`Invalid range: ${this.raw}`);
121
+ }
122
+ this.set = parsed;
123
+ }
124
+ test(version) {
125
+ const v = version instanceof SemVer ? version : parse(String(version));
126
+ if (!v) return false;
127
+ for (const conj of this.set) {
128
+ if (conj.every((c) => testComparator(c, v))) {
129
+ if (v.prerelease.length > 0) {
130
+ const allowed = conj.some(
131
+ (c) => c.semver !== null && c.semver.prerelease.length > 0 && c.semver.major === v.major && c.semver.minor === v.minor && c.semver.patch === v.patch
132
+ );
133
+ if (!allowed) continue;
134
+ }
135
+ return true;
136
+ }
137
+ }
138
+ return false;
139
+ }
140
+ format() {
141
+ return this.set.map((c) => c.map(formatComparator).join(" ")).join(" || ");
142
+ }
143
+ toString() {
144
+ return this.format();
145
+ }
146
+ }
147
+ function testComparator(c, v) {
148
+ if (c.semver === null) return true;
149
+ const cmp = v.compare(c.semver);
150
+ switch (c.operator) {
151
+ case "":
152
+ case "=":
153
+ return cmp === 0;
154
+ case "<":
155
+ return cmp < 0;
156
+ case "<=":
157
+ return cmp <= 0;
158
+ case ">":
159
+ return cmp > 0;
160
+ case ">=":
161
+ return cmp >= 0;
162
+ }
163
+ }
164
+ function formatComparator(c) {
165
+ if (c.semver === null) return "*";
166
+ return `${c.operator}${c.semver.version}`;
167
+ }
168
+ function parseRangePart(part) {
169
+ const trimmed = part.trim();
170
+ if (trimmed === "" || trimmed === "*" || trimmed.toLowerCase() === "latest") {
171
+ return [{ operator: ">=", semver: new SemVer("0.0.0") }];
172
+ }
173
+ const hyphen = trimmed.match(/^\s*(\S+)\s+-\s+(\S+)\s*$/);
174
+ if (hyphen) return hyphenRange(hyphen[1], hyphen[2]);
175
+ const tokens = trimmed.split(/\s+/);
176
+ const out = [];
177
+ for (const tok of tokens) out.push(...parseSimple(tok));
178
+ return out;
179
+ }
180
+ function parseSimple(tok) {
181
+ if (tok === "*" || tok === "" || tok.toLowerCase() === "latest") {
182
+ return [{ operator: ">=", semver: new SemVer("0.0.0") }];
183
+ }
184
+ if (tok.startsWith("^")) return caretRange(tok.slice(1));
185
+ if (tok.startsWith("~")) return tildeRange(tok.slice(1).replace(/^>/, ""));
186
+ const opMatch = tok.match(/^(<=|>=|<|>|=)\s*(.+)$/);
187
+ if (opMatch) {
188
+ const op = opMatch[1];
189
+ return primitiveRange(op, opMatch[2]);
190
+ }
191
+ return partialRange(tok);
192
+ }
193
+ function parsePartial(s) {
194
+ const trimmed = s.trim().replace(/^v/, "");
195
+ if (trimmed === "" || trimmed === "*") {
196
+ return { major: null, minor: null, patch: null, pre: "", build: "" };
197
+ }
198
+ let pre = "";
199
+ let build = "";
200
+ let core = trimmed;
201
+ const plus = core.indexOf("+");
202
+ if (plus >= 0) {
203
+ build = core.slice(plus + 1);
204
+ core = core.slice(0, plus);
205
+ }
206
+ const dash = core.indexOf("-");
207
+ if (dash >= 0) {
208
+ pre = core.slice(dash + 1);
209
+ core = core.slice(0, dash);
210
+ }
211
+ const parts = core.split(".");
212
+ const xr = (part) => {
213
+ if (part === void 0 || part === "") return null;
214
+ if (part === "x" || part === "X" || part === "*") return null;
215
+ if (!/^\d+$/.test(part)) {
216
+ throw new TypeError(`Invalid partial version: ${s}`);
217
+ }
218
+ return Number(part);
219
+ };
220
+ return {
221
+ major: xr(parts[0]),
222
+ minor: xr(parts[1]),
223
+ patch: xr(parts[2]),
224
+ pre,
225
+ build
226
+ };
227
+ }
228
+ function partialToVersion(p) {
229
+ return `${p.major ?? 0}.${p.minor ?? 0}.${p.patch ?? 0}${p.pre ? `-${p.pre}` : ""}${p.build ? `+${p.build}` : ""}`;
230
+ }
231
+ function partialRange(tok) {
232
+ const p = parsePartial(tok);
233
+ if (p.major === null) return [{ operator: ">=", semver: new SemVer("0.0.0") }];
234
+ if (p.minor === null) {
235
+ return [
236
+ { operator: ">=", semver: new SemVer(`${p.major}.0.0`) },
237
+ { operator: "<", semver: new SemVer(`${p.major + 1}.0.0`) }
238
+ ];
239
+ }
240
+ if (p.patch === null) {
241
+ return [
242
+ { operator: ">=", semver: new SemVer(`${p.major}.${p.minor}.0`) },
243
+ { operator: "<", semver: new SemVer(`${p.major}.${p.minor + 1}.0`) }
244
+ ];
245
+ }
246
+ return [{ operator: "=", semver: new SemVer(partialToVersion(p)) }];
247
+ }
248
+ function caretRange(tok) {
249
+ const p = parsePartial(tok);
250
+ if (p.major === null) return [{ operator: ">=", semver: new SemVer("0.0.0") }];
251
+ const lower = `${p.major}.${p.minor ?? 0}.${p.patch ?? 0}${p.pre ? `-${p.pre}` : ""}`;
252
+ let upper;
253
+ if (p.major > 0 || p.minor === null) {
254
+ upper = `${p.major + 1}.0.0`;
255
+ } else if (p.minor > 0 || p.patch === null) {
256
+ upper = `0.${p.minor + 1}.0`;
257
+ } else {
258
+ upper = `0.0.${p.patch + 1}`;
259
+ }
260
+ return [
261
+ { operator: ">=", semver: new SemVer(lower) },
262
+ { operator: "<", semver: new SemVer(upper) }
263
+ ];
264
+ }
265
+ function tildeRange(tok) {
266
+ const p = parsePartial(tok);
267
+ if (p.major === null) return [{ operator: ">=", semver: new SemVer("0.0.0") }];
268
+ const lower = `${p.major}.${p.minor ?? 0}.${p.patch ?? 0}${p.pre ? `-${p.pre}` : ""}`;
269
+ const upper = p.minor === null ? `${p.major + 1}.0.0` : `${p.major}.${p.minor + 1}.0`;
270
+ return [
271
+ { operator: ">=", semver: new SemVer(lower) },
272
+ { operator: "<", semver: new SemVer(upper) }
273
+ ];
274
+ }
275
+ function primitiveRange(op, rhs) {
276
+ const p = parsePartial(rhs);
277
+ if (p.major === null) return [{ operator: ">=", semver: new SemVer("0.0.0") }];
278
+ if (op === "=" || op === "") return partialRange(rhs);
279
+ if (op === ">") {
280
+ if (p.minor === null) return [{ operator: ">=", semver: new SemVer(`${p.major + 1}.0.0`) }];
281
+ if (p.patch === null) return [{ operator: ">=", semver: new SemVer(`${p.major}.${p.minor + 1}.0`) }];
282
+ return [{ operator: ">", semver: new SemVer(partialToVersion(p)) }];
283
+ }
284
+ if (op === "<") {
285
+ if (p.minor === null) return [{ operator: "<", semver: new SemVer(`${p.major}.0.0`) }];
286
+ if (p.patch === null) return [{ operator: "<", semver: new SemVer(`${p.major}.${p.minor}.0`) }];
287
+ return [{ operator: "<", semver: new SemVer(partialToVersion(p)) }];
288
+ }
289
+ if (op === ">=") return [{ operator: ">=", semver: new SemVer(partialToVersion(p)) }];
290
+ if (p.minor === null) return [{ operator: "<", semver: new SemVer(`${p.major + 1}.0.0`) }];
291
+ if (p.patch === null) return [{ operator: "<", semver: new SemVer(`${p.major}.${p.minor + 1}.0`) }];
292
+ return [{ operator: "<=", semver: new SemVer(partialToVersion(p)) }];
293
+ }
294
+ function hyphenRange(left, right) {
295
+ const a = parsePartial(left);
296
+ const b = parsePartial(right);
297
+ const lower = a.major === null ? { operator: ">=", semver: new SemVer("0.0.0") } : {
298
+ operator: ">=",
299
+ semver: new SemVer(
300
+ `${a.major}.${a.minor ?? 0}.${a.patch ?? 0}${a.pre ? `-${a.pre}` : ""}`
301
+ )
302
+ };
303
+ let upper;
304
+ if (b.major === null) {
305
+ upper = { operator: ">=", semver: new SemVer("0.0.0") };
306
+ } else if (b.minor === null) {
307
+ upper = { operator: "<", semver: new SemVer(`${b.major + 1}.0.0`) };
308
+ } else if (b.patch === null) {
309
+ upper = { operator: "<", semver: new SemVer(`${b.major}.${b.minor + 1}.0`) };
310
+ } else {
311
+ upper = {
312
+ operator: "<=",
313
+ semver: new SemVer(
314
+ `${b.major}.${b.minor}.${b.patch}${b.pre ? `-${b.pre}` : ""}`
315
+ )
316
+ };
317
+ }
318
+ return [lower, upper];
319
+ }
320
+ export {
321
+ Range,
322
+ SemVer,
323
+ compare,
324
+ maxSatisfying,
325
+ minSatisfying,
326
+ parse,
327
+ satisfies,
328
+ valid,
329
+ validRange
330
+ };
@@ -0,0 +1 @@
1
+ {"fileNames":["../../../../node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../../node_modules/typescript/lib/lib.es2023.d.ts","../../../../node_modules/typescript/lib/lib.es2024.d.ts","../../../../node_modules/typescript/lib/lib.es2025.d.ts","../../../../node_modules/typescript/lib/lib.esnext.d.ts","../../../../node_modules/typescript/lib/lib.dom.d.ts","../../../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../../node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../../node_modules/typescript/lib/lib.scripthost.d.ts","../../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../../../node_modules/typescript/lib/lib.es2024.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2024.object.d.ts","../../../../node_modules/typescript/lib/lib.es2024.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2024.string.d.ts","../../../../node_modules/typescript/lib/lib.es2025.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2025.float16.d.ts","../../../../node_modules/typescript/lib/lib.es2025.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2025.iterator.d.ts","../../../../node_modules/typescript/lib/lib.es2025.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2025.regexp.d.ts","../../../../node_modules/typescript/lib/lib.esnext.array.d.ts","../../../../node_modules/typescript/lib/lib.esnext.collection.d.ts","../../../../node_modules/typescript/lib/lib.esnext.date.d.ts","../../../../node_modules/typescript/lib/lib.esnext.decorators.d.ts","../../../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../../../node_modules/typescript/lib/lib.esnext.error.d.ts","../../../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../../../node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.esnext.temporal.d.ts","../../../../node_modules/typescript/lib/lib.esnext.typedarrays.d.ts","../../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../../node_modules/typescript/lib/lib.esnext.full.d.ts","../src/index.ts"],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"1e9332c23e9a907175e0ffc6a49e236f97b48838cc8aec9ce7e4cec21e544b65","impliedFormat":1},{"version":"3753fbc1113dc511214802a2342280a8b284ab9094f6420e7aa171e868679f91","impliedFormat":1},{"version":"999ca32883495a866aa5737fe1babc764a469e4cde6ee6b136a4b9ae68853e4b","impliedFormat":1},{"version":"17f13ecb98cbc39243f2eee1f16d45cd8ec4706b03ee314f1915f1a8b42f6984","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"2a2de5b9459b3fc44decd9ce6100b72f1b002ef523126c1d3d8b2a4a63d74d78","affectsGlobalScope":true,"impliedFormat":1},{"version":"f13f4b465c99041e912db5c44129a94588e1aafee35a50eab51044833f50b4ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"0bd714129fca875f7d4c477a1a392200b0bcd13fb2e80928cd334b63830ea047","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2c9037ae6cd2c52d80ceef0b3c5ffdb488627d71529cf4f63776daf11161c9a","affectsGlobalScope":true,"impliedFormat":1},{"version":"135d5cf4d345f59f1a9caadfafcd858d3d9cc68290db616cc85797224448cccc","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc238c3f81c2984751932b6aab223cd5b830e0ac6cad76389e5e9d2ffc03287d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4a07f9b76d361f572620927e5735b77d6d2101c23cdd94383eb5b706e7b36357","affectsGlobalScope":true,"impliedFormat":1},{"version":"7c4e8dc6ab834cc6baa0227e030606d29e3e8449a9f67cdf5605ea5493c4db29","affectsGlobalScope":true,"impliedFormat":1},{"version":"de7ba0fd02e06cd9a5bd4ab441ed0e122735786e67dde1e849cced1cd8b46b78","affectsGlobalScope":true,"impliedFormat":1},{"version":"6148e4e88d720a06855071c3db02069434142a8332cf9c182cda551adedf3156","affectsGlobalScope":true,"impliedFormat":1},{"version":"d63dba625b108316a40c95a4425f8d4294e0deeccfd6c7e59d819efa19e23409","affectsGlobalScope":true,"impliedFormat":1},{"version":"0568d6befee03dd435bed4fc25c4e46865b24bdcb8c563fdc21f580a2c301904","affectsGlobalScope":true,"impliedFormat":1},{"version":"30d62269b05b584741f19a5369852d5d34895aa2ac4fd948956f886d15f9cc0d","affectsGlobalScope":true,"impliedFormat":1},{"version":"f128dae7c44d8f35ee42e0a437000a57c9f06cc04f8b4fb42eebf44954d53dc8","affectsGlobalScope":true,"impliedFormat":1},{"version":"ffbe6d7b295306b2ba88030f65b74c107d8d99bdcf596ea99c62a02f606108b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"996fb27b15277369c68a4ba46ed138b4e9e839a02fb4ec756f7997629242fd9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"79b712591b270d4778c89706ca2cfc56ddb8c3f895840e477388f1710dc5eda9","affectsGlobalScope":true,"impliedFormat":1},{"version":"20884846cef428b992b9bd032e70a4ef88e349263f63aeddf04dda837a7dba26","affectsGlobalScope":true,"impliedFormat":1},{"version":"5fcab789c73a97cd43828ee3cc94a61264cf24d4c44472ce64ced0e0f148bdb2","affectsGlobalScope":true,"impliedFormat":1},{"version":"db59a81f070c1880ad645b2c0275022baa6a0c4f0acdc58d29d349c6efcf0903","affectsGlobalScope":true,"impliedFormat":1},{"version":"673294292640f5722b700e7d814e17aaf7d93f83a48a2c9b38f33cbc940ad8b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"d786b48f934cbca483b3c6d0a798cb43bbb4ada283e76fb22c28e53ae05b9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ecb8e347cb6b2a8927c09b86263663289418df375f5e68e11a0ae683776978f","affectsGlobalScope":true,"impliedFormat":1},{"version":"142efd4ce210576f777dc34df121777be89eda476942d6d6663b03dcb53be3ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"379bc41580c2d774f82e828c70308f24a005b490c25ba34d679d84bcf05c3d9d","affectsGlobalScope":true,"impliedFormat":1},{"version":"ed484fb2aa8a1a23d0277056ec3336e0a0b52f9b8d6a961f338a642faf43235d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ffedae1d1c2d53fdbca1c96d3c7dda544281f7d262f99b6880634f8fd8d9820","affectsGlobalScope":true,"impliedFormat":1},{"version":"83a730b125d477dd264df8ba479afab27a3dae7152b005c214ab94dc7ee44fd3","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"ef4a897cd2a3f91000c10264e400b3667c7e51e1b7365f03b62e8081dc53bde6","impliedFormat":1},{"version":"6be8a27016e6c12deef9d45a9c5349dacc2b46dab2f3b2f4eed56ce3a0ba7e02","signature":"6b8091108ad58d10b0bd314d33d73ca1d0f4d5a6db9a688ed78da95265b15516"}],"root":[94],"options":{"allowImportingTsExtensions":false,"composite":true,"declaration":true,"declarationDir":"./types","experimentalDecorators":true,"module":99,"outDir":"./esm","rootDir":"../src","skipLibCheck":true,"strict":true,"target":99},"latestChangedDtsFile":"./types/index.d.ts","version":"6.0.3"}
@@ -0,0 +1,33 @@
1
+ export type ReleaseType = "major" | "minor" | "patch";
2
+ export declare function parse(version: string): SemVer | null;
3
+ export declare function valid(version: string): string | null;
4
+ export declare function compare(a: string | SemVer, b: string | SemVer): -1 | 0 | 1;
5
+ export declare function satisfies(version: string | SemVer, range: string | Range): boolean;
6
+ export declare function maxSatisfying(versions: ReadonlyArray<string>, range: string | Range): string | null;
7
+ export declare function minSatisfying(versions: ReadonlyArray<string>, range: string | Range): string | null;
8
+ export declare function validRange(range: string): string | null;
9
+ export declare class SemVer {
10
+ readonly major: number;
11
+ readonly minor: number;
12
+ readonly patch: number;
13
+ readonly prerelease: ReadonlyArray<string | number>;
14
+ readonly build: ReadonlyArray<string>;
15
+ readonly version: string;
16
+ constructor(version: string);
17
+ compare(other: SemVer): -1 | 0 | 1;
18
+ comparePre(other: SemVer): -1 | 0 | 1;
19
+ toString(): string;
20
+ }
21
+ interface Comparator {
22
+ operator: "" | "<" | ">" | "<=" | ">=" | "=";
23
+ semver: SemVer | null;
24
+ }
25
+ export declare class Range {
26
+ readonly raw: string;
27
+ readonly set: ReadonlyArray<ReadonlyArray<Comparator>>;
28
+ constructor(range: string | Range);
29
+ test(version: SemVer | string): boolean;
30
+ format(): string;
31
+ toString(): string;
32
+ }
33
+ export {};
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@gjsify/semver",
3
+ "version": "0.3.8",
4
+ "description": "Subset of node-semver for the gjsify install backend — cross-platform Node + GJS",
5
+ "type": "module",
6
+ "module": "lib/esm/index.js",
7
+ "main": "lib/esm/index.js",
8
+ "types": "lib/types/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./lib/types/index.d.ts",
12
+ "default": "./lib/esm/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "clear": "rm -rf lib tsconfig.tsbuildinfo test.gjs.mjs test.node.mjs || exit 0",
17
+ "check": "tsc --noEmit",
18
+ "build": "yarn build:gjsify && yarn build:types",
19
+ "build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.mts'",
20
+ "build:types": "tsc -p tsconfig.build.json",
21
+ "build:test": "yarn build:test:gjs && yarn build:test:node",
22
+ "build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
23
+ "build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
24
+ "test": "yarn build:gjsify && yarn build:test && yarn test:node && yarn test:gjs",
25
+ "test:gjs": "gjsify run test.gjs.mjs",
26
+ "test:node": "node test.node.mjs"
27
+ },
28
+ "keywords": [
29
+ "gjs",
30
+ "node",
31
+ "semver",
32
+ "install"
33
+ ],
34
+ "license": "MIT",
35
+ "devDependencies": {
36
+ "@gjsify/cli": "^0.3.8",
37
+ "@gjsify/unit": "^0.3.8",
38
+ "typescript": "^6.0.3"
39
+ }
40
+ }
@@ -0,0 +1,197 @@
1
+ import { describe, it, expect } from "@gjsify/unit";
2
+ import {
3
+ SemVer,
4
+ Range,
5
+ parse,
6
+ valid,
7
+ compare,
8
+ satisfies,
9
+ maxSatisfying,
10
+ minSatisfying,
11
+ validRange,
12
+ } from "./index.js";
13
+
14
+ export default async () => {
15
+ await describe("@gjsify/semver — SemVer", async () => {
16
+ await it("parses major.minor.patch", async () => {
17
+ const v = new SemVer("1.2.3");
18
+ expect(v.major).toBe(1);
19
+ expect(v.minor).toBe(2);
20
+ expect(v.patch).toBe(3);
21
+ expect(v.version).toBe("1.2.3");
22
+ });
23
+
24
+ await it("parses prerelease + build", async () => {
25
+ const v = new SemVer("1.2.3-alpha.1+build.7");
26
+ expect(v.prerelease.length).toBe(2);
27
+ expect(v.prerelease[0]).toBe("alpha");
28
+ expect(v.prerelease[1]).toBe(1);
29
+ expect(v.build[0]).toBe("build");
30
+ expect(v.version).toBe("1.2.3-alpha.1+build.7");
31
+ });
32
+
33
+ await it("strips leading v", async () => {
34
+ expect(new SemVer("v1.2.3").version).toBe("1.2.3");
35
+ });
36
+
37
+ await it("rejects garbage", async () => {
38
+ expect(parse("not-a-version")).toBeNull();
39
+ expect(parse("1.2")).toBeNull();
40
+ expect(valid("1.2.3.4")).toBeNull();
41
+ });
42
+
43
+ await it("compares major/minor/patch", async () => {
44
+ expect(compare("1.0.0", "2.0.0")).toBe(-1);
45
+ expect(compare("1.2.3", "1.2.3")).toBe(0);
46
+ expect(compare("1.2.10", "1.2.9")).toBe(1);
47
+ });
48
+
49
+ await it("non-prerelease > any prerelease", async () => {
50
+ expect(compare("1.0.0", "1.0.0-alpha")).toBe(1);
51
+ expect(compare("1.0.0-alpha", "1.0.0")).toBe(-1);
52
+ });
53
+
54
+ await it("compares prerelease tags by parts (numeric < alpha)", async () => {
55
+ expect(compare("1.0.0-alpha", "1.0.0-alpha.1")).toBe(-1);
56
+ expect(compare("1.0.0-alpha.1", "1.0.0-alpha.2")).toBe(-1);
57
+ expect(compare("1.0.0-alpha.10", "1.0.0-alpha.9")).toBe(1);
58
+ expect(compare("1.0.0-alpha", "1.0.0-beta")).toBe(-1);
59
+ expect(compare("1.0.0-1", "1.0.0-alpha")).toBe(-1); // numeric < alpha
60
+ });
61
+ });
62
+
63
+ await describe("@gjsify/semver — Range", async () => {
64
+ await it("caret narrows on 0.x.y", async () => {
65
+ const r = new Range("^0.3.7");
66
+ expect(r.test(new SemVer("0.3.7"))).toBe(true);
67
+ expect(r.test(new SemVer("0.3.99"))).toBe(true);
68
+ expect(r.test(new SemVer("0.4.0"))).toBe(false);
69
+ expect(r.test(new SemVer("0.3.6"))).toBe(false);
70
+ });
71
+
72
+ await it("caret on >=1 keeps the major", async () => {
73
+ const r = new Range("^1.2.3");
74
+ expect(r.test("1.2.3")).toBe(true);
75
+ expect(r.test("1.999.999")).toBe(true);
76
+ expect(r.test("2.0.0")).toBe(false);
77
+ expect(r.test("1.2.2")).toBe(false);
78
+ });
79
+
80
+ await it("caret 0.0.x is exact", async () => {
81
+ const r = new Range("^0.0.3");
82
+ expect(r.test("0.0.3")).toBe(true);
83
+ expect(r.test("0.0.4")).toBe(false);
84
+ });
85
+
86
+ await it("tilde", async () => {
87
+ const r = new Range("~1.2.3");
88
+ expect(r.test("1.2.3")).toBe(true);
89
+ expect(r.test("1.2.99")).toBe(true);
90
+ expect(r.test("1.3.0")).toBe(false);
91
+ expect(r.test("1.2.2")).toBe(false);
92
+ });
93
+
94
+ await it("x-ranges", async () => {
95
+ expect(satisfies("1.2.3", "1.x")).toBe(true);
96
+ expect(satisfies("2.0.0", "1.x")).toBe(false);
97
+ expect(satisfies("1.2.99", "1.2.x")).toBe(true);
98
+ expect(satisfies("1.3.0", "1.2.x")).toBe(false);
99
+ });
100
+
101
+ await it("primitives", async () => {
102
+ expect(satisfies("1.2.3", ">=1.0.0 <2.0.0")).toBe(true);
103
+ expect(satisfies("2.0.0", ">=1.0.0 <2.0.0")).toBe(false);
104
+ expect(satisfies("1.2.3", ">1.2.2")).toBe(true);
105
+ expect(satisfies("1.2.2", ">1.2.2")).toBe(false);
106
+ expect(satisfies("1.2.3", "<=1.2.3")).toBe(true);
107
+ });
108
+
109
+ await it("primitives on partial RHS", async () => {
110
+ expect(satisfies("2.0.0", ">1")).toBe(true);
111
+ expect(satisfies("1.5.0", ">1")).toBe(false);
112
+ expect(satisfies("0.9.0", "<1")).toBe(true);
113
+ expect(satisfies("1.0.0", "<1")).toBe(false);
114
+ expect(satisfies("1.9.9", "<=1")).toBe(true);
115
+ expect(satisfies("2.0.0", "<=1")).toBe(false);
116
+ });
117
+
118
+ await it("hyphen ranges", async () => {
119
+ const r = new Range("1.2.3 - 2.3.4");
120
+ expect(r.test("1.2.3")).toBe(true);
121
+ expect(r.test("2.0.0")).toBe(true);
122
+ expect(r.test("2.3.4")).toBe(true);
123
+ expect(r.test("2.3.5")).toBe(false);
124
+ expect(r.test("1.2.2")).toBe(false);
125
+ });
126
+
127
+ await it("partial hyphen RHS extends", async () => {
128
+ const r = new Range("1.2.3 - 2.3");
129
+ expect(r.test("2.3.99")).toBe(true);
130
+ expect(r.test("2.4.0")).toBe(false);
131
+ });
132
+
133
+ await it("OR sets", async () => {
134
+ const r = new Range("^1.0.0 || ^2.0.0");
135
+ expect(r.test("1.5.0")).toBe(true);
136
+ expect(r.test("2.5.0")).toBe(true);
137
+ expect(r.test("3.0.0")).toBe(false);
138
+ });
139
+
140
+ await it("star/* matches anything stable", async () => {
141
+ expect(satisfies("0.0.0", "*")).toBe(true);
142
+ expect(satisfies("99.99.99", "*")).toBe(true);
143
+ });
144
+
145
+ await it("rejects prereleases unless explicitly mentioned", async () => {
146
+ expect(satisfies("1.2.3-alpha", ">=1.0.0")).toBe(false);
147
+ expect(satisfies("1.2.3-alpha", ">=1.2.3-alpha")).toBe(true);
148
+ expect(satisfies("1.2.3-beta", ">=1.2.3-alpha")).toBe(true);
149
+ // Different mmp tuple — not eligible.
150
+ expect(satisfies("1.3.0-beta", ">=1.2.3-alpha")).toBe(false);
151
+ });
152
+
153
+ await it("validRange formats / rejects garbage", async () => {
154
+ expect(validRange("^1.2.3")).toBe(">=1.2.3 <2.0.0");
155
+ expect(validRange("not-a-range !!")).toBeNull();
156
+ });
157
+ });
158
+
159
+ await describe("@gjsify/semver — maxSatisfying / minSatisfying", async () => {
160
+ const versions = [
161
+ "0.0.1",
162
+ "0.1.0",
163
+ "0.3.6",
164
+ "0.3.7",
165
+ "0.3.7-rc.1",
166
+ "1.0.0",
167
+ "1.2.3",
168
+ "2.0.0-rc.1",
169
+ "2.0.0",
170
+ ];
171
+
172
+ await it("maxSatisfying ^0.3.0", async () => {
173
+ expect(maxSatisfying(versions, "^0.3.0")).toBe("0.3.7");
174
+ });
175
+
176
+ await it("maxSatisfying ^1.0.0", async () => {
177
+ expect(maxSatisfying(versions, "^1.0.0")).toBe("1.2.3");
178
+ });
179
+
180
+ await it("maxSatisfying *", async () => {
181
+ expect(maxSatisfying(versions, "*")).toBe("2.0.0");
182
+ });
183
+
184
+ await it("minSatisfying >=1", async () => {
185
+ expect(minSatisfying(versions, ">=1")).toBe("1.0.0");
186
+ });
187
+
188
+ await it("returns null for empty match", async () => {
189
+ expect(maxSatisfying(versions, "^9.0.0")).toBeNull();
190
+ expect(minSatisfying([], "*")).toBeNull();
191
+ });
192
+
193
+ await it("ignores invalid version strings", async () => {
194
+ expect(maxSatisfying(["1.0.0", "garbage", "1.1.0"], "^1.0.0")).toBe("1.1.0");
195
+ });
196
+ });
197
+ };
package/src/index.ts ADDED
@@ -0,0 +1,386 @@
1
+ // SemVer - subset of node-semver for the gjsify install backend.
2
+ // Implements parse, compare, satisfies, maxSatisfying, minSatisfying, and Range
3
+ // for caret/tilde/hyphen/x/star/comparator/OR ranges.
4
+ // Reference: https://semver.org/spec/v2.0.0.html and refs/npm-cli/.../semver/.
5
+
6
+ const NUM_RE = /^(0|[1-9]\d*)$/;
7
+ const SEMVER_RE =
8
+ /^(\d+)\.(\d+)\.(\d+)(?:-((?:[0-9A-Za-z-]+)(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
9
+
10
+ export type ReleaseType = "major" | "minor" | "patch";
11
+
12
+ export function parse(version: string): SemVer | null {
13
+ try {
14
+ return new SemVer(version);
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+
20
+ export function valid(version: string): string | null {
21
+ const v = parse(version);
22
+ return v ? v.version : null;
23
+ }
24
+
25
+ export function compare(a: string | SemVer, b: string | SemVer): -1 | 0 | 1 {
26
+ const av = a instanceof SemVer ? a : new SemVer(a);
27
+ const bv = b instanceof SemVer ? b : new SemVer(b);
28
+ return av.compare(bv);
29
+ }
30
+
31
+ export function satisfies(version: string | SemVer, range: string | Range): boolean {
32
+ const r = range instanceof Range ? range : new Range(range);
33
+ const v = version instanceof SemVer ? version : parse(String(version));
34
+ if (!v) return false;
35
+ return r.test(v);
36
+ }
37
+
38
+ export function maxSatisfying(versions: ReadonlyArray<string>, range: string | Range): string | null {
39
+ const r = range instanceof Range ? range : new Range(range);
40
+ let best: SemVer | null = null;
41
+ for (const raw of versions) {
42
+ const v = parse(raw);
43
+ if (!v || !r.test(v)) continue;
44
+ if (best === null || v.compare(best) > 0) best = v;
45
+ }
46
+ return best ? best.version : null;
47
+ }
48
+
49
+ export function minSatisfying(versions: ReadonlyArray<string>, range: string | Range): string | null {
50
+ const r = range instanceof Range ? range : new Range(range);
51
+ let best: SemVer | null = null;
52
+ for (const raw of versions) {
53
+ const v = parse(raw);
54
+ if (!v || !r.test(v)) continue;
55
+ if (best === null || v.compare(best) < 0) best = v;
56
+ }
57
+ return best ? best.version : null;
58
+ }
59
+
60
+ export function validRange(range: string): string | null {
61
+ try {
62
+ return new Range(range).format();
63
+ } catch {
64
+ return null;
65
+ }
66
+ }
67
+
68
+ export class SemVer {
69
+ readonly major: number;
70
+ readonly minor: number;
71
+ readonly patch: number;
72
+ readonly prerelease: ReadonlyArray<string | number>;
73
+ readonly build: ReadonlyArray<string>;
74
+ readonly version: string;
75
+
76
+ constructor(version: string) {
77
+ const trimmed = String(version).trim().replace(/^v/, "");
78
+ const m = SEMVER_RE.exec(trimmed);
79
+ if (!m) throw new TypeError(`Invalid Version: ${version}`);
80
+ this.major = Number(m[1]);
81
+ this.minor = Number(m[2]);
82
+ this.patch = Number(m[3]);
83
+ this.prerelease = m[4]
84
+ ? m[4].split(".").map((id) => (NUM_RE.test(id) ? Number(id) : id))
85
+ : [];
86
+ this.build = m[5] ? m[5].split(".") : [];
87
+ this.version =
88
+ `${this.major}.${this.minor}.${this.patch}` +
89
+ (this.prerelease.length ? `-${this.prerelease.join(".")}` : "") +
90
+ (this.build.length ? `+${this.build.join(".")}` : "");
91
+ }
92
+
93
+ compare(other: SemVer): -1 | 0 | 1 {
94
+ if (this.major !== other.major) return this.major < other.major ? -1 : 1;
95
+ if (this.minor !== other.minor) return this.minor < other.minor ? -1 : 1;
96
+ if (this.patch !== other.patch) return this.patch < other.patch ? -1 : 1;
97
+ return this.comparePre(other);
98
+ }
99
+
100
+ comparePre(other: SemVer): -1 | 0 | 1 {
101
+ const a = this.prerelease;
102
+ const b = other.prerelease;
103
+ if (a.length === 0 && b.length === 0) return 0;
104
+ if (a.length === 0) return 1;
105
+ if (b.length === 0) return -1;
106
+ for (let i = 0; ; i++) {
107
+ const x = a[i];
108
+ const y = b[i];
109
+ if (x === undefined && y === undefined) return 0;
110
+ if (y === undefined) return 1;
111
+ if (x === undefined) return -1;
112
+ if (x === y) continue;
113
+ const xn = typeof x === "number";
114
+ const yn = typeof y === "number";
115
+ if (xn && !yn) return -1;
116
+ if (!xn && yn) return 1;
117
+ return x < y ? -1 : 1;
118
+ }
119
+ }
120
+
121
+ toString(): string {
122
+ return this.version;
123
+ }
124
+ }
125
+
126
+ interface Comparator {
127
+ operator: "" | "<" | ">" | "<=" | ">=" | "=";
128
+ semver: SemVer | null;
129
+ }
130
+
131
+ export class Range {
132
+ readonly raw: string;
133
+ readonly set: ReadonlyArray<ReadonlyArray<Comparator>>;
134
+
135
+ constructor(range: string | Range) {
136
+ if (range instanceof Range) {
137
+ this.raw = range.raw;
138
+ this.set = range.set;
139
+ return;
140
+ }
141
+ this.raw = String(range).trim();
142
+ const sets = this.raw.split(/\s*\|\|\s*/);
143
+ const parsed: Comparator[][] = [];
144
+ for (const part of sets) {
145
+ const c = parseRangePart(part);
146
+ if (c.length === 0) {
147
+ throw new TypeError(`Invalid range: ${this.raw}`);
148
+ }
149
+ parsed.push(c);
150
+ }
151
+ if (parsed.length === 0) {
152
+ throw new TypeError(`Invalid range: ${this.raw}`);
153
+ }
154
+ this.set = parsed;
155
+ }
156
+
157
+ test(version: SemVer | string): boolean {
158
+ const v = version instanceof SemVer ? version : parse(String(version));
159
+ if (!v) return false;
160
+ for (const conj of this.set) {
161
+ if (conj.every((c) => testComparator(c, v))) {
162
+ if (v.prerelease.length > 0) {
163
+ const allowed = conj.some(
164
+ (c) =>
165
+ c.semver !== null &&
166
+ c.semver.prerelease.length > 0 &&
167
+ c.semver.major === v.major &&
168
+ c.semver.minor === v.minor &&
169
+ c.semver.patch === v.patch,
170
+ );
171
+ if (!allowed) continue;
172
+ }
173
+ return true;
174
+ }
175
+ }
176
+ return false;
177
+ }
178
+
179
+ format(): string {
180
+ return this.set.map((c) => c.map(formatComparator).join(" ")).join(" || ");
181
+ }
182
+
183
+ toString(): string {
184
+ return this.format();
185
+ }
186
+ }
187
+
188
+ function testComparator(c: Comparator, v: SemVer): boolean {
189
+ if (c.semver === null) return true;
190
+ const cmp = v.compare(c.semver);
191
+ switch (c.operator) {
192
+ case "":
193
+ case "=":
194
+ return cmp === 0;
195
+ case "<":
196
+ return cmp < 0;
197
+ case "<=":
198
+ return cmp <= 0;
199
+ case ">":
200
+ return cmp > 0;
201
+ case ">=":
202
+ return cmp >= 0;
203
+ }
204
+ }
205
+
206
+ function formatComparator(c: Comparator): string {
207
+ if (c.semver === null) return "*";
208
+ return `${c.operator}${c.semver.version}`;
209
+ }
210
+
211
+ function parseRangePart(part: string): Comparator[] {
212
+ const trimmed = part.trim();
213
+ if (trimmed === "" || trimmed === "*" || trimmed.toLowerCase() === "latest") {
214
+ return [{ operator: ">=", semver: new SemVer("0.0.0") }];
215
+ }
216
+ const hyphen = trimmed.match(/^\s*(\S+)\s+-\s+(\S+)\s*$/);
217
+ if (hyphen) return hyphenRange(hyphen[1], hyphen[2]);
218
+ const tokens = trimmed.split(/\s+/);
219
+ const out: Comparator[] = [];
220
+ for (const tok of tokens) out.push(...parseSimple(tok));
221
+ return out;
222
+ }
223
+
224
+ function parseSimple(tok: string): Comparator[] {
225
+ if (tok === "*" || tok === "" || tok.toLowerCase() === "latest") {
226
+ return [{ operator: ">=", semver: new SemVer("0.0.0") }];
227
+ }
228
+ if (tok.startsWith("^")) return caretRange(tok.slice(1));
229
+ if (tok.startsWith("~")) return tildeRange(tok.slice(1).replace(/^>/, ""));
230
+ const opMatch = tok.match(/^(<=|>=|<|>|=)\s*(.+)$/);
231
+ if (opMatch) {
232
+ const op = opMatch[1] as Comparator["operator"];
233
+ return primitiveRange(op, opMatch[2]);
234
+ }
235
+ return partialRange(tok);
236
+ }
237
+
238
+ interface PartialVersion {
239
+ major: number | null;
240
+ minor: number | null;
241
+ patch: number | null;
242
+ pre: string;
243
+ build: string;
244
+ }
245
+
246
+ function parsePartial(s: string): PartialVersion {
247
+ const trimmed = s.trim().replace(/^v/, "");
248
+ if (trimmed === "" || trimmed === "*") {
249
+ return { major: null, minor: null, patch: null, pre: "", build: "" };
250
+ }
251
+ let pre = "";
252
+ let build = "";
253
+ let core = trimmed;
254
+ const plus = core.indexOf("+");
255
+ if (plus >= 0) {
256
+ build = core.slice(plus + 1);
257
+ core = core.slice(0, plus);
258
+ }
259
+ const dash = core.indexOf("-");
260
+ if (dash >= 0) {
261
+ pre = core.slice(dash + 1);
262
+ core = core.slice(0, dash);
263
+ }
264
+ const parts = core.split(".");
265
+ const xr = (part: string | undefined): number | null => {
266
+ if (part === undefined || part === "") return null;
267
+ if (part === "x" || part === "X" || part === "*") return null;
268
+ if (!/^\d+$/.test(part)) {
269
+ throw new TypeError(`Invalid partial version: ${s}`);
270
+ }
271
+ return Number(part);
272
+ };
273
+ return {
274
+ major: xr(parts[0]),
275
+ minor: xr(parts[1]),
276
+ patch: xr(parts[2]),
277
+ pre,
278
+ build,
279
+ };
280
+ }
281
+
282
+ function partialToVersion(p: PartialVersion): string {
283
+ return `${p.major ?? 0}.${p.minor ?? 0}.${p.patch ?? 0}${p.pre ? `-${p.pre}` : ""}${
284
+ p.build ? `+${p.build}` : ""
285
+ }`;
286
+ }
287
+
288
+ function partialRange(tok: string): Comparator[] {
289
+ const p = parsePartial(tok);
290
+ if (p.major === null) return [{ operator: ">=", semver: new SemVer("0.0.0") }];
291
+ if (p.minor === null) {
292
+ return [
293
+ { operator: ">=", semver: new SemVer(`${p.major}.0.0`) },
294
+ { operator: "<", semver: new SemVer(`${p.major + 1}.0.0`) },
295
+ ];
296
+ }
297
+ if (p.patch === null) {
298
+ return [
299
+ { operator: ">=", semver: new SemVer(`${p.major}.${p.minor}.0`) },
300
+ { operator: "<", semver: new SemVer(`${p.major}.${p.minor + 1}.0`) },
301
+ ];
302
+ }
303
+ return [{ operator: "=", semver: new SemVer(partialToVersion(p)) }];
304
+ }
305
+
306
+ function caretRange(tok: string): Comparator[] {
307
+ const p = parsePartial(tok);
308
+ if (p.major === null) return [{ operator: ">=", semver: new SemVer("0.0.0") }];
309
+ const lower = `${p.major}.${p.minor ?? 0}.${p.patch ?? 0}${p.pre ? `-${p.pre}` : ""}`;
310
+ let upper: string;
311
+ if (p.major > 0 || p.minor === null) {
312
+ upper = `${p.major + 1}.0.0`;
313
+ } else if (p.minor > 0 || p.patch === null) {
314
+ upper = `0.${p.minor + 1}.0`;
315
+ } else {
316
+ upper = `0.0.${p.patch + 1}`;
317
+ }
318
+ return [
319
+ { operator: ">=", semver: new SemVer(lower) },
320
+ { operator: "<", semver: new SemVer(upper) },
321
+ ];
322
+ }
323
+
324
+ function tildeRange(tok: string): Comparator[] {
325
+ const p = parsePartial(tok);
326
+ if (p.major === null) return [{ operator: ">=", semver: new SemVer("0.0.0") }];
327
+ const lower = `${p.major}.${p.minor ?? 0}.${p.patch ?? 0}${p.pre ? `-${p.pre}` : ""}`;
328
+ const upper =
329
+ p.minor === null
330
+ ? `${p.major + 1}.0.0`
331
+ : `${p.major}.${p.minor + 1}.0`;
332
+ return [
333
+ { operator: ">=", semver: new SemVer(lower) },
334
+ { operator: "<", semver: new SemVer(upper) },
335
+ ];
336
+ }
337
+
338
+ function primitiveRange(op: Comparator["operator"], rhs: string): Comparator[] {
339
+ const p = parsePartial(rhs);
340
+ if (p.major === null) return [{ operator: ">=", semver: new SemVer("0.0.0") }];
341
+ if (op === "=" || op === "") return partialRange(rhs);
342
+ if (op === ">") {
343
+ if (p.minor === null) return [{ operator: ">=", semver: new SemVer(`${p.major + 1}.0.0`) }];
344
+ if (p.patch === null) return [{ operator: ">=", semver: new SemVer(`${p.major}.${p.minor + 1}.0`) }];
345
+ return [{ operator: ">", semver: new SemVer(partialToVersion(p)) }];
346
+ }
347
+ if (op === "<") {
348
+ if (p.minor === null) return [{ operator: "<", semver: new SemVer(`${p.major}.0.0`) }];
349
+ if (p.patch === null) return [{ operator: "<", semver: new SemVer(`${p.major}.${p.minor}.0`) }];
350
+ return [{ operator: "<", semver: new SemVer(partialToVersion(p)) }];
351
+ }
352
+ if (op === ">=") return [{ operator: ">=", semver: new SemVer(partialToVersion(p)) }];
353
+ if (p.minor === null) return [{ operator: "<", semver: new SemVer(`${p.major + 1}.0.0`) }];
354
+ if (p.patch === null) return [{ operator: "<", semver: new SemVer(`${p.major}.${p.minor + 1}.0`) }];
355
+ return [{ operator: "<=", semver: new SemVer(partialToVersion(p)) }];
356
+ }
357
+
358
+ function hyphenRange(left: string, right: string): Comparator[] {
359
+ const a = parsePartial(left);
360
+ const b = parsePartial(right);
361
+ const lower: Comparator =
362
+ a.major === null
363
+ ? { operator: ">=", semver: new SemVer("0.0.0") }
364
+ : {
365
+ operator: ">=",
366
+ semver: new SemVer(
367
+ `${a.major}.${a.minor ?? 0}.${a.patch ?? 0}${a.pre ? `-${a.pre}` : ""}`,
368
+ ),
369
+ };
370
+ let upper: Comparator;
371
+ if (b.major === null) {
372
+ upper = { operator: ">=", semver: new SemVer("0.0.0") };
373
+ } else if (b.minor === null) {
374
+ upper = { operator: "<", semver: new SemVer(`${b.major + 1}.0.0`) };
375
+ } else if (b.patch === null) {
376
+ upper = { operator: "<", semver: new SemVer(`${b.major}.${b.minor + 1}.0`) };
377
+ } else {
378
+ upper = {
379
+ operator: "<=",
380
+ semver: new SemVer(
381
+ `${b.major}.${b.minor}.${b.patch}${b.pre ? `-${b.pre}` : ""}`,
382
+ ),
383
+ };
384
+ }
385
+ return [lower, upper];
386
+ }
package/src/test.mts ADDED
@@ -0,0 +1,5 @@
1
+ import { run } from "@gjsify/unit";
2
+
3
+ import semverTestSuite from "./index.spec.js";
4
+
5
+ run({ semverTestSuite });
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": [
4
+ "src/test.mts",
5
+ "src/**/*.spec.ts",
6
+ "src/**/*.spec.mts"
7
+ ]
8
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "ESNext",
4
+ "target": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "experimentalDecorators": true,
7
+ "declaration": true,
8
+ "allowImportingTsExtensions": false,
9
+ "outDir": "lib/esm",
10
+ "rootDir": "src",
11
+ "declarationDir": "lib/types",
12
+ "composite": true,
13
+ "skipLibCheck": true,
14
+ "strict": true
15
+ },
16
+ "include": [
17
+ "src/**/*.ts"
18
+ ],
19
+ "exclude": [
20
+ "src/test.mts"
21
+ ]
22
+ }