Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 32 additions & 21 deletions ranges/subset.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const compare = require('../functions/compare.js')
// - If EQ is more than one, return true (null set)
// - Let GT be the highest > or >= comparator in c
// - Let LT be the lowest < or <= comparator in c
// - If LT is set without GT or EQ, use the lowest admitted version for GT
// - When not in prerelease mode, replace an exclusive stable LT `<X`
// with `<X-0` to exclude prereleases of X's tuple
// - If GT and LT, and GT.semver > LT.semver, return true (null set)
// - If any C is a = range, and GT or LT are set, return false
// - If EQ
Expand All @@ -49,9 +52,9 @@ const subset = (sub, dom, options = {}) => {

sub = new Range(sub, options)
dom = new Range(dom, options)
let sawNonNull = false

OUTER: for (const simpleSub of sub.set) {
let sawNonNull = false
for (const simpleDom of dom.set) {
const isSub = simpleSubset(simpleSub, simpleDom, options)
sawNonNull = sawNonNull || isSub !== null
Expand Down Expand Up @@ -112,6 +115,19 @@ const simpleSubset = (sub, dom, options) => {
return null
}

if (lt && !gt && eqSet.size === 0) {
// An omitted lower bound still starts at the lowest admitted version.
const includesZeroPrerelease = options.includePrerelease ||
(lt.semver.prerelease.length && lt.semver.major === 0 &&
lt.semver.minor === 0 && lt.semver.patch === 0)
gt = (includesZeroPrerelease ? minimumVersionWithPreRelease : minimumVersion)[0]

// No prereleases of this tuple are admitted by an exclusive stable bound.
if (!options.includePrerelease && lt.operator === '<' && !lt.semver.prerelease.length) {
lt = new Comparator(`${lt.value}-0`, options)
}
}

let gtltComp
if (gt && lt) {
gtltComp = compare(gt.semver, lt.semver, options)
Expand Down Expand Up @@ -142,7 +158,7 @@ const simpleSubset = (sub, dom, options) => {
}

let higher, lower
let hasDomLT, hasDomGT
let hasDomLT
// if the subset has a prerelease, we need a comparator in the superset
// with the same tuple and a prerelease, or it's not a subset
let needDomLTPre = lt &&
Expand All @@ -157,26 +173,25 @@ const simpleSubset = (sub, dom, options) => {
needDomLTPre = false
}

// EQ cases returned above; ANY and LT-only ranges now have a lower bound,
// so gt is always set here.
for (const c of dom) {
hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='
hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='
if (gt) {
if (needDomGTPre) {
if (c.semver.prerelease && c.semver.prerelease.length &&
c.semver.major === needDomGTPre.major &&
c.semver.minor === needDomGTPre.minor &&
c.semver.patch === needDomGTPre.patch) {
needDomGTPre = false
}
if (needDomGTPre) {
if (c.semver.prerelease && c.semver.prerelease.length &&
c.semver.major === needDomGTPre.major &&
c.semver.minor === needDomGTPre.minor &&
c.semver.patch === needDomGTPre.patch) {
needDomGTPre = false
}
if (c.operator === '>' || c.operator === '>=') {
higher = higherGT(gt, c, options)
if (higher === c && higher !== gt) {
return false
}
} else if (gt.operator === '>=' && !c.test(gt.semver)) {
}
if (c.operator === '>' || c.operator === '>=') {
higher = higherGT(gt, c, options)
if (higher === c && higher !== gt) {
return false
}
} else if (gt.operator === '>=' && !c.test(gt.semver)) {
return false
}
if (lt) {
if (needDomLTPre) {
Expand Down Expand Up @@ -208,10 +223,6 @@ const simpleSubset = (sub, dom, options) => {
return false
}

if (lt && hasDomGT && !gt && gtltComp !== 0) {
return false
}

// we needed a prerelease range in a specific tuple, but didn't get one
// then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0,
// because it includes prereleases in the 1.2.3 tuple
Expand Down
46 changes: 46 additions & 0 deletions test/ranges/subset.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,51 @@ const cases = [
['^1.2.3-pre.0', '*', true, { includePrerelease: true }],
['1 || 2 || 3', '*', true],

// upper-bound-only ranges start at the lowest admitted version
['<2.0.0', '*', true],
['<2', '*', true],
['<2.0.0', '>=0.0.0', true],
['<2.0.0', '>=0.0.0-0', true],
['<1.0.0', '0.x', true],
['<01.0.0', '0.x', true, { loose: true }],
['<=2.0.0', '*', true],
['<2.0.0', '>0.0.0', false],
['<2.0.0', '>=0.0.1', false],
['<2.0.0', '>=1.0.0', false],
['<2.0.0', '*', true, { includePrerelease: true }],
['<2.0.0', '>=0.0.0', false, { includePrerelease: true }],
['<2.0.0', '>0.0.0-0', false, { includePrerelease: true }],
['<2.0.0', '>=0.0.0-0', true, { includePrerelease: true }],
['<1.0.0', '0.x', false, { includePrerelease: true }],
['<=1.0.0', '0.x', false],
['<1.0.0', '<1.0.0-0', true],
['<1.0.1', '0.x', false],
['<1.0.0-0', '0.x', true],
['<1.0.0-beta', '<1.0.0-beta.2', true],
['>=1.0.0-alpha <1.0.0', '0.x', false],
['<0.0.0-beta', '*', false],
['<0.0.0-beta', '>=0.0.0-0', true],
['<0.0.0-beta', '>0.0.0-0', false],
['<0.0.1-beta', '>=0.0.0-0', false],
['<0.1.0-beta', '>=0.0.0-0', false],
['<0.0.0-0', '1.0.0', true],
['<0.0.0', '1.0.0', true],
['<=0.0.0', '0.0.0', true],

// empty upper-bound-only branches do not change a union
['<1.0.0 || <0.0.0', '<2.0.0', true],
['<0.0.0 || <1.0.0', '<2.0.0', true],
['<1.0.0 || <0.0.0', '<0.5.0 || <2.0.0', true],
['<0.0.0 || <1.0.0', '<0.5.0 || <2.0.0', true],
['<0.0.0 || <1.0.0 || <0.0.0', '<2.0.0', true],
['<1.0.0 || <0.0.0', '<0.5.0', false],
['<0.0.0 || <1.0.0', '<0.5.0', false],
['<0.0.0 || <0.0.0', '1.0.0', true],
['<=0.0.0 || <0.0.0', '0.0.0', true],
['<0.0.0 || <=0.0.0', '0.0.0', true],
['<01.0.0 || <00.0.0', '<2.0.0', true, { loose: true }],
['<1.0.0 || <0.0.0', '>=0.0.0 <2.0.0', false, { includePrerelease: true }],

// prerelease edge cases
['^1.2.3-pre.0', '>=1.0.0', false],
['^1.2.3-pre.0', '>=1.0.0', true, { includePrerelease: true }],
Expand Down Expand Up @@ -82,6 +127,7 @@ const cases = [
['>=1.0.0 <2.0.0', '<2.0.0', true],
['>=1.0.0 <2.0.0', '>0.0.0', true],
['>=1.0.0 <=1.0.0', '1.0.0', true],
['>=1.0.0 <=2.0.0', '1.0.0', false],
['>=1.0.0 <=1.0.0', '2.0.0', false],
['<2.0.0', '>=1.0.0 <2.0.0', false],
['>=1.0.0', '>=1.0.0 <2.0.0', false],
Expand Down