semver 6.3.0 → 7.0.0

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +58 -2
  3. package/bin/semver.js +78 -79
  4. package/classes/comparator.js +139 -0
  5. package/classes/index.js +5 -0
  6. package/classes/range.js +448 -0
  7. package/classes/semver.js +290 -0
  8. package/functions/clean.js +6 -0
  9. package/functions/cmp.js +48 -0
  10. package/functions/coerce.js +51 -0
  11. package/functions/compare-build.js +7 -0
  12. package/functions/compare-loose.js +3 -0
  13. package/functions/compare.js +5 -0
  14. package/functions/diff.js +25 -0
  15. package/functions/eq.js +3 -0
  16. package/functions/gt.js +3 -0
  17. package/functions/gte.js +3 -0
  18. package/functions/inc.js +15 -0
  19. package/functions/lt.js +3 -0
  20. package/functions/lte.js +3 -0
  21. package/functions/major.js +3 -0
  22. package/functions/minor.js +3 -0
  23. package/functions/neq.js +3 -0
  24. package/functions/parse.js +37 -0
  25. package/functions/patch.js +3 -0
  26. package/functions/prerelease.js +6 -0
  27. package/functions/rcompare.js +3 -0
  28. package/functions/rsort.js +3 -0
  29. package/functions/satisfies.js +10 -0
  30. package/functions/sort.js +3 -0
  31. package/functions/valid.js +6 -0
  32. package/index.js +64 -0
  33. package/internal/constants.js +17 -0
  34. package/internal/debug.js +9 -0
  35. package/internal/identifiers.js +23 -0
  36. package/internal/re.js +179 -0
  37. package/package.json +11 -5
  38. package/ranges/gtr.js +4 -0
  39. package/ranges/intersects.js +7 -0
  40. package/ranges/ltr.js +4 -0
  41. package/ranges/max-satisfying.js +25 -0
  42. package/ranges/min-satisfying.js +24 -0
  43. package/ranges/min-version.js +57 -0
  44. package/ranges/outside.js +80 -0
  45. package/ranges/to-comparators.js +8 -0
  46. package/ranges/valid.js +11 -0
  47. package/semver.js +0 -1596
