11const Range = require ( '../classes/range.js' )
2- const { ANY } = require ( '../classes/comparator.js' )
2+ const Comparator = require ( '../classes/comparator.js' )
3+ const { ANY } = Comparator
34const satisfies = require ( '../functions/satisfies.js' )
45const compare = require ( '../functions/compare.js' )
56
67// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:
7- // - Every simple range `r1, r2, ...` is a subset of some `R1, R2, ...`
8+ // - Every simple range `r1, r2, ...` is a null set, OR
9+ // - Every simple range `r1, r2, ...` which is not a null set is a subset of
10+ // some `R1, R2, ...`
811//
912// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:
10- // - If C is only the ANY comparator
11- // - return true
1213// - If c is only the ANY comparator
1314// - If C is only the ANY comparator, return true
14- // - Else return false
15+ // - Else if in prerelease mode, return false
16+ // - else replace c with `[>=0.0.0]`
17+ // - If C is only the ANY comparator
18+ // - if in prerelease mode, return true
19+ // - else replace C with `[>=0.0.0]`
1520// - Let EQ be the set of = comparators in c
1621// - If EQ is more than one, return true (null set)
1722// - Let GT be the highest > or >= comparator in c
1823// - Let LT be the lowest < or <= comparator in c
1924// - If GT and LT, and GT.semver > LT.semver, return true (null set)
25+ // - If any C is a = range, and GT or LT are set, return false
2026// - If EQ
2127// - If GT, and EQ does not satisfy GT, return true (null set)
2228// - If LT, and EQ does not satisfy LT, return true (null set)
@@ -25,13 +31,16 @@ const compare = require('../functions/compare.js')
2531// - If GT
2632// - If GT.semver is lower than any > or >= comp in C, return false
2733// - If GT is >=, and GT.semver does not satisfy every C, return false
34+ // - If GT.semver has a prerelease, and not in prerelease mode
35+ // - If no C has a prerelease and the GT.semver tuple, return false
2836// - If LT
2937// - If LT.semver is greater than any < or <= comp in C, return false
3038// - If LT is <=, and LT.semver does not satisfy every C, return false
31- // - If any C is a = range, and GT or LT are set, return false
39+ // - If GT.semver has a prerelease, and not in prerelease mode
40+ // - If no C has a prerelease and the LT.semver tuple, return false
3241// - Else return true
3342
34- const subset = ( sub , dom , options ) => {
43+ const subset = ( sub , dom , options = { } ) => {
3544 if ( sub === dom )
3645 return true
3746
@@ -60,11 +69,21 @@ const simpleSubset = (sub, dom, options) => {
6069 if ( sub === dom )
6170 return true
6271
63- if ( dom . length === 1 && dom [ 0 ] . semver === ANY )
64- return true
72+ if ( sub . length === 1 && sub [ 0 ] . semver === ANY ) {
73+ if ( dom . length === 1 && dom [ 0 ] . semver === ANY )
74+ return true
75+ else if ( options . includePrerelease )
76+ sub = [ new Comparator ( '>=0.0.0-0' ) ]
77+ else
78+ sub = [ new Comparator ( '>=0.0.0' ) ]
79+ }
6580
66- if ( sub . length === 1 && sub [ 0 ] . semver === ANY )
67- return dom . length === 1 && dom [ 0 ] . semver === ANY
81+ if ( dom . length === 1 && dom [ 0 ] . semver === ANY ) {
82+ if ( options . includePrerelease )
83+ return true
84+ else
85+ dom = [ new Comparator ( '>=0.0.0' ) ]
86+ }
6887
6988 const eqSet = new Set ( )
7089 let gt , lt
@@ -107,10 +126,32 @@ const simpleSubset = (sub, dom, options) => {
107126
108127 let higher , lower
109128 let hasDomLT , hasDomGT
129+ // if the subset has a prerelease, we need a comparator in the superset
130+ // with the same tuple and a prerelease, or it's not a subset
131+ let needDomLTPre = lt &&
132+ ! options . includePrerelease &&
133+ lt . semver . prerelease . length ? lt . semver : false
134+ let needDomGTPre = gt &&
135+ ! options . includePrerelease &&
136+ gt . semver . prerelease . length ? gt . semver : false
137+ // exception: <1.2.3-0 is the same as <1.2.3
138+ if ( needDomLTPre && needDomLTPre . prerelease . length === 1 &&
139+ lt . operator === '<' && needDomLTPre . prerelease [ 0 ] === 0 ) {
140+ needDomLTPre = false
141+ }
142+
110143 for ( const c of dom ) {
111144 hasDomGT = hasDomGT || c . operator === '>' || c . operator === '>='
112145 hasDomLT = hasDomLT || c . operator === '<' || c . operator === '<='
113146 if ( gt ) {
147+ if ( needDomGTPre ) {
148+ if ( c . semver . prerelease && c . semver . prerelease . length &&
149+ c . semver . major === needDomGTPre . major &&
150+ c . semver . minor === needDomGTPre . minor &&
151+ c . semver . patch === needDomGTPre . patch ) {
152+ needDomGTPre = false
153+ }
154+ }
114155 if ( c . operator === '>' || c . operator === '>=' ) {
115156 higher = higherGT ( gt , c , options )
116157 if ( higher === c && higher !== gt )
@@ -119,6 +160,14 @@ const simpleSubset = (sub, dom, options) => {
119160 return false
120161 }
121162 if ( lt ) {
163+ if ( needDomLTPre ) {
164+ if ( c . semver . prerelease && c . semver . prerelease . length &&
165+ c . semver . major === needDomLTPre . major &&
166+ c . semver . minor === needDomLTPre . minor &&
167+ c . semver . patch === needDomLTPre . patch ) {
168+ needDomLTPre = false
169+ }
170+ }
122171 if ( c . operator === '<' || c . operator === '<=' ) {
123172 lower = lowerLT ( lt , c , options )
124173 if ( lower === c && lower !== lt )
@@ -139,6 +188,12 @@ const simpleSubset = (sub, dom, options) => {
139188 if ( lt && hasDomGT && ! gt && gtltComp !== 0 )
140189 return false
141190
191+ // we needed a prerelease range in a specific tuple, but didn't get one
192+ // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0,
193+ // because it includes prereleases in the 1.2.3 tuple
194+ if ( needDomGTPre || needDomLTPre )
195+ return false
196+
142197 return true
143198}
144199
0 commit comments