@vltpkg/semver 1.0.0-rc.30 → 1.0.0-rc.32

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.
package/dist/index.d.ts CHANGED
@@ -201,3 +201,8 @@ export declare const stable: <T extends Version | string = string | Version>(ver
201
201
  * Returns true if any version would satisfy both ranges.
202
202
  */
203
203
  export declare const intersects: (r1: Range | string, r2: Range | string, includePrerelease?: boolean) => boolean;
204
+ /**
205
+ * Check if range r1 is a subset of range r2.
206
+ * Returns true if every version that satisfies r1 also satisfies r2.
207
+ */
208
+ export declare const subset: (r1: Range | string, r2: Range | string, includePrerelease?: boolean) => boolean;
package/dist/index.js CHANGED
@@ -364,6 +364,149 @@ export const intersects = (r1, r2, includePrerelease) => {
364
364
  // Check if any set from range1 intersects with any set from range2
365
365
  return range1.set.some(set1 => range2.set.some(set2 => intersectComparators(set1, set2)));
366
366
  };
367
+ /**
368
+ * Check if range r1 is a subset of range r2.
369
+ * Returns true if every version that satisfies r1 also satisfies r2.
370
+ */
371
+ export const subset = (r1, r2, includePrerelease) => {
372
+ const range1 = typeof r1 === 'string' ? parseRange(r1, includePrerelease) : r1;
373
+ const range2 = typeof r2 === 'string' ? parseRange(r2, includePrerelease) : r2;
374
+ if (!range1 || !range2)
375
+ return false;
376
+ // Any range is only a subset of another 'any' range
377
+ if (range2.isAny)
378
+ return true;
379
+ if (range1.isAny)
380
+ return false;
381
+ // Every comparator set in r1 must be a subset of at least one
382
+ // comparator set in r2
383
+ return range1.set.every(set1 => range2.set.some(set2 => comparatorSubset(set1, set2)));
384
+ };
385
+ /**
386
+ * Check if comparator comp1 is a subset of comparator comp2.
387
+ * Every version satisfying comp1 must also satisfy comp2.
388
+ */
389
+ const comparatorSubset = (comp1, comp2) => {
390
+ const tuples1 = comp1.tuples.filter((t) => Array.isArray(t));
391
+ const tuples2 = comp2.tuples.filter((t) => Array.isArray(t));
392
+ // comp1 must be satisfiable
393
+ if (!satisfiableRange(tuples1))
394
+ return true;
395
+ const bounds1 = getBounds(tuples1);
396
+ const bounds2 = getBounds(tuples2);
397
+ // If comp2 has an exact match, comp1 must only match that exact version
398
+ if (bounds2.hasExact) {
399
+ if (bounds1.hasExact) {
400
+ return eq(bounds1.hasExact, bounds2.hasExact);
401
+ }
402
+ // bounds1 must collapse to exactly that version
403
+ if (!bounds1.lowerBound ||
404
+ !bounds1.upperBound ||
405
+ !eq(bounds1.lowerBound, bounds2.hasExact) ||
406
+ !eq(bounds1.upperBound, bounds2.hasExact) ||
407
+ !bounds1.lowerInclusive ||
408
+ !bounds1.upperInclusive) {
409
+ return false;
410
+ }
411
+ return true;
412
+ }
413
+ // If comp1 has an exact match, check it satisfies comp2's bounds
414
+ if (bounds1.hasExact) {
415
+ if (bounds2.lowerBound) {
416
+ if (bounds2.lowerInclusive ?
417
+ lt(bounds1.hasExact, bounds2.lowerBound)
418
+ : lte(bounds1.hasExact, bounds2.lowerBound)) {
419
+ return false;
420
+ }
421
+ }
422
+ if (bounds2.upperBound) {
423
+ if (bounds2.upperInclusive ?
424
+ gt(bounds1.hasExact, bounds2.upperBound)
425
+ : gte(bounds1.hasExact, bounds2.upperBound)) {
426
+ return false;
427
+ }
428
+ }
429
+ return true;
430
+ }
431
+ // comp1's lower bound must be >= comp2's lower bound
432
+ if (bounds2.lowerBound) {
433
+ if (!bounds1.lowerBound)
434
+ return false;
435
+ const cmp = compare(bounds1.lowerBound, bounds2.lowerBound);
436
+ if (cmp < 0)
437
+ return false;
438
+ if (cmp === 0 &&
439
+ !bounds2.lowerInclusive &&
440
+ bounds1.lowerInclusive)
441
+ return false;
442
+ }
443
+ // comp1's upper bound must be <= comp2's upper bound
444
+ if (bounds2.upperBound) {
445
+ if (!bounds1.upperBound)
446
+ return false;
447
+ const cmp = compare(bounds1.upperBound, bounds2.upperBound);
448
+ if (cmp > 0)
449
+ return false;
450
+ if (cmp === 0 &&
451
+ !bounds2.upperInclusive &&
452
+ bounds1.upperInclusive)
453
+ return false;
454
+ }
455
+ return true;
456
+ };
457
+ const getBounds = (tuples) => {
458
+ let lowerBound = null;
459
+ let lowerInclusive = false;
460
+ let upperBound = null;
461
+ let upperInclusive = false;
462
+ let hasExact = null;
463
+ for (const [op, ver] of tuples) {
464
+ switch (op) {
465
+ case '':
466
+ hasExact = ver;
467
+ break;
468
+ case '>=':
469
+ /* c8 ignore start */
470
+ if (!lowerBound ||
471
+ gt(ver, lowerBound) ||
472
+ (eq(ver, lowerBound) && !lowerInclusive)) {
473
+ lowerBound = ver;
474
+ lowerInclusive = true;
475
+ }
476
+ /* c8 ignore stop */
477
+ break;
478
+ case '>':
479
+ if (!lowerBound || gt(ver, lowerBound)) {
480
+ lowerBound = ver;
481
+ lowerInclusive = false;
482
+ }
483
+ break;
484
+ case '<=':
485
+ /* c8 ignore start */
486
+ if (!upperBound ||
487
+ lt(ver, upperBound) ||
488
+ (eq(ver, upperBound) && !upperInclusive)) {
489
+ upperBound = ver;
490
+ upperInclusive = true;
491
+ }
492
+ /* c8 ignore stop */
493
+ break;
494
+ case '<':
495
+ if (!upperBound || lt(ver, upperBound)) {
496
+ upperBound = ver;
497
+ upperInclusive = false;
498
+ }
499
+ break;
500
+ }
501
+ }
502
+ return {
503
+ lowerBound,
504
+ lowerInclusive,
505
+ upperBound,
506
+ upperInclusive,
507
+ hasExact,
508
+ };
509
+ };
367
510
  /**
368
511
  * Check if two comparators can be satisfied simultaneously
369
512
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vltpkg/semver",
3
3
  "description": "The semantic version parser used by vlt",
4
- "version": "1.0.0-rc.30",
4
+ "version": "1.0.0-rc.32",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
@@ -13,9 +13,9 @@
13
13
  "url": "http://vlt.sh"
14
14
  },
15
15
  "dependencies": {
16
- "@vltpkg/error-cause": "1.0.0-rc.30",
17
- "@vltpkg/fast-split": "1.0.0-rc.30",
18
- "@vltpkg/types": "1.0.0-rc.30"
16
+ "@vltpkg/error-cause": "1.0.0-rc.32",
17
+ "@vltpkg/fast-split": "1.0.0-rc.32",
18
+ "@vltpkg/types": "1.0.0-rc.32"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@eslint/js": "^9.39.1",