• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1exports = module.exports = SemVer
2
3var debug
4/* istanbul ignore next */
5if (typeof process === 'object' &&
6    process.env &&
7    process.env.NODE_DEBUG &&
8    /\bsemver\b/i.test(process.env.NODE_DEBUG)) {
9  debug = function () {
10    var args = Array.prototype.slice.call(arguments, 0)
11    args.unshift('SEMVER')
12    console.log.apply(console, args)
13  }
14} else {
15  debug = function () {}
16}
17
18// Note: this is the semver.org version of the spec that it implements
19// Not necessarily the package version of this code.
20exports.SEMVER_SPEC_VERSION = '2.0.0'
21
22var MAX_LENGTH = 256
23var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
24  /* istanbul ignore next */ 9007199254740991
25
26// Max safe segment length for coercion.
27var MAX_SAFE_COMPONENT_LENGTH = 16
28
29// The actual regexps go on exports.re
30var re = exports.re = []
31var src = exports.src = []
32var R = 0
33
34// The following Regular Expressions can be used for tokenizing,
35// validating, and parsing SemVer version strings.
36
37// ## Numeric Identifier
38// A single `0`, or a non-zero digit followed by zero or more digits.
39
40var NUMERICIDENTIFIER = R++
41src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'
42var NUMERICIDENTIFIERLOOSE = R++
43src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'
44
45// ## Non-numeric Identifier
46// Zero or more digits, followed by a letter or hyphen, and then zero or
47// more letters, digits, or hyphens.
48
49var NONNUMERICIDENTIFIER = R++
50src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'
51
52// ## Main Version
53// Three dot-separated numeric identifiers.
54
55var MAINVERSION = R++
56src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' +
57                   '(' + src[NUMERICIDENTIFIER] + ')\\.' +
58                   '(' + src[NUMERICIDENTIFIER] + ')'
59
60var MAINVERSIONLOOSE = R++
61src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
62                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
63                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')'
64
65// ## Pre-release Version Identifier
66// A numeric identifier, or a non-numeric identifier.
67
68var PRERELEASEIDENTIFIER = R++
69src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] +
70                            '|' + src[NONNUMERICIDENTIFIER] + ')'
71
72var PRERELEASEIDENTIFIERLOOSE = R++
73src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] +
74                                 '|' + src[NONNUMERICIDENTIFIER] + ')'
75
76// ## Pre-release Version
77// Hyphen, followed by one or more dot-separated pre-release version
78// identifiers.
79
80var PRERELEASE = R++
81src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] +
82                  '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'
83
84var PRERELEASELOOSE = R++
85src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] +
86                       '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'
87
88// ## Build Metadata Identifier
89// Any combination of digits, letters, or hyphens.
90
91var BUILDIDENTIFIER = R++
92src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'
93
94// ## Build Metadata
95// Plus sign, followed by one or more period-separated build metadata
96// identifiers.
97
98var BUILD = R++
99src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] +
100             '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'
101
102// ## Full Version String
103// A main version, followed optionally by a pre-release version and
104// build metadata.
105
106// Note that the only major, minor, patch, and pre-release sections of
107// the version string are capturing groups.  The build metadata is not a
108// capturing group, because it should not ever be used in version
109// comparison.
110
111var FULL = R++
112var FULLPLAIN = 'v?' + src[MAINVERSION] +
113                src[PRERELEASE] + '?' +
114                src[BUILD] + '?'
115
116src[FULL] = '^' + FULLPLAIN + '$'
117
118// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
119// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
120// common in the npm registry.
121var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] +
122                 src[PRERELEASELOOSE] + '?' +
123                 src[BUILD] + '?'
124
125var LOOSE = R++
126src[LOOSE] = '^' + LOOSEPLAIN + '$'
127
128var GTLT = R++
129src[GTLT] = '((?:<|>)?=?)'
130
131// Something like "2.*" or "1.2.x".
132// Note that "x.x" is a valid xRange identifer, meaning "any version"
133// Only the first item is strictly required.
134var XRANGEIDENTIFIERLOOSE = R++
135src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'
136var XRANGEIDENTIFIER = R++
137src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'
138
139var XRANGEPLAIN = R++
140src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' +
141                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
142                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
143                   '(?:' + src[PRERELEASE] + ')?' +
144                   src[BUILD] + '?' +
145                   ')?)?'
146
147var XRANGEPLAINLOOSE = R++
148src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
149                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
150                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
151                        '(?:' + src[PRERELEASELOOSE] + ')?' +
152                        src[BUILD] + '?' +
153                        ')?)?'
154
155var XRANGE = R++
156src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'
157var XRANGELOOSE = R++
158src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'
159
160// Coercion.
161// Extract anything that could conceivably be a part of a valid semver
162var COERCE = R++
163src[COERCE] = '(?:^|[^\\d])' +
164              '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' +
165              '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' +
166              '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' +
167              '(?:$|[^\\d])'
168
169// Tilde ranges.
170// Meaning is "reasonably at or greater than"
171var LONETILDE = R++
172src[LONETILDE] = '(?:~>?)'
173
174var TILDETRIM = R++
175src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'
176re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g')
177var tildeTrimReplace = '$1~'
178
179var TILDE = R++
180src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'
181var TILDELOOSE = R++
182src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'
183
184// Caret ranges.
185// Meaning is "at least and backwards compatible with"
186var LONECARET = R++
187src[LONECARET] = '(?:\\^)'
188
189var CARETTRIM = R++
190src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'
191re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g')
192var caretTrimReplace = '$1^'
193
194var CARET = R++
195src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'
196var CARETLOOSE = R++
197src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'
198
199// A simple gt/lt/eq thing, or just "" to indicate "any version"
200var COMPARATORLOOSE = R++
201src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'
202var COMPARATOR = R++
203src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'
204
205// An expression to strip any whitespace between the gtlt and the thing
206// it modifies, so that `> 1.2.3` ==> `>1.2.3`
207var COMPARATORTRIM = R++
208src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] +
209                      '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'
210
211// this one has to use the /g flag
212re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g')
213var comparatorTrimReplace = '$1$2$3'
214
215// Something like `1.2.3 - 1.2.4`
216// Note that these all use the loose form, because they'll be
217// checked against either the strict or loose comparator form
218// later.
219var HYPHENRANGE = R++
220src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' +
221                   '\\s+-\\s+' +
222                   '(' + src[XRANGEPLAIN] + ')' +
223                   '\\s*$'
224
225var HYPHENRANGELOOSE = R++
226src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' +
227                        '\\s+-\\s+' +
228                        '(' + src[XRANGEPLAINLOOSE] + ')' +
229                        '\\s*$'
230
231// Star ranges basically just allow anything at all.
232var STAR = R++
233src[STAR] = '(<|>)?=?\\s*\\*'
234
235// Compile to actual regexp objects.
236// All are flag-free, unless they were created above with a flag.
237for (var i = 0; i < R; i++) {
238  debug(i, src[i])
239  if (!re[i]) {
240    re[i] = new RegExp(src[i])
241  }
242}
243
244exports.parse = parse
245function parse (version, options) {
246  if (!options || typeof options !== 'object') {
247    options = {
248      loose: !!options,
249      includePrerelease: false
250    }
251  }
252
253  if (version instanceof SemVer) {
254    return version
255  }
256
257  if (typeof version !== 'string') {
258    return null
259  }
260
261  if (version.length > MAX_LENGTH) {
262    return null
263  }
264
265  var r = options.loose ? re[LOOSE] : re[FULL]
266  if (!r.test(version)) {
267    return null
268  }
269
270  try {
271    return new SemVer(version, options)
272  } catch (er) {
273    return null
274  }
275}
276
277exports.valid = valid
278function valid (version, options) {
279  var v = parse(version, options)
280  return v ? v.version : null
281}
282
283exports.clean = clean
284function clean (version, options) {
285  var s = parse(version.trim().replace(/^[=v]+/, ''), options)
286  return s ? s.version : null
287}
288
289exports.SemVer = SemVer
290
291function SemVer (version, options) {
292  if (!options || typeof options !== 'object') {
293    options = {
294      loose: !!options,
295      includePrerelease: false
296    }
297  }
298  if (version instanceof SemVer) {
299    if (version.loose === options.loose) {
300      return version
301    } else {
302      version = version.version
303    }
304  } else if (typeof version !== 'string') {
305    throw new TypeError('Invalid Version: ' + version)
306  }
307
308  if (version.length > MAX_LENGTH) {
309    throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
310  }
311
312  if (!(this instanceof SemVer)) {
313    return new SemVer(version, options)
314  }
315
316  debug('SemVer', version, options)
317  this.options = options
318  this.loose = !!options.loose
319
320  var m = version.trim().match(options.loose ? re[LOOSE] : re[FULL])
321
322  if (!m) {
323    throw new TypeError('Invalid Version: ' + version)
324  }
325
326  this.raw = version
327
328  // these are actually numbers
329  this.major = +m[1]
330  this.minor = +m[2]
331  this.patch = +m[3]
332
333  if (this.major > MAX_SAFE_INTEGER || this.major < 0) {
334    throw new TypeError('Invalid major version')
335  }
336
337  if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {
338    throw new TypeError('Invalid minor version')
339  }
340
341  if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {
342    throw new TypeError('Invalid patch version')
343  }
344
345  // numberify any prerelease numeric ids
346  if (!m[4]) {
347    this.prerelease = []
348  } else {
349    this.prerelease = m[4].split('.').map(function (id) {
350      if (/^[0-9]+$/.test(id)) {
351        var num = +id
352        if (num >= 0 && num < MAX_SAFE_INTEGER) {
353          return num
354        }
355      }
356      return id
357    })
358  }
359
360  this.build = m[5] ? m[5].split('.') : []
361  this.format()
362}
363
364SemVer.prototype.format = function () {
365  this.version = this.major + '.' + this.minor + '.' + this.patch
366  if (this.prerelease.length) {
367    this.version += '-' + this.prerelease.join('.')
368  }
369  return this.version
370}
371
372SemVer.prototype.toString = function () {
373  return this.version
374}
375
376SemVer.prototype.compare = function (other) {
377  debug('SemVer.compare', this.version, this.options, other)
378  if (!(other instanceof SemVer)) {
379    other = new SemVer(other, this.options)
380  }
381
382  return this.compareMain(other) || this.comparePre(other)
383}
384
385SemVer.prototype.compareMain = function (other) {
386  if (!(other instanceof SemVer)) {
387    other = new SemVer(other, this.options)
388  }
389
390  return compareIdentifiers(this.major, other.major) ||
391         compareIdentifiers(this.minor, other.minor) ||
392         compareIdentifiers(this.patch, other.patch)
393}
394
395SemVer.prototype.comparePre = function (other) {
396  if (!(other instanceof SemVer)) {
397    other = new SemVer(other, this.options)
398  }
399
400  // NOT having a prerelease is > having one
401  if (this.prerelease.length && !other.prerelease.length) {
402    return -1
403  } else if (!this.prerelease.length && other.prerelease.length) {
404    return 1
405  } else if (!this.prerelease.length && !other.prerelease.length) {
406    return 0
407  }
408
409  var i = 0
410  do {
411    var a = this.prerelease[i]
412    var b = other.prerelease[i]
413    debug('prerelease compare', i, a, b)
414    if (a === undefined && b === undefined) {
415      return 0
416    } else if (b === undefined) {
417      return 1
418    } else if (a === undefined) {
419      return -1
420    } else if (a === b) {
421      continue
422    } else {
423      return compareIdentifiers(a, b)
424    }
425  } while (++i)
426}
427
428// preminor will bump the version up to the next minor release, and immediately
429// down to pre-release. premajor and prepatch work the same way.
430SemVer.prototype.inc = function (release, identifier) {
431  switch (release) {
432    case 'premajor':
433      this.prerelease.length = 0
434      this.patch = 0
435      this.minor = 0
436      this.major++
437      this.inc('pre', identifier)
438      break
439    case 'preminor':
440      this.prerelease.length = 0
441      this.patch = 0
442      this.minor++
443      this.inc('pre', identifier)
444      break
445    case 'prepatch':
446      // If this is already a prerelease, it will bump to the next version
447      // drop any prereleases that might already exist, since they are not
448      // relevant at this point.
449      this.prerelease.length = 0
450      this.inc('patch', identifier)
451      this.inc('pre', identifier)
452      break
453    // If the input is a non-prerelease version, this acts the same as
454    // prepatch.
455    case 'prerelease':
456      if (this.prerelease.length === 0) {
457        this.inc('patch', identifier)
458      }
459      this.inc('pre', identifier)
460      break
461
462    case 'major':
463      // If this is a pre-major version, bump up to the same major version.
464      // Otherwise increment major.
465      // 1.0.0-5 bumps to 1.0.0
466      // 1.1.0 bumps to 2.0.0
467      if (this.minor !== 0 ||
468          this.patch !== 0 ||
469          this.prerelease.length === 0) {
470        this.major++
471      }
472      this.minor = 0
473      this.patch = 0
474      this.prerelease = []
475      break
476    case 'minor':
477      // If this is a pre-minor version, bump up to the same minor version.
478      // Otherwise increment minor.
479      // 1.2.0-5 bumps to 1.2.0
480      // 1.2.1 bumps to 1.3.0
481      if (this.patch !== 0 || this.prerelease.length === 0) {
482        this.minor++
483      }
484      this.patch = 0
485      this.prerelease = []
486      break
487    case 'patch':
488      // If this is not a pre-release version, it will increment the patch.
489      // If it is a pre-release it will bump up to the same patch version.
490      // 1.2.0-5 patches to 1.2.0
491      // 1.2.0 patches to 1.2.1
492      if (this.prerelease.length === 0) {
493        this.patch++
494      }
495      this.prerelease = []
496      break
497    // This probably shouldn't be used publicly.
498    // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
499    case 'pre':
500      if (this.prerelease.length === 0) {
501        this.prerelease = [0]
502      } else {
503        var i = this.prerelease.length
504        while (--i >= 0) {
505          if (typeof this.prerelease[i] === 'number') {
506            this.prerelease[i]++
507            i = -2
508          }
509        }
510        if (i === -1) {
511          // didn't increment anything
512          this.prerelease.push(0)
513        }
514      }
515      if (identifier) {
516        // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
517        // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
518        if (this.prerelease[0] === identifier) {
519          if (isNaN(this.prerelease[1])) {
520            this.prerelease = [identifier, 0]
521          }
522        } else {
523          this.prerelease = [identifier, 0]
524        }
525      }
526      break
527
528    default:
529      throw new Error('invalid increment argument: ' + release)
530  }
531  this.format()
532  this.raw = this.version
533  return this
534}
535
536exports.inc = inc
537function inc (version, release, loose, identifier) {
538  if (typeof (loose) === 'string') {
539    identifier = loose
540    loose = undefined
541  }
542
543  try {
544    return new SemVer(version, loose).inc(release, identifier).version
545  } catch (er) {
546    return null
547  }
548}
549
550exports.diff = diff
551function diff (version1, version2) {
552  if (eq(version1, version2)) {
553    return null
554  } else {
555    var v1 = parse(version1)
556    var v2 = parse(version2)
557    var prefix = ''
558    if (v1.prerelease.length || v2.prerelease.length) {
559      prefix = 'pre'
560      var defaultResult = 'prerelease'
561    }
562    for (var key in v1) {
563      if (key === 'major' || key === 'minor' || key === 'patch') {
564        if (v1[key] !== v2[key]) {
565          return prefix + key
566        }
567      }
568    }
569    return defaultResult // may be undefined
570  }
571}
572
573exports.compareIdentifiers = compareIdentifiers
574
575var numeric = /^[0-9]+$/
576function compareIdentifiers (a, b) {
577  var anum = numeric.test(a)
578  var bnum = numeric.test(b)
579
580  if (anum && bnum) {
581    a = +a
582    b = +b
583  }
584
585  return a === b ? 0
586    : (anum && !bnum) ? -1
587    : (bnum && !anum) ? 1
588    : a < b ? -1
589    : 1
590}
591
592exports.rcompareIdentifiers = rcompareIdentifiers
593function rcompareIdentifiers (a, b) {
594  return compareIdentifiers(b, a)
595}
596
597exports.major = major
598function major (a, loose) {
599  return new SemVer(a, loose).major
600}
601
602exports.minor = minor
603function minor (a, loose) {
604  return new SemVer(a, loose).minor
605}
606
607exports.patch = patch
608function patch (a, loose) {
609  return new SemVer(a, loose).patch
610}
611
612exports.compare = compare
613function compare (a, b, loose) {
614  return new SemVer(a, loose).compare(new SemVer(b, loose))
615}
616
617exports.compareLoose = compareLoose
618function compareLoose (a, b) {
619  return compare(a, b, true)
620}
621
622exports.rcompare = rcompare
623function rcompare (a, b, loose) {
624  return compare(b, a, loose)
625}
626
627exports.sort = sort
628function sort (list, loose) {
629  return list.sort(function (a, b) {
630    return exports.compare(a, b, loose)
631  })
632}
633
634exports.rsort = rsort
635function rsort (list, loose) {
636  return list.sort(function (a, b) {
637    return exports.rcompare(a, b, loose)
638  })
639}
640
641exports.gt = gt
642function gt (a, b, loose) {
643  return compare(a, b, loose) > 0
644}
645
646exports.lt = lt
647function lt (a, b, loose) {
648  return compare(a, b, loose) < 0
649}
650
651exports.eq = eq
652function eq (a, b, loose) {
653  return compare(a, b, loose) === 0
654}
655
656exports.neq = neq
657function neq (a, b, loose) {
658  return compare(a, b, loose) !== 0
659}
660
661exports.gte = gte
662function gte (a, b, loose) {
663  return compare(a, b, loose) >= 0
664}
665
666exports.lte = lte
667function lte (a, b, loose) {
668  return compare(a, b, loose) <= 0
669}
670
671exports.cmp = cmp
672function cmp (a, op, b, loose) {
673  switch (op) {
674    case '===':
675      if (typeof a === 'object')
676        a = a.version
677      if (typeof b === 'object')
678        b = b.version
679      return a === b
680
681    case '!==':
682      if (typeof a === 'object')
683        a = a.version
684      if (typeof b === 'object')
685        b = b.version
686      return a !== b
687
688    case '':
689    case '=':
690    case '==':
691      return eq(a, b, loose)
692
693    case '!=':
694      return neq(a, b, loose)
695
696    case '>':
697      return gt(a, b, loose)
698
699    case '>=':
700      return gte(a, b, loose)
701
702    case '<':
703      return lt(a, b, loose)
704
705    case '<=':
706      return lte(a, b, loose)
707
708    default:
709      throw new TypeError('Invalid operator: ' + op)
710  }
711}
712
713exports.Comparator = Comparator
714function Comparator (comp, options) {
715  if (!options || typeof options !== 'object') {
716    options = {
717      loose: !!options,
718      includePrerelease: false
719    }
720  }
721
722  if (comp instanceof Comparator) {
723    if (comp.loose === !!options.loose) {
724      return comp
725    } else {
726      comp = comp.value
727    }
728  }
729
730  if (!(this instanceof Comparator)) {
731    return new Comparator(comp, options)
732  }
733
734  debug('comparator', comp, options)
735  this.options = options
736  this.loose = !!options.loose
737  this.parse(comp)
738
739  if (this.semver === ANY) {
740    this.value = ''
741  } else {
742    this.value = this.operator + this.semver.version
743  }
744
745  debug('comp', this)
746}
747
748var ANY = {}
749Comparator.prototype.parse = function (comp) {
750  var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
751  var m = comp.match(r)
752
753  if (!m) {
754    throw new TypeError('Invalid comparator: ' + comp)
755  }
756
757  this.operator = m[1]
758  if (this.operator === '=') {
759    this.operator = ''
760  }
761
762  // if it literally is just '>' or '' then allow anything.
763  if (!m[2]) {
764    this.semver = ANY
765  } else {
766    this.semver = new SemVer(m[2], this.options.loose)
767  }
768}
769
770Comparator.prototype.toString = function () {
771  return this.value
772}
773
774Comparator.prototype.test = function (version) {
775  debug('Comparator.test', version, this.options.loose)
776
777  if (this.semver === ANY) {
778    return true
779  }
780
781  if (typeof version === 'string') {
782    version = new SemVer(version, this.options)
783  }
784
785  return cmp(version, this.operator, this.semver, this.options)
786}
787
788Comparator.prototype.intersects = function (comp, options) {
789  if (!(comp instanceof Comparator)) {
790    throw new TypeError('a Comparator is required')
791  }
792
793  if (!options || typeof options !== 'object') {
794    options = {
795      loose: !!options,
796      includePrerelease: false
797    }
798  }
799
800  var rangeTmp
801
802  if (this.operator === '') {
803    rangeTmp = new Range(comp.value, options)
804    return satisfies(this.value, rangeTmp, options)
805  } else if (comp.operator === '') {
806    rangeTmp = new Range(this.value, options)
807    return satisfies(comp.semver, rangeTmp, options)
808  }
809
810  var sameDirectionIncreasing =
811    (this.operator === '>=' || this.operator === '>') &&
812    (comp.operator === '>=' || comp.operator === '>')
813  var sameDirectionDecreasing =
814    (this.operator === '<=' || this.operator === '<') &&
815    (comp.operator === '<=' || comp.operator === '<')
816  var sameSemVer = this.semver.version === comp.semver.version
817  var differentDirectionsInclusive =
818    (this.operator === '>=' || this.operator === '<=') &&
819    (comp.operator === '>=' || comp.operator === '<=')
820  var oppositeDirectionsLessThan =
821    cmp(this.semver, '<', comp.semver, options) &&
822    ((this.operator === '>=' || this.operator === '>') &&
823    (comp.operator === '<=' || comp.operator === '<'))
824  var oppositeDirectionsGreaterThan =
825    cmp(this.semver, '>', comp.semver, options) &&
826    ((this.operator === '<=' || this.operator === '<') &&
827    (comp.operator === '>=' || comp.operator === '>'))
828
829  return sameDirectionIncreasing || sameDirectionDecreasing ||
830    (sameSemVer && differentDirectionsInclusive) ||
831    oppositeDirectionsLessThan || oppositeDirectionsGreaterThan
832}
833
834exports.Range = Range
835function Range (range, options) {
836  if (!options || typeof options !== 'object') {
837    options = {
838      loose: !!options,
839      includePrerelease: false
840    }
841  }
842
843  if (range instanceof Range) {
844    if (range.loose === !!options.loose &&
845        range.includePrerelease === !!options.includePrerelease) {
846      return range
847    } else {
848      return new Range(range.raw, options)
849    }
850  }
851
852  if (range instanceof Comparator) {
853    return new Range(range.value, options)
854  }
855
856  if (!(this instanceof Range)) {
857    return new Range(range, options)
858  }
859
860  this.options = options
861  this.loose = !!options.loose
862  this.includePrerelease = !!options.includePrerelease
863
864  // First, split based on boolean or ||
865  this.raw = range
866  this.set = range.split(/\s*\|\|\s*/).map(function (range) {
867    return this.parseRange(range.trim())
868  }, this).filter(function (c) {
869    // throw out any that are not relevant for whatever reason
870    return c.length
871  })
872
873  if (!this.set.length) {
874    throw new TypeError('Invalid SemVer Range: ' + range)
875  }
876
877  this.format()
878}
879
880Range.prototype.format = function () {
881  this.range = this.set.map(function (comps) {
882    return comps.join(' ').trim()
883  }).join('||').trim()
884  return this.range
885}
886
887Range.prototype.toString = function () {
888  return this.range
889}
890
891Range.prototype.parseRange = function (range) {
892  var loose = this.options.loose
893  range = range.trim()
894  // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
895  var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]
896  range = range.replace(hr, hyphenReplace)
897  debug('hyphen replace', range)
898  // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
899  range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace)
900  debug('comparator trim', range, re[COMPARATORTRIM])
901
902  // `~ 1.2.3` => `~1.2.3`
903  range = range.replace(re[TILDETRIM], tildeTrimReplace)
904
905  // `^ 1.2.3` => `^1.2.3`
906  range = range.replace(re[CARETTRIM], caretTrimReplace)
907
908  // normalize spaces
909  range = range.split(/\s+/).join(' ')
910
911  // At this point, the range is completely trimmed and
912  // ready to be split into comparators.
913
914  var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
915  var set = range.split(' ').map(function (comp) {
916    return parseComparator(comp, this.options)
917  }, this).join(' ').split(/\s+/)
918  if (this.options.loose) {
919    // in loose mode, throw out any that are not valid comparators
920    set = set.filter(function (comp) {
921      return !!comp.match(compRe)
922    })
923  }
924  set = set.map(function (comp) {
925    return new Comparator(comp, this.options)
926  }, this)
927
928  return set
929}
930
931Range.prototype.intersects = function (range, options) {
932  if (!(range instanceof Range)) {
933    throw new TypeError('a Range is required')
934  }
935
936  return this.set.some(function (thisComparators) {
937    return thisComparators.every(function (thisComparator) {
938      return range.set.some(function (rangeComparators) {
939        return rangeComparators.every(function (rangeComparator) {
940          return thisComparator.intersects(rangeComparator, options)
941        })
942      })
943    })
944  })
945}
946
947// Mostly just for testing and legacy API reasons
948exports.toComparators = toComparators
949function toComparators (range, options) {
950  return new Range(range, options).set.map(function (comp) {
951    return comp.map(function (c) {
952      return c.value
953    }).join(' ').trim().split(' ')
954  })
955}
956
957// comprised of xranges, tildes, stars, and gtlt's at this point.
958// already replaced the hyphen ranges
959// turn into a set of JUST comparators.
960function parseComparator (comp, options) {
961  debug('comp', comp, options)
962  comp = replaceCarets(comp, options)
963  debug('caret', comp)
964  comp = replaceTildes(comp, options)
965  debug('tildes', comp)
966  comp = replaceXRanges(comp, options)
967  debug('xrange', comp)
968  comp = replaceStars(comp, options)
969  debug('stars', comp)
970  return comp
971}
972
973function isX (id) {
974  return !id || id.toLowerCase() === 'x' || id === '*'
975}
976
977// ~, ~> --> * (any, kinda silly)
978// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
979// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
980// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
981// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
982// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
983function replaceTildes (comp, options) {
984  return comp.trim().split(/\s+/).map(function (comp) {
985    return replaceTilde(comp, options)
986  }).join(' ')
987}
988
989function replaceTilde (comp, options) {
990  var r = options.loose ? re[TILDELOOSE] : re[TILDE]
991  return comp.replace(r, function (_, M, m, p, pr) {
992    debug('tilde', comp, _, M, m, p, pr)
993    var ret
994
995    if (isX(M)) {
996      ret = ''
997    } else if (isX(m)) {
998      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
999    } else if (isX(p)) {
1000      // ~1.2 == >=1.2.0 <1.3.0
1001      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
1002    } else if (pr) {
1003      debug('replaceTilde pr', pr)
1004      ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1005            ' <' + M + '.' + (+m + 1) + '.0'
1006    } else {
1007      // ~1.2.3 == >=1.2.3 <1.3.0
1008      ret = '>=' + M + '.' + m + '.' + p +
1009            ' <' + M + '.' + (+m + 1) + '.0'
1010    }
1011
1012    debug('tilde return', ret)
1013    return ret
1014  })
1015}
1016
1017// ^ --> * (any, kinda silly)
1018// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
1019// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
1020// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
1021// ^1.2.3 --> >=1.2.3 <2.0.0
1022// ^1.2.0 --> >=1.2.0 <2.0.0
1023function replaceCarets (comp, options) {
1024  return comp.trim().split(/\s+/).map(function (comp) {
1025    return replaceCaret(comp, options)
1026  }).join(' ')
1027}
1028
1029function replaceCaret (comp, options) {
1030  debug('caret', comp, options)
1031  var r = options.loose ? re[CARETLOOSE] : re[CARET]
1032  return comp.replace(r, function (_, M, m, p, pr) {
1033    debug('caret', comp, _, M, m, p, pr)
1034    var ret
1035
1036    if (isX(M)) {
1037      ret = ''
1038    } else if (isX(m)) {
1039      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
1040    } else if (isX(p)) {
1041      if (M === '0') {
1042        ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
1043      } else {
1044        ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'
1045      }
1046    } else if (pr) {
1047      debug('replaceCaret pr', pr)
1048      if (M === '0') {
1049        if (m === '0') {
1050          ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1051                ' <' + M + '.' + m + '.' + (+p + 1)
1052        } else {
1053          ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1054                ' <' + M + '.' + (+m + 1) + '.0'
1055        }
1056      } else {
1057        ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1058              ' <' + (+M + 1) + '.0.0'
1059      }
1060    } else {
1061      debug('no pr')
1062      if (M === '0') {
1063        if (m === '0') {
1064          ret = '>=' + M + '.' + m + '.' + p +
1065                ' <' + M + '.' + m + '.' + (+p + 1)
1066        } else {
1067          ret = '>=' + M + '.' + m + '.' + p +
1068                ' <' + M + '.' + (+m + 1) + '.0'
1069        }
1070      } else {
1071        ret = '>=' + M + '.' + m + '.' + p +
1072              ' <' + (+M + 1) + '.0.0'
1073      }
1074    }
1075
1076    debug('caret return', ret)
1077    return ret
1078  })
1079}
1080
1081function replaceXRanges (comp, options) {
1082  debug('replaceXRanges', comp, options)
1083  return comp.split(/\s+/).map(function (comp) {
1084    return replaceXRange(comp, options)
1085  }).join(' ')
1086}
1087
1088function replaceXRange (comp, options) {
1089  comp = comp.trim()
1090  var r = options.loose ? re[XRANGELOOSE] : re[XRANGE]
1091  return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
1092    debug('xRange', comp, ret, gtlt, M, m, p, pr)
1093    var xM = isX(M)
1094    var xm = xM || isX(m)
1095    var xp = xm || isX(p)
1096    var anyX = xp
1097
1098    if (gtlt === '=' && anyX) {
1099      gtlt = ''
1100    }
1101
1102    if (xM) {
1103      if (gtlt === '>' || gtlt === '<') {
1104        // nothing is allowed
1105        ret = '<0.0.0'
1106      } else {
1107        // nothing is forbidden
1108        ret = '*'
1109      }
1110    } else if (gtlt && anyX) {
1111      // we know patch is an x, because we have any x at all.
1112      // replace X with 0
1113      if (xm) {
1114        m = 0
1115      }
1116      p = 0
1117
1118      if (gtlt === '>') {
1119        // >1 => >=2.0.0
1120        // >1.2 => >=1.3.0
1121        // >1.2.3 => >= 1.2.4
1122        gtlt = '>='
1123        if (xm) {
1124          M = +M + 1
1125          m = 0
1126          p = 0
1127        } else {
1128          m = +m + 1
1129          p = 0
1130        }
1131      } else if (gtlt === '<=') {
1132        // <=0.7.x is actually <0.8.0, since any 0.7.x should
1133        // pass.  Similarly, <=7.x is actually <8.0.0, etc.
1134        gtlt = '<'
1135        if (xm) {
1136          M = +M + 1
1137        } else {
1138          m = +m + 1
1139        }
1140      }
1141
1142      ret = gtlt + M + '.' + m + '.' + p
1143    } else if (xm) {
1144      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
1145    } else if (xp) {
1146      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
1147    }
1148
1149    debug('xRange return', ret)
1150
1151    return ret
1152  })
1153}
1154
1155// Because * is AND-ed with everything else in the comparator,
1156// and '' means "any version", just remove the *s entirely.
1157function replaceStars (comp, options) {
1158  debug('replaceStars', comp, options)
1159  // Looseness is ignored here.  star is always as loose as it gets!
1160  return comp.trim().replace(re[STAR], '')
1161}
1162
1163// This function is passed to string.replace(re[HYPHENRANGE])
1164// M, m, patch, prerelease, build
1165// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
1166// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
1167// 1.2 - 3.4 => >=1.2.0 <3.5.0
1168function hyphenReplace ($0,
1169  from, fM, fm, fp, fpr, fb,
1170  to, tM, tm, tp, tpr, tb) {
1171  if (isX(fM)) {
1172    from = ''
1173  } else if (isX(fm)) {
1174    from = '>=' + fM + '.0.0'
1175  } else if (isX(fp)) {
1176    from = '>=' + fM + '.' + fm + '.0'
1177  } else {
1178    from = '>=' + from
1179  }
1180
1181  if (isX(tM)) {
1182    to = ''
1183  } else if (isX(tm)) {
1184    to = '<' + (+tM + 1) + '.0.0'
1185  } else if (isX(tp)) {
1186    to = '<' + tM + '.' + (+tm + 1) + '.0'
1187  } else if (tpr) {
1188    to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr
1189  } else {
1190    to = '<=' + to
1191  }
1192
1193  return (from + ' ' + to).trim()
1194}
1195
1196// if ANY of the sets match ALL of its comparators, then pass
1197Range.prototype.test = function (version) {
1198  if (!version) {
1199    return false
1200  }
1201
1202  if (typeof version === 'string') {
1203    version = new SemVer(version, this.options)
1204  }
1205
1206  for (var i = 0; i < this.set.length; i++) {
1207    if (testSet(this.set[i], version, this.options)) {
1208      return true
1209    }
1210  }
1211  return false
1212}
1213
1214function testSet (set, version, options) {
1215  for (var i = 0; i < set.length; i++) {
1216    if (!set[i].test(version)) {
1217      return false
1218    }
1219  }
1220
1221  if (version.prerelease.length && !options.includePrerelease) {
1222    // Find the set of versions that are allowed to have prereleases
1223    // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
1224    // That should allow `1.2.3-pr.2` to pass.
1225    // However, `1.2.4-alpha.notready` should NOT be allowed,
1226    // even though it's within the range set by the comparators.
1227    for (i = 0; i < set.length; i++) {
1228      debug(set[i].semver)
1229      if (set[i].semver === ANY) {
1230        continue
1231      }
1232
1233      if (set[i].semver.prerelease.length > 0) {
1234        var allowed = set[i].semver
1235        if (allowed.major === version.major &&
1236            allowed.minor === version.minor &&
1237            allowed.patch === version.patch) {
1238          return true
1239        }
1240      }
1241    }
1242
1243    // Version has a -pre, but it's not one of the ones we like.
1244    return false
1245  }
1246
1247  return true
1248}
1249
1250exports.satisfies = satisfies
1251function satisfies (version, range, options) {
1252  try {
1253    range = new Range(range, options)
1254  } catch (er) {
1255    return false
1256  }
1257  return range.test(version)
1258}
1259
1260exports.maxSatisfying = maxSatisfying
1261function maxSatisfying (versions, range, options) {
1262  var max = null
1263  var maxSV = null
1264  try {
1265    var rangeObj = new Range(range, options)
1266  } catch (er) {
1267    return null
1268  }
1269  versions.forEach(function (v) {
1270    if (rangeObj.test(v)) {
1271      // satisfies(v, range, options)
1272      if (!max || maxSV.compare(v) === -1) {
1273        // compare(max, v, true)
1274        max = v
1275        maxSV = new SemVer(max, options)
1276      }
1277    }
1278  })
1279  return max
1280}
1281
1282exports.minSatisfying = minSatisfying
1283function minSatisfying (versions, range, options) {
1284  var min = null
1285  var minSV = null
1286  try {
1287    var rangeObj = new Range(range, options)
1288  } catch (er) {
1289    return null
1290  }
1291  versions.forEach(function (v) {
1292    if (rangeObj.test(v)) {
1293      // satisfies(v, range, options)
1294      if (!min || minSV.compare(v) === 1) {
1295        // compare(min, v, true)
1296        min = v
1297        minSV = new SemVer(min, options)
1298      }
1299    }
1300  })
1301  return min
1302}
1303
1304exports.minVersion = minVersion
1305function minVersion (range, loose) {
1306  range = new Range(range, loose)
1307
1308  var minver = new SemVer('0.0.0')
1309  if (range.test(minver)) {
1310    return minver
1311  }
1312
1313  minver = new SemVer('0.0.0-0')
1314  if (range.test(minver)) {
1315    return minver
1316  }
1317
1318  minver = null
1319  for (var i = 0; i < range.set.length; ++i) {
1320    var comparators = range.set[i]
1321
1322    comparators.forEach(function (comparator) {
1323      // Clone to avoid manipulating the comparator's semver object.
1324      var compver = new SemVer(comparator.semver.version)
1325      switch (comparator.operator) {
1326        case '>':
1327          if (compver.prerelease.length === 0) {
1328            compver.patch++
1329          } else {
1330            compver.prerelease.push(0)
1331          }
1332          compver.raw = compver.format()
1333          /* fallthrough */
1334        case '':
1335        case '>=':
1336          if (!minver || gt(minver, compver)) {
1337            minver = compver
1338          }
1339          break
1340        case '<':
1341        case '<=':
1342          /* Ignore maximum versions */
1343          break
1344        /* istanbul ignore next */
1345        default:
1346          throw new Error('Unexpected operation: ' + comparator.operator)
1347      }
1348    })
1349  }
1350
1351  if (minver && range.test(minver)) {
1352    return minver
1353  }
1354
1355  return null
1356}
1357
1358exports.validRange = validRange
1359function validRange (range, options) {
1360  try {
1361    // Return '*' instead of '' so that truthiness works.
1362    // This will throw if it's invalid anyway
1363    return new Range(range, options).range || '*'
1364  } catch (er) {
1365    return null
1366  }
1367}
1368
1369// Determine if version is less than all the versions possible in the range
1370exports.ltr = ltr
1371function ltr (version, range, options) {
1372  return outside(version, range, '<', options)
1373}
1374
1375// Determine if version is greater than all the versions possible in the range.
1376exports.gtr = gtr
1377function gtr (version, range, options) {
1378  return outside(version, range, '>', options)
1379}
1380
1381exports.outside = outside
1382function outside (version, range, hilo, options) {
1383  version = new SemVer(version, options)
1384  range = new Range(range, options)
1385
1386  var gtfn, ltefn, ltfn, comp, ecomp
1387  switch (hilo) {
1388    case '>':
1389      gtfn = gt
1390      ltefn = lte
1391      ltfn = lt
1392      comp = '>'
1393      ecomp = '>='
1394      break
1395    case '<':
1396      gtfn = lt
1397      ltefn = gte
1398      ltfn = gt
1399      comp = '<'
1400      ecomp = '<='
1401      break
1402    default:
1403      throw new TypeError('Must provide a hilo val of "<" or ">"')
1404  }
1405
1406  // If it satisifes the range it is not outside
1407  if (satisfies(version, range, options)) {
1408    return false
1409  }
1410
1411  // From now on, variable terms are as if we're in "gtr" mode.
1412  // but note that everything is flipped for the "ltr" function.
1413
1414  for (var i = 0; i < range.set.length; ++i) {
1415    var comparators = range.set[i]
1416
1417    var high = null
1418    var low = null
1419
1420    comparators.forEach(function (comparator) {
1421      if (comparator.semver === ANY) {
1422        comparator = new Comparator('>=0.0.0')
1423      }
1424      high = high || comparator
1425      low = low || comparator
1426      if (gtfn(comparator.semver, high.semver, options)) {
1427        high = comparator
1428      } else if (ltfn(comparator.semver, low.semver, options)) {
1429        low = comparator
1430      }
1431    })
1432
1433    // If the edge version comparator has a operator then our version
1434    // isn't outside it
1435    if (high.operator === comp || high.operator === ecomp) {
1436      return false
1437    }
1438
1439    // If the lowest version comparator has an operator and our version
1440    // is less than it then it isn't higher than the range
1441    if ((!low.operator || low.operator === comp) &&
1442        ltefn(version, low.semver)) {
1443      return false
1444    } else if (low.operator === ecomp && ltfn(version, low.semver)) {
1445      return false
1446    }
1447  }
1448  return true
1449}
1450
1451exports.prerelease = prerelease
1452function prerelease (version, options) {
1453  var parsed = parse(version, options)
1454  return (parsed && parsed.prerelease.length) ? parsed.prerelease : null
1455}
1456
1457exports.intersects = intersects
1458function intersects (r1, r2, options) {
1459  r1 = new Range(r1, options)
1460  r2 = new Range(r2, options)
1461  return r1.intersects(r2)
1462}
1463
1464exports.coerce = coerce
1465function coerce (version) {
1466  if (version instanceof SemVer) {
1467    return version
1468  }
1469
1470  if (typeof version !== 'string') {
1471    return null
1472  }
1473
1474  var match = version.match(re[COERCE])
1475
1476  if (match == null) {
1477    return null
1478  }
1479
1480  return parse(match[1] +
1481    '.' + (match[2] || '0') +
1482    '.' + (match[3] || '0'))
1483}
1484