Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
subset.js250 linesDownload Raw Back to ranges
1'use strict'
2
3const Range = require('../classes/range.js')
4const Comparator = require('../classes/comparator.js')
5const { ANY } = Comparator
6const satisfies = require('../functions/satisfies.js')
7const compare = require('../functions/compare.js')
8
9// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:
10// - Every simple range `r1, r2, ...` is a null set, OR
11// - Every simple range `r1, r2, ...` which is not a null set is a subset of
12//   some `R1, R2, ...`
13//
14// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:
15// - If c is only the ANY comparator
16//   - If C is only the ANY comparator, return true
17//   - Else if in prerelease mode, return false
18//   - else replace c with `[>=0.0.0]`
19// - If C is only the ANY comparator
20//   - if in prerelease mode, return true
21//   - else replace C with `[>=0.0.0]`
22// - Let EQ be the set of = comparators in c
23// - If EQ is more than one, return true (null set)
24// - Let GT be the highest > or >= comparator in c
25// - Let LT be the lowest < or <= comparator in c
26// - If GT and LT, and GT.semver > LT.semver, return true (null set)
27// - If any C is a = range, and GT or LT are set, return false
28// - If EQ
29//   - If GT, and EQ does not satisfy GT, return true (null set)
30//   - If LT, and EQ does not satisfy LT, return true (null set)
31//   - If EQ satisfies every C, return true
32//   - Else return false
33// - If GT
34//   - If GT.semver is lower than any > or >= comp in C, return false
35//   - If GT is >=, and GT.semver does not satisfy every C, return false
36//   - If GT.semver has a prerelease, and not in prerelease mode
37//     - If no C has a prerelease and the GT.semver tuple, return false
38// - If LT
39//   - If LT.semver is greater than any < or <= comp in C, return false
40//   - If LT is <=, and LT.semver does not satisfy every C, return false
41//   - If LT.semver has a prerelease, and not in prerelease mode
42//     - If no C has a prerelease and the LT.semver tuple, return false
43// - Else return true
44
45const subset = (sub, dom, options = {}) => {
46  if (sub === dom) {
47    return true
48  }
49
50  sub = new Range(sub, options)
51  dom = new Range(dom, options)
52  let sawNonNull = false
53
54  OUTER: for (const simpleSub of sub.set) {
55    for (const simpleDom of dom.set) {
56      const isSub = simpleSubset(simpleSub, simpleDom, options)
57      sawNonNull = sawNonNull || isSub !== null
58      if (isSub) {
59        continue OUTER
60      }
61    }
62    // the null set is a subset of everything, but null simple ranges in
63    // a complex range should be ignored.  so if we saw a non-null range,
64    // then we know this isn't a subset, but if EVERY simple range was null,
65    // then it is a subset.
66    if (sawNonNull) {
67      return false
68    }
69  }
70  return true
71}
72
73const minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')]
74const minimumVersion = [new Comparator('>=0.0.0')]
75
76const simpleSubset = (sub, dom, options) => {
77  if (sub === dom) {
78    return true
79  }
80
81  if (sub.length === 1 && sub[0].semver === ANY) {
82    if (dom.length === 1 && dom[0].semver === ANY) {
83      return true
84    } else if (options.includePrerelease) {
85      sub = minimumVersionWithPreRelease
86    } else {
87      sub = minimumVersion
88    }
89  }
90
91  if (dom.length === 1 && dom[0].semver === ANY) {
92    if (options.includePrerelease) {
93      return true
94    } else {
95      dom = minimumVersion
96    }
97  }
98
99  const eqSet = new Set()
100  let gt, lt
101  for (const c of sub) {
102    if (c.operator === '>' || c.operator === '>=') {
103      gt = higherGT(gt, c, options)
104    } else if (c.operator === '<' || c.operator === '<=') {
105      lt = lowerLT(lt, c, options)
106    } else {
107      eqSet.add(c.semver)
108    }
109  }
110
111  if (eqSet.size > 1) {
112    return null
113  }
114
115  let gtltComp
116  if (gt && lt) {
117    gtltComp = compare(gt.semver, lt.semver, options)
118    if (gtltComp > 0) {
119      return null
120    } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) {
121      return null
122    }
123  }
124
125  // will iterate one or zero times
126  for (const eq of eqSet) {
127    if (gt && !satisfies(eq, String(gt), options)) {
128      return null
129    }
130
131    if (lt && !satisfies(eq, String(lt), options)) {
132      return null
133    }
134
135    for (const c of dom) {
136      if (!satisfies(eq, String(c), options)) {
137        return false
138      }
139    }
140
141    return true
142  }
143
144  let higher, lower
145  let hasDomLT, hasDomGT
146  // if the subset has a prerelease, we need a comparator in the superset
147  // with the same tuple and a prerelease, or it's not a subset
148  let needDomLTPre = lt &&
149    !options.includePrerelease &&
150    lt.semver.prerelease.length ? lt.semver : false
151  let needDomGTPre = gt &&
152    !options.includePrerelease &&
153    gt.semver.prerelease.length ? gt.semver : false
154  // exception: <1.2.3-0 is the same as <1.2.3
155  if (needDomLTPre && needDomLTPre.prerelease.length === 1 &&
156      lt.operator === '<' && needDomLTPre.prerelease[0] === 0) {
157    needDomLTPre = false
158  }
159
160  for (const c of dom) {
161    hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='
162    hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='
163    if (gt) {
164      if (needDomGTPre) {
165        if (c.semver.prerelease && c.semver.prerelease.length &&
166            c.semver.major === needDomGTPre.major &&
167            c.semver.minor === needDomGTPre.minor &&
168            c.semver.patch === needDomGTPre.patch) {
169          needDomGTPre = false
170        }
171      }
172      if (c.operator === '>' || c.operator === '>=') {
173        higher = higherGT(gt, c, options)
174        if (higher === c && higher !== gt) {
175          return false
176        }
177      } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {
178        return false
179      }
180    }
181    if (lt) {
182      if (needDomLTPre) {
183        if (c.semver.prerelease && c.semver.prerelease.length &&
184            c.semver.major === needDomLTPre.major &&
185            c.semver.minor === needDomLTPre.minor &&
186            c.semver.patch === needDomLTPre.patch) {
187          needDomLTPre = false
188        }
189      }
190      if (c.operator === '<' || c.operator === '<=') {
191        lower = lowerLT(lt, c, options)
192        if (lower === c && lower !== lt) {
193          return false
194        }
195      } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {
196        return false
197      }
198    }
199    if (!c.operator && (lt || gt) && gtltComp !== 0) {
200      return false
201    }
202  }
203
204  // if there was a < or >, and nothing in the dom, then must be false
205  // UNLESS it was limited by another range in the other direction.
206  // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0
207  if (gt && hasDomLT && !lt && gtltComp !== 0) {
208    return false
209  }
210
211  if (lt && hasDomGT && !gt && gtltComp !== 0) {
212    return false
213  }
214
215  // we needed a prerelease range in a specific tuple, but didn't get one
216  // then this isn't a subset.  eg >=1.2.3-pre is not a subset of >=1.0.0,
217  // because it includes prereleases in the 1.2.3 tuple
218  if (needDomGTPre || needDomLTPre) {
219    return false
220  }
221
222  return true
223}
224
225// >=1.2.3 is lower than >1.2.3
226const higherGT = (a, b, options) => {
227  if (!a) {
228    return b
229  }
230  const comp = compare(a.semver, b.semver, options)
231  return comp > 0 ? a
232    : comp < 0 ? b
233    : b.operator === '>' && a.operator === '>=' ? b
234    : a
235}
236
237// <=1.2.3 is higher than <1.2.3
238const lowerLT = (a, b, options) => {
239  if (!a) {
240    return b
241  }
242  const comp = compare(a.semver, b.semver, options)
243  return comp < 0 ? a
244    : comp > 0 ? b
245    : b.operator === '<' && a.operator === '<=' ? b
246    : a
247}
248
249module.exports = subset
250 
codekingpro/portable-devtools · Team Ai