.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / semver / ranges / subset.js
1 const Range = require('../classes/range.js')
2 const Comparator = require('../classes/comparator.js')
3 const { ANY } = Comparator
4 const satisfies = require('../functions/satisfies.js')
5 const compare = require('../functions/compare.js')
6
7 // Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:
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, ...`
11 //
12 // Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:
13 // - If c is only the ANY comparator
14 //   - If C is only the ANY comparator, return true
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]`
20 // - Let EQ be the set of = comparators in c
21 // - If EQ is more than one, return true (null set)
22 // - Let GT be the highest > or >= comparator in c
23 // - Let LT be the lowest < or <= comparator in c
24 // - 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
26 // - If EQ
27 //   - If GT, and EQ does not satisfy GT, return true (null set)
28 //   - If LT, and EQ does not satisfy LT, return true (null set)
29 //   - If EQ satisfies every C, return true
30 //   - Else return false
31 // - If GT
32 //   - If GT.semver is lower than any > or >= comp in C, return false
33 //   - 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
36 // - If LT
37 //   - If LT.semver is greater than any < or <= comp in C, return false
38 //   - If LT is <=, and LT.semver does not satisfy every C, 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
41 // - Else return true
42
43 const subset = (sub, dom, options = {}) => {
44   if (sub === dom)
45     return true
46
47   sub = new Range(sub, options)
48   dom = new Range(dom, options)
49   let sawNonNull = false
50
51   OUTER: for (const simpleSub of sub.set) {
52     for (const simpleDom of dom.set) {
53       const isSub = simpleSubset(simpleSub, simpleDom, options)
54       sawNonNull = sawNonNull || isSub !== null
55       if (isSub)
56         continue OUTER
57     }
58     // the null set is a subset of everything, but null simple ranges in
59     // a complex range should be ignored.  so if we saw a non-null range,
60     // then we know this isn't a subset, but if EVERY simple range was null,
61     // then it is a subset.
62     if (sawNonNull)
63       return false
64   }
65   return true
66 }
67
68 const simpleSubset = (sub, dom, options) => {
69   if (sub === dom)
70     return true
71
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   }
80
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   }
87
88   const eqSet = new Set()
89   let gt, lt
90   for (const c of sub) {
91     if (c.operator === '>' || c.operator === '>=')
92       gt = higherGT(gt, c, options)
93     else if (c.operator === '<' || c.operator === '<=')
94       lt = lowerLT(lt, c, options)
95     else
96       eqSet.add(c.semver)
97   }
98
99   if (eqSet.size > 1)
100     return null
101
102   let gtltComp
103   if (gt && lt) {
104     gtltComp = compare(gt.semver, lt.semver, options)
105     if (gtltComp > 0)
106       return null
107     else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<='))
108       return null
109   }
110
111   // will iterate one or zero times
112   for (const eq of eqSet) {
113     if (gt && !satisfies(eq, String(gt), options))
114       return null
115
116     if (lt && !satisfies(eq, String(lt), options))
117       return null
118
119     for (const c of dom) {
120       if (!satisfies(eq, String(c), options))
121         return false
122     }
123
124     return true
125   }
126
127   let higher, lower
128   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
143   for (const c of dom) {
144     hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='
145     hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='
146     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       }
155       if (c.operator === '>' || c.operator === '>=') {
156         higher = higherGT(gt, c, options)
157         if (higher === c && higher !== gt)
158           return false
159       } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options))
160         return false
161     }
162     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       }
171       if (c.operator === '<' || c.operator === '<=') {
172         lower = lowerLT(lt, c, options)
173         if (lower === c && lower !== lt)
174           return false
175       } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options))
176         return false
177     }
178     if (!c.operator && (lt || gt) && gtltComp !== 0)
179       return false
180   }
181
182   // if there was a < or >, and nothing in the dom, then must be false
183   // UNLESS it was limited by another range in the other direction.
184   // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0
185   if (gt && hasDomLT && !lt && gtltComp !== 0)
186     return false
187
188   if (lt && hasDomGT && !gt && gtltComp !== 0)
189     return false
190
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
197   return true
198 }
199
200 // >=1.2.3 is lower than >1.2.3
201 const higherGT = (a, b, options) => {
202   if (!a)
203     return b
204   const comp = compare(a.semver, b.semver, options)
205   return comp > 0 ? a
206     : comp < 0 ? b
207     : b.operator === '>' && a.operator === '>=' ? b
208     : a
209 }
210
211 // <=1.2.3 is higher than <1.2.3
212 const lowerLT = (a, b, options) => {
213   if (!a)
214     return b
215   const comp = compare(a.semver, b.semver, options)
216   return comp < 0 ? a
217     : comp > 0 ? b
218     : b.operator === '<' && a.operator === '<=' ? b
219     : a
220 }
221
222 module.exports = subset