@@ -0,0 +1,448 @@
1
+ // hoisted class for cyclic dependency
2
+ class Range {
3
+ constructor (range, options) {
4
+ if (!options || typeof options !== 'object') {
5
+ options = {
6
+ loose: !!options,
7
+ includePrerelease: false
8
+ }
9
+ }
10
+
11
+ if (range instanceof Range) {
12
+ if (
13
+ range.loose === !!options.loose &&
14
+ range.includePrerelease === !!options.includePrerelease
15
+ ) {
16
+ return range
17
+ } else {
18
+ return new Range(range.raw, options)
19
+ }
20
+ }
21
+
22
+ if (range instanceof Comparator) {
23
+ // just put it in the set and return
24
+ this.raw = range.value
25
+ this.set = [[range]]
26
+ this.format()
27
+ return this
28
+ }
29
+
30
+ this.options = options
31
+ this.loose = !!options.loose
32
+ this.includePrerelease = !!options.includePrerelease
33
+
34
+ // First, split based on boolean or ||
35
+ this.raw = range
36
+ this.set = range
37
+ .split(/\s*\|\|\s*/)
38
+ // map the range to a 2d array of comparators
39
+ .map(range => this.parseRange(range.trim()))
40
+ // throw out any comparator lists that are empty
41
+ // this generally means that it was not a valid range, which is allowed
42
+ // in loose mode, but will still throw if the WHOLE range is invalid.
43
+ .filter(c => c.length)
44
+
45
+ if (!this.set.length) {
46
+ throw new TypeError(`Invalid SemVer Range: ${range}`)
47
+ }
48
+
49
+ this.format()
50
+ }
51
+
52
+ format () {
53
+ this.range = this.set
54
+ .map((comps) => {
55
+ return comps.join(' ').trim()
56
+ })
57
+ .join('||')
58
+ .trim()
59
+ return this.range
60
+ }
61
+
62
+ toString () {
63
+ return this.range
64
+ }
65
+
66
+ parseRange (range) {
67
+ const loose = this.options.loose
68
+ range = range.trim()
69
+ // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
70
+ const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]
71
+ range = range.replace(hr, hyphenReplace)
72
+ debug('hyphen replace', range)
73
+ // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
74
+ range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
75
+ debug('comparator trim', range, re[t.COMPARATORTRIM])
76
+
77
+ // `~ 1.2.3` => `~1.2.3`
78
+ range = range.replace(re[t.TILDETRIM], tildeTrimReplace)
79
+
80
+ // `^ 1.2.3` => `^1.2.3`
81
+ range = range.replace(re[t.CARETTRIM], caretTrimReplace)
82
+
83
+ // normalize spaces
84
+ range = range.split(/\s+/).join(' ')
85
+
86
+ // At this point, the range is completely trimmed and
87
+ // ready to be split into comparators.
88
+
89
+ const compRe = loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
90
+ return range
91
+ .split(' ')
92
+ .map(comp => parseComparator(comp, this.options))
93
+ .join(' ')
94
+ .split(/\s+/)
95
+ // in loose mode, throw out any that are not valid comparators
96
+ .filter(this.options.loose ? comp => !!comp.match(compRe) : () => true)
97
+ .map(comp => new Comparator(comp, this.options))
98
+ }
99
+
100
+ intersects (range, options) {
101
+ if (!(range instanceof Range)) {
102
+ throw new TypeError('a Range is required')
103
+ }
104
+
105
+ return this.set.some((thisComparators) => {
106
+ return (
107
+ isSatisfiable(thisComparators, options) &&
108
+ range.set.some((rangeComparators) => {
109
+ return (
110
+ isSatisfiable(rangeComparators, options) &&
111
+ thisComparators.every((thisComparator) => {
112
+ return rangeComparators.every((rangeComparator) => {
113
+ return thisComparator.intersects(rangeComparator, options)
114
+ })
115
+ })
116
+ )
117
+ })
118
+ )
119
+ })
120
+ }
121
+
122
+ // if ANY of the sets match ALL of its comparators, then pass
123
+ test (version) {
124
+ if (!version) {
125
+ return false
126
+ }
127
+
128
+ if (typeof version === 'string') {
129
+ try {
130
+ version = new SemVer(version, this.options)
131
+ } catch (er) {
132
+ return false
133
+ }
134
+ }
135
+
136
+ for (let i = 0; i < this.set.length; i++) {
137
+ if (testSet(this.set[i], version, this.options)) {
138
+ return true
139
+ }
140
+ }
141
+ return false
142
+ }
143
+ }
144
+ module.exports = Range
145
+
146
+ const Comparator = require('./comparator')
147
+ const debug = require('../internal/debug')
148
+ const SemVer = require('./semver')
149
+ const {
150
+ re,
151
+ t,
152
+ comparatorTrimReplace,
153
+ tildeTrimReplace,
154
+ caretTrimReplace
155
+ } = require('../internal/re')
156
+
157
+ // take a set of comparators and determine whether there
158
+ // exists a version which can satisfy it
159
+ const isSatisfiable = (comparators, options) => {
160
+ let result = true
161
+ const remainingComparators = comparators.slice()
162
+ let testComparator = remainingComparators.pop()
163
+
164
+ while (result && remainingComparators.length) {
165
+ result = remainingComparators.every((otherComparator) => {
166
+ return testComparator.intersects(otherComparator, options)
167
+ })
168
+
169
+ testComparator = remainingComparators.pop()
170
+ }
171
+
172
+ return result
173
+ }
174
+
175
+ // comprised of xranges, tildes, stars, and gtlt's at this point.
176
+ // already replaced the hyphen ranges
177
+ // turn into a set of JUST comparators.
178
+ const parseComparator = (comp, options) => {
179
+ debug('comp', comp, options)
180
+ comp = replaceCarets(comp, options)
181
+ debug('caret', comp)
182
+ comp = replaceTildes(comp, options)
183
+ debug('tildes', comp)
184
+ comp = replaceXRanges(comp, options)
185
+ debug('xrange', comp)
186
+ comp = replaceStars(comp, options)
187
+ debug('stars', comp)
188
+ return comp
189
+ }
190
+
191
+ const isX = id => !id || id.toLowerCase() === 'x' || id === '*'
192
+
193
+ // ~, ~> --> * (any, kinda silly)
194
+ // ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
195
+ // ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
196
+ // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
197
+ // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
198
+ // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
199
+ const replaceTildes = (comp, options) =>
200
+ comp.trim().split(/\s+/).map((comp) => {
201
+ return replaceTilde(comp, options)
202
+ }).join(' ')
203
+
204
+ const replaceTilde = (comp, options) => {
205
+ const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]
206
+ return comp.replace(r, (_, M, m, p, pr) => {
207
+ debug('tilde', comp, _, M, m, p, pr)
208
+ let ret
209
+
210
+ if (isX(M)) {
211
+ ret = ''
212
+ } else if (isX(m)) {
213
+ ret = `>=${M}.0.0 <${+M + 1}.0.0`
214
+ } else if (isX(p)) {
215
+ // ~1.2 == >=1.2.0 <1.3.0
216
+ ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0`
217
+ } else if (pr) {
218
+ debug('replaceTilde pr', pr)
219
+ ret = `>=${M}.${m}.${p}-${pr
220
+ } <${M}.${+m + 1}.0`
221
+ } else {
222
+ // ~1.2.3 == >=1.2.3 <1.3.0
223
+ ret = `>=${M}.${m}.${p
224
+ } <${M}.${+m + 1}.0`
225
+ }
226
+
227
+ debug('tilde return', ret)
228
+ return ret
229
+ })
230
+ }
231
+
232
+ // ^ --> * (any, kinda silly)
233
+ // ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
234
+ // ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
235
+ // ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
236
+ // ^1.2.3 --> >=1.2.3 <2.0.0
237
+ // ^1.2.0 --> >=1.2.0 <2.0.0
238
+ const replaceCarets = (comp, options) =>
239
+ comp.trim().split(/\s+/).map((comp) => {
240
+ return replaceCaret(comp, options)
241
+ }).join(' ')
242
+
243
+ const replaceCaret = (comp, options) => {
244
+ debug('caret', comp, options)
245
+ const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]
246
+ return comp.replace(r, (_, M, m, p, pr) => {
247
+ debug('caret', comp, _, M, m, p, pr)
248
+ let ret
249
+
250
+ if (isX(M)) {
251
+ ret = ''
252
+ } else if (isX(m)) {
253
+ ret = `>=${M}.0.0 <${+M + 1}.0.0`
254
+ } else if (isX(p)) {
255
+ if (M === '0') {
256
+ ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0`
257
+ } else {
258
+ ret = `>=${M}.${m}.0 <${+M + 1}.0.0`
259
+ }
260
+ } else if (pr) {
261
+ debug('replaceCaret pr', pr)
262
+ if (M === '0') {
263
+ if (m === '0') {
264
+ ret = `>=${M}.${m}.${p}-${pr
265
+ } <${M}.${m}.${+p + 1}`
266
+ } else {
267
+ ret = `>=${M}.${m}.${p}-${pr
268
+ } <${M}.${+m + 1}.0`
269
+ }
270
+ } else {
271
+ ret = `>=${M}.${m}.${p}-${pr
272
+ } <${+M + 1}.0.0`
273
+ }
274
+ } else {
275
+ debug('no pr')
276
+ if (M === '0') {
277
+ if (m === '0') {
278
+ ret = `>=${M}.${m}.${p
279
+ } <${M}.${m}.${+p + 1}`
280
+ } else {
281
+ ret = `>=${M}.${m}.${p
282
+ } <${M}.${+m + 1}.0`
283
+ }
284
+ } else {
285
+ ret = `>=${M}.${m}.${p
286
+ } <${+M + 1}.0.0`
287
+ }
288
+ }
289
+
290
+ debug('caret return', ret)
291
+ return ret
292
+ })
293
+ }
294
+
295
+ const replaceXRanges = (comp, options) => {
296
+ debug('replaceXRanges', comp, options)
297
+ return comp.split(/\s+/).map((comp) => {
298
+ return replaceXRange(comp, options)
299
+ }).join(' ')
300
+ }
301
+
302
+ const replaceXRange = (comp, options) => {
303
+ comp = comp.trim()
304
+ const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]
305
+ return comp.replace(r, (ret, gtlt, M, m, p, pr) => {
306
+ debug('xRange', comp, ret, gtlt, M, m, p, pr)
307
+ const xM = isX(M)
308
+ const xm = xM || isX(m)
309
+ const xp = xm || isX(p)
310
+ const anyX = xp
311
+
312
+ if (gtlt === '=' && anyX) {
313
+ gtlt = ''
314
+ }
315
+
316
+ // if we're including prereleases in the match, then we need
317
+ // to fix this to -0, the lowest possible prerelease value
318
+ pr = options.includePrerelease ? '-0' : ''
319
+
320
+ if (xM) {
321
+ if (gtlt === '>' || gtlt === '<') {
322
+ // nothing is allowed
323
+ ret = '<0.0.0-0'
324
+ } else {
325
+ // nothing is forbidden
326
+ ret = '*'
327
+ }
328
+ } else if (gtlt && anyX) {
329
+ // we know patch is an x, because we have any x at all.
330
+ // replace X with 0
331
+ if (xm) {
332
+ m = 0
333
+ }
334
+ p = 0
335
+
336
+ if (gtlt === '>') {
337
+ // >1 => >=2.0.0
338
+ // >1.2 => >=1.3.0
339
+ gtlt = '>='
340
+ if (xm) {
341
+ M = +M + 1
342
+ m = 0
343
+ p = 0
344
+ } else {
345
+ m = +m + 1
346
+ p = 0
347
+ }
348
+ } else if (gtlt === '<=') {
349
+ // <=0.7.x is actually <0.8.0, since any 0.7.x should
350
+ // pass. Similarly, <=7.x is actually <8.0.0, etc.
351
+ gtlt = '<'
352
+ if (xm) {
353
+ M = +M + 1
354
+ } else {
355
+ m = +m + 1
356
+ }
357
+ }
358
+
359
+ ret = `${gtlt + M}.${m}.${p}${pr}`
360
+ } else if (xm) {
361
+ ret = `>=${M}.0.0${pr} <${+M + 1}.0.0${pr}`
362
+ } else if (xp) {
363
+ ret = `>=${M}.${m}.0${pr
364
+ } <${M}.${+m + 1}.0${pr}`
365
+ }
366
+
367
+ debug('xRange return', ret)
368
+
369
+ return ret
370
+ })
371
+ }
372
+
373
+ // Because * is AND-ed with everything else in the comparator,
374
+ // and '' means "any version", just remove the *s entirely.
375
+ const replaceStars = (comp, options) => {
376
+ debug('replaceStars', comp, options)
377
+ // Looseness is ignored here. star is always as loose as it gets!
378
+ return comp.trim().replace(re[t.STAR], '')
379
+ }
380
+
381
+ // This function is passed to string.replace(re[t.HYPHENRANGE])
382
+ // M, m, patch, prerelease, build
383
+ // 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
384
+ // 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
385
+ // 1.2 - 3.4 => >=1.2.0 <3.5.0
386
+ const hyphenReplace = ($0,
387
+ from, fM, fm, fp, fpr, fb,
388
+ to, tM, tm, tp, tpr, tb) => {
389
+ if (isX(fM)) {
390
+ from = ''
391
+ } else if (isX(fm)) {
392
+ from = `>=${fM}.0.0`
393
+ } else if (isX(fp)) {
394
+ from = `>=${fM}.${fm}.0`
395
+ } else {
396
+ from = `>=${from}`
397
+ }
398
+
399
+ if (isX(tM)) {
400
+ to = ''
401
+ } else if (isX(tm)) {
402
+ to = `<${+tM + 1}.0.0`
403
+ } else if (isX(tp)) {
404
+ to = `<${tM}.${+tm + 1}.0`
405
+ } else if (tpr) {
406
+ to = `<=${tM}.${tm}.${tp}-${tpr}`
407
+ } else {
408
+ to = `<=${to}`
409
+ }
410
+
411
+ return (`${from} ${to}`).trim()
412
+ }
413
+
414
+ const testSet = (set, version, options) => {
415
+ for (let i = 0; i < set.length; i++) {
416
+ if (!set[i].test(version)) {
417
+ return false
418
+ }
419
+ }
420
+
421
+ if (version.prerelease.length && !options.includePrerelease) {
422
+ // Find the set of versions that are allowed to have prereleases
423
+ // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
424
+ // That should allow `1.2.3-pr.2` to pass.
425
+ // However, `1.2.4-alpha.notready` should NOT be allowed,
426
+ // even though it's within the range set by the comparators.
427
+ for (let i = 0; i < set.length; i++) {
428
+ debug(set[i].semver)
429
+ if (set[i].semver === Comparator.ANY) {
430
+ continue
431
+ }
432
+
433
+ if (set[i].semver.prerelease.length > 0) {
434
+ const allowed = set[i].semver
435
+ if (allowed.major === version.major &&
436
+ allowed.minor === version.minor &&
437
+ allowed.patch === version.patch) {
438
+ return true
439
+ }
440
+ }
441
+ }
442
+
443
+ // Version has a -pre, but it's not one of the ones we like.
444
+ return false
445
+ }
446
+
447
+ return true
448
+ }