1 exports = module.exports = SemVer
4 /* istanbul ignore next */
5 if (typeof process === 'object' &&
7 process.env.NODE_DEBUG &&
8 /\bsemver\b/i.test(process.env.NODE_DEBUG)) {
10 var args = Array.prototype.slice.call(arguments, 0)
11 args.unshift('SEMVER')
12 console.log.apply(console, args)
15 debug = function () {}
18 // Note: this is the semver.org version of the spec that it implements
19 // Not necessarily the package version of this code.
20 exports.SEMVER_SPEC_VERSION = '2.0.0'
23 var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
24 /* istanbul ignore next */ 9007199254740991
26 // Max safe segment length for coercion.
27 var MAX_SAFE_COMPONENT_LENGTH = 16
29 // The actual regexps go on exports.re
30 var re = exports.re = []
31 var src = exports.src = []
32 var t = exports.tokens = {}
39 // The following Regular Expressions can be used for tokenizing,
40 // validating, and parsing SemVer version strings.
42 // ## Numeric Identifier
43 // A single `0`, or a non-zero digit followed by zero or more digits.
45 tok('NUMERICIDENTIFIER')
46 src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*'
47 tok('NUMERICIDENTIFIERLOOSE')
48 src[t.NUMERICIDENTIFIERLOOSE] = '[0-9]+'
50 // ## Non-numeric Identifier
51 // Zero or more digits, followed by a letter or hyphen, and then zero or
52 // more letters, digits, or hyphens.
54 tok('NONNUMERICIDENTIFIER')
55 src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'
58 // Three dot-separated numeric identifiers.
61 src[t.MAINVERSION] = '(' + src[t.NUMERICIDENTIFIER] + ')\\.' +
62 '(' + src[t.NUMERICIDENTIFIER] + ')\\.' +
63 '(' + src[t.NUMERICIDENTIFIER] + ')'
65 tok('MAINVERSIONLOOSE')
66 src[t.MAINVERSIONLOOSE] = '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' +
67 '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' +
68 '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')'
70 // ## Pre-release Version Identifier
71 // A numeric identifier, or a non-numeric identifier.
73 tok('PRERELEASEIDENTIFIER')
74 src[t.PRERELEASEIDENTIFIER] = '(?:' + src[t.NUMERICIDENTIFIER] +
75 '|' + src[t.NONNUMERICIDENTIFIER] + ')'
77 tok('PRERELEASEIDENTIFIERLOOSE')
78 src[t.PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[t.NUMERICIDENTIFIERLOOSE] +
79 '|' + src[t.NONNUMERICIDENTIFIER] + ')'
81 // ## Pre-release Version
82 // Hyphen, followed by one or more dot-separated pre-release version
86 src[t.PRERELEASE] = '(?:-(' + src[t.PRERELEASEIDENTIFIER] +
87 '(?:\\.' + src[t.PRERELEASEIDENTIFIER] + ')*))'
89 tok('PRERELEASELOOSE')
90 src[t.PRERELEASELOOSE] = '(?:-?(' + src[t.PRERELEASEIDENTIFIERLOOSE] +
91 '(?:\\.' + src[t.PRERELEASEIDENTIFIERLOOSE] + ')*))'
93 // ## Build Metadata Identifier
94 // Any combination of digits, letters, or hyphens.
96 tok('BUILDIDENTIFIER')
97 src[t.BUILDIDENTIFIER] = '[0-9A-Za-z-]+'
100 // Plus sign, followed by one or more period-separated build metadata
104 src[t.BUILD] = '(?:\\+(' + src[t.BUILDIDENTIFIER] +
105 '(?:\\.' + src[t.BUILDIDENTIFIER] + ')*))'
107 // ## Full Version String
108 // A main version, followed optionally by a pre-release version and
111 // Note that the only major, minor, patch, and pre-release sections of
112 // the version string are capturing groups. The build metadata is not a
113 // capturing group, because it should not ever be used in version
118 src[t.FULLPLAIN] = 'v?' + src[t.MAINVERSION] +
119 src[t.PRERELEASE] + '?' +
122 src[t.FULL] = '^' + src[t.FULLPLAIN] + '$'
124 // like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
125 // also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
126 // common in the npm registry.
128 src[t.LOOSEPLAIN] = '[v=\\s]*' + src[t.MAINVERSIONLOOSE] +
129 src[t.PRERELEASELOOSE] + '?' +
133 src[t.LOOSE] = '^' + src[t.LOOSEPLAIN] + '$'
136 src[t.GTLT] = '((?:<|>)?=?)'
138 // Something like "2.*" or "1.2.x".
139 // Note that "x.x" is a valid xRange identifer, meaning "any version"
140 // Only the first item is strictly required.
141 tok('XRANGEIDENTIFIERLOOSE')
142 src[t.XRANGEIDENTIFIERLOOSE] = src[t.NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'
143 tok('XRANGEIDENTIFIER')
144 src[t.XRANGEIDENTIFIER] = src[t.NUMERICIDENTIFIER] + '|x|X|\\*'
147 src[t.XRANGEPLAIN] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIER] + ')' +
148 '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' +
149 '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' +
150 '(?:' + src[t.PRERELEASE] + ')?' +
154 tok('XRANGEPLAINLOOSE')
155 src[t.XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
156 '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
157 '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
158 '(?:' + src[t.PRERELEASELOOSE] + ')?' +
163 src[t.XRANGE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAIN] + '$'
165 src[t.XRANGELOOSE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAINLOOSE] + '$'
168 // Extract anything that could conceivably be a part of a valid semver
170 src[t.COERCE] = '(^|[^\\d])' +
171 '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' +
172 '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' +
173 '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' +
176 re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g')
179 // Meaning is "reasonably at or greater than"
181 src[t.LONETILDE] = '(?:~>?)'
184 src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+'
185 re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g')
186 var tildeTrimReplace = '$1~'
189 src[t.TILDE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAIN] + '$'
191 src[t.TILDELOOSE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAINLOOSE] + '$'
194 // Meaning is "at least and backwards compatible with"
196 src[t.LONECARET] = '(?:\\^)'
199 src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+'
200 re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g')
201 var caretTrimReplace = '$1^'
204 src[t.CARET] = '^' + src[t.LONECARET] + src[t.XRANGEPLAIN] + '$'
206 src[t.CARETLOOSE] = '^' + src[t.LONECARET] + src[t.XRANGEPLAINLOOSE] + '$'
208 // A simple gt/lt/eq thing, or just "" to indicate "any version"
209 tok('COMPARATORLOOSE')
210 src[t.COMPARATORLOOSE] = '^' + src[t.GTLT] + '\\s*(' + src[t.LOOSEPLAIN] + ')$|^$'
212 src[t.COMPARATOR] = '^' + src[t.GTLT] + '\\s*(' + src[t.FULLPLAIN] + ')$|^$'
214 // An expression to strip any whitespace between the gtlt and the thing
215 // it modifies, so that `> 1.2.3` ==> `>1.2.3`
216 tok('COMPARATORTRIM')
217 src[t.COMPARATORTRIM] = '(\\s*)' + src[t.GTLT] +
218 '\\s*(' + src[t.LOOSEPLAIN] + '|' + src[t.XRANGEPLAIN] + ')'
220 // this one has to use the /g flag
221 re[t.COMPARATORTRIM] = new RegExp(src[t.COMPARATORTRIM], 'g')
222 var comparatorTrimReplace = '$1$2$3'
224 // Something like `1.2.3 - 1.2.4`
225 // Note that these all use the loose form, because they'll be
226 // checked against either the strict or loose comparator form
229 src[t.HYPHENRANGE] = '^\\s*(' + src[t.XRANGEPLAIN] + ')' +
231 '(' + src[t.XRANGEPLAIN] + ')' +
234 tok('HYPHENRANGELOOSE')
235 src[t.HYPHENRANGELOOSE] = '^\\s*(' + src[t.XRANGEPLAINLOOSE] + ')' +
237 '(' + src[t.XRANGEPLAINLOOSE] + ')' +
240 // Star ranges basically just allow anything at all.
242 src[t.STAR] = '(<|>)?=?\\s*\\*'
244 // Compile to actual regexp objects.
245 // All are flag-free, unless they were created above with a flag.
246 for (var i = 0; i < R; i++) {
249 re[i] = new RegExp(src[i])
253 exports.parse = parse
254 function parse (version, options) {
255 if (!options || typeof options !== 'object') {
258 includePrerelease: false
262 if (version instanceof SemVer) {
266 if (typeof version !== 'string') {
270 if (version.length > MAX_LENGTH) {
274 var r = options.loose ? re[t.LOOSE] : re[t.FULL]
275 if (!r.test(version)) {
280 return new SemVer(version, options)
286 exports.valid = valid
287 function valid (version, options) {
288 var v = parse(version, options)
289 return v ? v.version : null
292 exports.clean = clean
293 function clean (version, options) {
294 var s = parse(version.trim().replace(/^[=v]+/, ''), options)
295 return s ? s.version : null
298 exports.SemVer = SemVer
300 function SemVer (version, options) {
301 if (!options || typeof options !== 'object') {
304 includePrerelease: false
307 if (version instanceof SemVer) {
308 if (version.loose === options.loose) {
311 version = version.version
313 } else if (typeof version !== 'string') {
314 throw new TypeError('Invalid Version: ' + version)
317 if (version.length > MAX_LENGTH) {
318 throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
321 if (!(this instanceof SemVer)) {
322 return new SemVer(version, options)
325 debug('SemVer', version, options)
326 this.options = options
327 this.loose = !!options.loose
329 var m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])
332 throw new TypeError('Invalid Version: ' + version)
337 // these are actually numbers
342 if (this.major > MAX_SAFE_INTEGER || this.major < 0) {
343 throw new TypeError('Invalid major version')
346 if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {
347 throw new TypeError('Invalid minor version')
350 if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {
351 throw new TypeError('Invalid patch version')
354 // numberify any prerelease numeric ids
358 this.prerelease = m[4].split('.').map(function (id) {
359 if (/^[0-9]+$/.test(id)) {
361 if (num >= 0 && num < MAX_SAFE_INTEGER) {
369 this.build = m[5] ? m[5].split('.') : []
373 SemVer.prototype.format = function () {
374 this.version = this.major + '.' + this.minor + '.' + this.patch
375 if (this.prerelease.length) {
376 this.version += '-' + this.prerelease.join('.')
381 SemVer.prototype.toString = function () {
385 SemVer.prototype.compare = function (other) {
386 debug('SemVer.compare', this.version, this.options, other)
387 if (!(other instanceof SemVer)) {
388 other = new SemVer(other, this.options)
391 return this.compareMain(other) || this.comparePre(other)
394 SemVer.prototype.compareMain = function (other) {
395 if (!(other instanceof SemVer)) {
396 other = new SemVer(other, this.options)
399 return compareIdentifiers(this.major, other.major) ||
400 compareIdentifiers(this.minor, other.minor) ||
401 compareIdentifiers(this.patch, other.patch)
404 SemVer.prototype.comparePre = function (other) {
405 if (!(other instanceof SemVer)) {
406 other = new SemVer(other, this.options)
409 // NOT having a prerelease is > having one
410 if (this.prerelease.length && !other.prerelease.length) {
412 } else if (!this.prerelease.length && other.prerelease.length) {
414 } else if (!this.prerelease.length && !other.prerelease.length) {
420 var a = this.prerelease[i]
421 var b = other.prerelease[i]
422 debug('prerelease compare', i, a, b)
423 if (a === undefined && b === undefined) {
425 } else if (b === undefined) {
427 } else if (a === undefined) {
429 } else if (a === b) {
432 return compareIdentifiers(a, b)
437 SemVer.prototype.compareBuild = function (other) {
438 if (!(other instanceof SemVer)) {
439 other = new SemVer(other, this.options)
444 var a = this.build[i]
445 var b = other.build[i]
446 debug('prerelease compare', i, a, b)
447 if (a === undefined && b === undefined) {
449 } else if (b === undefined) {
451 } else if (a === undefined) {
453 } else if (a === b) {
456 return compareIdentifiers(a, b)
461 // preminor will bump the version up to the next minor release, and immediately
462 // down to pre-release. premajor and prepatch work the same way.
463 SemVer.prototype.inc = function (release, identifier) {
466 this.prerelease.length = 0
470 this.inc('pre', identifier)
473 this.prerelease.length = 0
476 this.inc('pre', identifier)
479 // If this is already a prerelease, it will bump to the next version
480 // drop any prereleases that might already exist, since they are not
481 // relevant at this point.
482 this.prerelease.length = 0
483 this.inc('patch', identifier)
484 this.inc('pre', identifier)
486 // If the input is a non-prerelease version, this acts the same as
489 if (this.prerelease.length === 0) {
490 this.inc('patch', identifier)
492 this.inc('pre', identifier)
496 // If this is a pre-major version, bump up to the same major version.
497 // Otherwise increment major.
498 // 1.0.0-5 bumps to 1.0.0
499 // 1.1.0 bumps to 2.0.0
500 if (this.minor !== 0 ||
502 this.prerelease.length === 0) {
510 // If this is a pre-minor version, bump up to the same minor version.
511 // Otherwise increment minor.
512 // 1.2.0-5 bumps to 1.2.0
513 // 1.2.1 bumps to 1.3.0
514 if (this.patch !== 0 || this.prerelease.length === 0) {
521 // If this is not a pre-release version, it will increment the patch.
522 // If it is a pre-release it will bump up to the same patch version.
523 // 1.2.0-5 patches to 1.2.0
524 // 1.2.0 patches to 1.2.1
525 if (this.prerelease.length === 0) {
530 // This probably shouldn't be used publicly.
531 // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
533 if (this.prerelease.length === 0) {
534 this.prerelease = [0]
536 var i = this.prerelease.length
538 if (typeof this.prerelease[i] === 'number') {
544 // didn't increment anything
545 this.prerelease.push(0)
549 // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
550 // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
551 if (this.prerelease[0] === identifier) {
552 if (isNaN(this.prerelease[1])) {
553 this.prerelease = [identifier, 0]
556 this.prerelease = [identifier, 0]
562 throw new Error('invalid increment argument: ' + release)
565 this.raw = this.version
570 function inc (version, release, loose, identifier) {
571 if (typeof (loose) === 'string') {
577 return new SemVer(version, loose).inc(release, identifier).version
584 function diff (version1, version2) {
585 if (eq(version1, version2)) {
588 var v1 = parse(version1)
589 var v2 = parse(version2)
591 if (v1.prerelease.length || v2.prerelease.length) {
593 var defaultResult = 'prerelease'
595 for (var key in v1) {
596 if (key === 'major' || key === 'minor' || key === 'patch') {
597 if (v1[key] !== v2[key]) {
602 return defaultResult // may be undefined
606 exports.compareIdentifiers = compareIdentifiers
608 var numeric = /^[0-9]+$/
609 function compareIdentifiers (a, b) {
610 var anum = numeric.test(a)
611 var bnum = numeric.test(b)
619 : (anum && !bnum) ? -1
620 : (bnum && !anum) ? 1
625 exports.rcompareIdentifiers = rcompareIdentifiers
626 function rcompareIdentifiers (a, b) {
627 return compareIdentifiers(b, a)
630 exports.major = major
631 function major (a, loose) {
632 return new SemVer(a, loose).major
635 exports.minor = minor
636 function minor (a, loose) {
637 return new SemVer(a, loose).minor
640 exports.patch = patch
641 function patch (a, loose) {
642 return new SemVer(a, loose).patch
645 exports.compare = compare
646 function compare (a, b, loose) {
647 return new SemVer(a, loose).compare(new SemVer(b, loose))
650 exports.compareLoose = compareLoose
651 function compareLoose (a, b) {
652 return compare(a, b, true)
655 exports.compareBuild = compareBuild
656 function compareBuild (a, b, loose) {
657 var versionA = new SemVer(a, loose)
658 var versionB = new SemVer(b, loose)
659 return versionA.compare(versionB) || versionA.compareBuild(versionB)
662 exports.rcompare = rcompare
663 function rcompare (a, b, loose) {
664 return compare(b, a, loose)
668 function sort (list, loose) {
669 return list.sort(function (a, b) {
670 return exports.compareBuild(a, b, loose)
674 exports.rsort = rsort
675 function rsort (list, loose) {
676 return list.sort(function (a, b) {
677 return exports.compareBuild(b, a, loose)
682 function gt (a, b, loose) {
683 return compare(a, b, loose) > 0
687 function lt (a, b, loose) {
688 return compare(a, b, loose) < 0
692 function eq (a, b, loose) {
693 return compare(a, b, loose) === 0
697 function neq (a, b, loose) {
698 return compare(a, b, loose) !== 0
702 function gte (a, b, loose) {
703 return compare(a, b, loose) >= 0
707 function lte (a, b, loose) {
708 return compare(a, b, loose) <= 0
712 function cmp (a, op, b, loose) {
715 if (typeof a === 'object')
717 if (typeof b === 'object')
722 if (typeof a === 'object')
724 if (typeof b === 'object')
731 return eq(a, b, loose)
734 return neq(a, b, loose)
737 return gt(a, b, loose)
740 return gte(a, b, loose)
743 return lt(a, b, loose)
746 return lte(a, b, loose)
749 throw new TypeError('Invalid operator: ' + op)
753 exports.Comparator = Comparator
754 function Comparator (comp, options) {
755 if (!options || typeof options !== 'object') {
758 includePrerelease: false
762 if (comp instanceof Comparator) {
763 if (comp.loose === !!options.loose) {
770 if (!(this instanceof Comparator)) {
771 return new Comparator(comp, options)
774 debug('comparator', comp, options)
775 this.options = options
776 this.loose = !!options.loose
779 if (this.semver === ANY) {
782 this.value = this.operator + this.semver.version
789 Comparator.prototype.parse = function (comp) {
790 var r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
791 var m = comp.match(r)
794 throw new TypeError('Invalid comparator: ' + comp)
797 this.operator = m[1] !== undefined ? m[1] : ''
798 if (this.operator === '=') {
802 // if it literally is just '>' or '' then allow anything.
806 this.semver = new SemVer(m[2], this.options.loose)
810 Comparator.prototype.toString = function () {
814 Comparator.prototype.test = function (version) {
815 debug('Comparator.test', version, this.options.loose)
817 if (this.semver === ANY || version === ANY) {
821 if (typeof version === 'string') {
823 version = new SemVer(version, this.options)
829 return cmp(version, this.operator, this.semver, this.options)
832 Comparator.prototype.intersects = function (comp, options) {
833 if (!(comp instanceof Comparator)) {
834 throw new TypeError('a Comparator is required')
837 if (!options || typeof options !== 'object') {
840 includePrerelease: false
846 if (this.operator === '') {
847 if (this.value === '') {
850 rangeTmp = new Range(comp.value, options)
851 return satisfies(this.value, rangeTmp, options)
852 } else if (comp.operator === '') {
853 if (comp.value === '') {
856 rangeTmp = new Range(this.value, options)
857 return satisfies(comp.semver, rangeTmp, options)
860 var sameDirectionIncreasing =
861 (this.operator === '>=' || this.operator === '>') &&
862 (comp.operator === '>=' || comp.operator === '>')
863 var sameDirectionDecreasing =
864 (this.operator === '<=' || this.operator === '<') &&
865 (comp.operator === '<=' || comp.operator === '<')
866 var sameSemVer = this.semver.version === comp.semver.version
867 var differentDirectionsInclusive =
868 (this.operator === '>=' || this.operator === '<=') &&
869 (comp.operator === '>=' || comp.operator === '<=')
870 var oppositeDirectionsLessThan =
871 cmp(this.semver, '<', comp.semver, options) &&
872 ((this.operator === '>=' || this.operator === '>') &&
873 (comp.operator === '<=' || comp.operator === '<'))
874 var oppositeDirectionsGreaterThan =
875 cmp(this.semver, '>', comp.semver, options) &&
876 ((this.operator === '<=' || this.operator === '<') &&
877 (comp.operator === '>=' || comp.operator === '>'))
879 return sameDirectionIncreasing || sameDirectionDecreasing ||
880 (sameSemVer && differentDirectionsInclusive) ||
881 oppositeDirectionsLessThan || oppositeDirectionsGreaterThan
884 exports.Range = Range
885 function Range (range, options) {
886 if (!options || typeof options !== 'object') {
889 includePrerelease: false
893 if (range instanceof Range) {
894 if (range.loose === !!options.loose &&
895 range.includePrerelease === !!options.includePrerelease) {
898 return new Range(range.raw, options)
902 if (range instanceof Comparator) {
903 return new Range(range.value, options)
906 if (!(this instanceof Range)) {
907 return new Range(range, options)
910 this.options = options
911 this.loose = !!options.loose
912 this.includePrerelease = !!options.includePrerelease
914 // First, split based on boolean or ||
916 this.set = range.split(/\s*\|\|\s*/).map(function (range) {
917 return this.parseRange(range.trim())
918 }, this).filter(function (c) {
919 // throw out any that are not relevant for whatever reason
923 if (!this.set.length) {
924 throw new TypeError('Invalid SemVer Range: ' + range)
930 Range.prototype.format = function () {
931 this.range = this.set.map(function (comps) {
932 return comps.join(' ').trim()
937 Range.prototype.toString = function () {
941 Range.prototype.parseRange = function (range) {
942 var loose = this.options.loose
944 // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
945 var hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]
946 range = range.replace(hr, hyphenReplace)
947 debug('hyphen replace', range)
948 // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
949 range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
950 debug('comparator trim', range, re[t.COMPARATORTRIM])
952 // `~ 1.2.3` => `~1.2.3`
953 range = range.replace(re[t.TILDETRIM], tildeTrimReplace)
955 // `^ 1.2.3` => `^1.2.3`
956 range = range.replace(re[t.CARETTRIM], caretTrimReplace)
959 range = range.split(/\s+/).join(' ')
961 // At this point, the range is completely trimmed and
962 // ready to be split into comparators.
964 var compRe = loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
965 var set = range.split(' ').map(function (comp) {
966 return parseComparator(comp, this.options)
967 }, this).join(' ').split(/\s+/)
968 if (this.options.loose) {
969 // in loose mode, throw out any that are not valid comparators
970 set = set.filter(function (comp) {
971 return !!comp.match(compRe)
974 set = set.map(function (comp) {
975 return new Comparator(comp, this.options)
981 Range.prototype.intersects = function (range, options) {
982 if (!(range instanceof Range)) {
983 throw new TypeError('a Range is required')
986 return this.set.some(function (thisComparators) {
988 isSatisfiable(thisComparators, options) &&
989 range.set.some(function (rangeComparators) {
991 isSatisfiable(rangeComparators, options) &&
992 thisComparators.every(function (thisComparator) {
993 return rangeComparators.every(function (rangeComparator) {
994 return thisComparator.intersects(rangeComparator, options)
1003 // take a set of comparators and determine whether there
1004 // exists a version which can satisfy it
1005 function isSatisfiable (comparators, options) {
1007 var remainingComparators = comparators.slice()
1008 var testComparator = remainingComparators.pop()
1010 while (result && remainingComparators.length) {
1011 result = remainingComparators.every(function (otherComparator) {
1012 return testComparator.intersects(otherComparator, options)
1015 testComparator = remainingComparators.pop()
1021 // Mostly just for testing and legacy API reasons
1022 exports.toComparators = toComparators
1023 function toComparators (range, options) {
1024 return new Range(range, options).set.map(function (comp) {
1025 return comp.map(function (c) {
1027 }).join(' ').trim().split(' ')
1031 // comprised of xranges, tildes, stars, and gtlt's at this point.
1032 // already replaced the hyphen ranges
1033 // turn into a set of JUST comparators.
1034 function parseComparator (comp, options) {
1035 debug('comp', comp, options)
1036 comp = replaceCarets(comp, options)
1037 debug('caret', comp)
1038 comp = replaceTildes(comp, options)
1039 debug('tildes', comp)
1040 comp = replaceXRanges(comp, options)
1041 debug('xrange', comp)
1042 comp = replaceStars(comp, options)
1043 debug('stars', comp)
1048 return !id || id.toLowerCase() === 'x' || id === '*'
1051 // ~, ~> --> * (any, kinda silly)
1052 // ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
1053 // ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
1054 // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
1055 // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
1056 // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
1057 function replaceTildes (comp, options) {
1058 return comp.trim().split(/\s+/).map(function (comp) {
1059 return replaceTilde(comp, options)
1063 function replaceTilde (comp, options) {
1064 var r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]
1065 return comp.replace(r, function (_, M, m, p, pr) {
1066 debug('tilde', comp, _, M, m, p, pr)
1071 } else if (isX(m)) {
1072 ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
1073 } else if (isX(p)) {
1074 // ~1.2 == >=1.2.0 <1.3.0
1075 ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
1077 debug('replaceTilde pr', pr)
1078 ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1079 ' <' + M + '.' + (+m + 1) + '.0'
1081 // ~1.2.3 == >=1.2.3 <1.3.0
1082 ret = '>=' + M + '.' + m + '.' + p +
1083 ' <' + M + '.' + (+m + 1) + '.0'
1086 debug('tilde return', ret)
1091 // ^ --> * (any, kinda silly)
1092 // ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
1093 // ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
1094 // ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
1095 // ^1.2.3 --> >=1.2.3 <2.0.0
1096 // ^1.2.0 --> >=1.2.0 <2.0.0
1097 function replaceCarets (comp, options) {
1098 return comp.trim().split(/\s+/).map(function (comp) {
1099 return replaceCaret(comp, options)
1103 function replaceCaret (comp, options) {
1104 debug('caret', comp, options)
1105 var r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]
1106 return comp.replace(r, function (_, M, m, p, pr) {
1107 debug('caret', comp, _, M, m, p, pr)
1112 } else if (isX(m)) {
1113 ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
1114 } else if (isX(p)) {
1116 ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
1118 ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'
1121 debug('replaceCaret pr', pr)
1124 ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1125 ' <' + M + '.' + m + '.' + (+p + 1)
1127 ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1128 ' <' + M + '.' + (+m + 1) + '.0'
1131 ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1132 ' <' + (+M + 1) + '.0.0'
1138 ret = '>=' + M + '.' + m + '.' + p +
1139 ' <' + M + '.' + m + '.' + (+p + 1)
1141 ret = '>=' + M + '.' + m + '.' + p +
1142 ' <' + M + '.' + (+m + 1) + '.0'
1145 ret = '>=' + M + '.' + m + '.' + p +
1146 ' <' + (+M + 1) + '.0.0'
1150 debug('caret return', ret)
1155 function replaceXRanges (comp, options) {
1156 debug('replaceXRanges', comp, options)
1157 return comp.split(/\s+/).map(function (comp) {
1158 return replaceXRange(comp, options)
1162 function replaceXRange (comp, options) {
1164 var r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]
1165 return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
1166 debug('xRange', comp, ret, gtlt, M, m, p, pr)
1168 var xm = xM || isX(m)
1169 var xp = xm || isX(p)
1172 if (gtlt === '=' && anyX) {
1176 // if we're including prereleases in the match, then we need
1177 // to fix this to -0, the lowest possible prerelease value
1178 pr = options.includePrerelease ? '-0' : ''
1181 if (gtlt === '>' || gtlt === '<') {
1182 // nothing is allowed
1185 // nothing is forbidden
1188 } else if (gtlt && anyX) {
1189 // we know patch is an x, because we have any x at all.
1199 // >1.2.3 => >= 1.2.4
1209 } else if (gtlt === '<=') {
1210 // <=0.7.x is actually <0.8.0, since any 0.7.x should
1211 // pass. Similarly, <=7.x is actually <8.0.0, etc.
1220 ret = gtlt + M + '.' + m + '.' + p + pr
1222 ret = '>=' + M + '.0.0' + pr + ' <' + (+M + 1) + '.0.0' + pr
1224 ret = '>=' + M + '.' + m + '.0' + pr +
1225 ' <' + M + '.' + (+m + 1) + '.0' + pr
1228 debug('xRange return', ret)
1234 // Because * is AND-ed with everything else in the comparator,
1235 // and '' means "any version", just remove the *s entirely.
1236 function replaceStars (comp, options) {
1237 debug('replaceStars', comp, options)
1238 // Looseness is ignored here. star is always as loose as it gets!
1239 return comp.trim().replace(re[t.STAR], '')
1242 // This function is passed to string.replace(re[t.HYPHENRANGE])
1243 // M, m, patch, prerelease, build
1244 // 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
1245 // 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
1246 // 1.2 - 3.4 => >=1.2.0 <3.5.0
1247 function hyphenReplace ($0,
1248 from, fM, fm, fp, fpr, fb,
1249 to, tM, tm, tp, tpr, tb) {
1252 } else if (isX(fm)) {
1253 from = '>=' + fM + '.0.0'
1254 } else if (isX(fp)) {
1255 from = '>=' + fM + '.' + fm + '.0'
1262 } else if (isX(tm)) {
1263 to = '<' + (+tM + 1) + '.0.0'
1264 } else if (isX(tp)) {
1265 to = '<' + tM + '.' + (+tm + 1) + '.0'
1267 to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr
1272 return (from + ' ' + to).trim()
1275 // if ANY of the sets match ALL of its comparators, then pass
1276 Range.prototype.test = function (version) {
1281 if (typeof version === 'string') {
1283 version = new SemVer(version, this.options)
1289 for (var i = 0; i < this.set.length; i++) {
1290 if (testSet(this.set[i], version, this.options)) {
1297 function testSet (set, version, options) {
1298 for (var i = 0; i < set.length; i++) {
1299 if (!set[i].test(version)) {
1304 if (version.prerelease.length && !options.includePrerelease) {
1305 // Find the set of versions that are allowed to have prereleases
1306 // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
1307 // That should allow `1.2.3-pr.2` to pass.
1308 // However, `1.2.4-alpha.notready` should NOT be allowed,
1309 // even though it's within the range set by the comparators.
1310 for (i = 0; i < set.length; i++) {
1311 debug(set[i].semver)
1312 if (set[i].semver === ANY) {
1316 if (set[i].semver.prerelease.length > 0) {
1317 var allowed = set[i].semver
1318 if (allowed.major === version.major &&
1319 allowed.minor === version.minor &&
1320 allowed.patch === version.patch) {
1326 // Version has a -pre, but it's not one of the ones we like.
1333 exports.satisfies = satisfies
1334 function satisfies (version, range, options) {
1336 range = new Range(range, options)
1340 return range.test(version)
1343 exports.maxSatisfying = maxSatisfying
1344 function maxSatisfying (versions, range, options) {
1348 var rangeObj = new Range(range, options)
1352 versions.forEach(function (v) {
1353 if (rangeObj.test(v)) {
1354 // satisfies(v, range, options)
1355 if (!max || maxSV.compare(v) === -1) {
1356 // compare(max, v, true)
1358 maxSV = new SemVer(max, options)
1365 exports.minSatisfying = minSatisfying
1366 function minSatisfying (versions, range, options) {
1370 var rangeObj = new Range(range, options)
1374 versions.forEach(function (v) {
1375 if (rangeObj.test(v)) {
1376 // satisfies(v, range, options)
1377 if (!min || minSV.compare(v) === 1) {
1378 // compare(min, v, true)
1380 minSV = new SemVer(min, options)
1387 exports.minVersion = minVersion
1388 function minVersion (range, loose) {
1389 range = new Range(range, loose)
1391 var minver = new SemVer('0.0.0')
1392 if (range.test(minver)) {
1396 minver = new SemVer('0.0.0-0')
1397 if (range.test(minver)) {
1402 for (var i = 0; i < range.set.length; ++i) {
1403 var comparators = range.set[i]
1405 comparators.forEach(function (comparator) {
1406 // Clone to avoid manipulating the comparator's semver object.
1407 var compver = new SemVer(comparator.semver.version)
1408 switch (comparator.operator) {
1410 if (compver.prerelease.length === 0) {
1413 compver.prerelease.push(0)
1415 compver.raw = compver.format()
1419 if (!minver || gt(minver, compver)) {
1425 /* Ignore maximum versions */
1427 /* istanbul ignore next */
1429 throw new Error('Unexpected operation: ' + comparator.operator)
1434 if (minver && range.test(minver)) {
1441 exports.validRange = validRange
1442 function validRange (range, options) {
1444 // Return '*' instead of '' so that truthiness works.
1445 // This will throw if it's invalid anyway
1446 return new Range(range, options).range || '*'
1452 // Determine if version is less than all the versions possible in the range
1454 function ltr (version, range, options) {
1455 return outside(version, range, '<', options)
1458 // Determine if version is greater than all the versions possible in the range.
1460 function gtr (version, range, options) {
1461 return outside(version, range, '>', options)
1464 exports.outside = outside
1465 function outside (version, range, hilo, options) {
1466 version = new SemVer(version, options)
1467 range = new Range(range, options)
1469 var gtfn, ltefn, ltfn, comp, ecomp
1486 throw new TypeError('Must provide a hilo val of "<" or ">"')
1489 // If it satisifes the range it is not outside
1490 if (satisfies(version, range, options)) {
1494 // From now on, variable terms are as if we're in "gtr" mode.
1495 // but note that everything is flipped for the "ltr" function.
1497 for (var i = 0; i < range.set.length; ++i) {
1498 var comparators = range.set[i]
1503 comparators.forEach(function (comparator) {
1504 if (comparator.semver === ANY) {
1505 comparator = new Comparator('>=0.0.0')
1507 high = high || comparator
1508 low = low || comparator
1509 if (gtfn(comparator.semver, high.semver, options)) {
1511 } else if (ltfn(comparator.semver, low.semver, options)) {
1516 // If the edge version comparator has a operator then our version
1518 if (high.operator === comp || high.operator === ecomp) {
1522 // If the lowest version comparator has an operator and our version
1523 // is less than it then it isn't higher than the range
1524 if ((!low.operator || low.operator === comp) &&
1525 ltefn(version, low.semver)) {
1527 } else if (low.operator === ecomp && ltfn(version, low.semver)) {
1534 exports.prerelease = prerelease
1535 function prerelease (version, options) {
1536 var parsed = parse(version, options)
1537 return (parsed && parsed.prerelease.length) ? parsed.prerelease : null
1540 exports.intersects = intersects
1541 function intersects (r1, r2, options) {
1542 r1 = new Range(r1, options)
1543 r2 = new Range(r2, options)
1544 return r1.intersects(r2)
1547 exports.coerce = coerce
1548 function coerce (version, options) {
1549 if (version instanceof SemVer) {
1553 if (typeof version === 'number') {
1554 version = String(version)
1557 if (typeof version !== 'string') {
1561 options = options || {}
1565 match = version.match(re[t.COERCE])
1567 // Find the right-most coercible string that does not share
1568 // a terminus with a more left-ward coercible string.
1569 // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4'
1571 // Walk through the string checking with a /g regexp
1572 // Manually set the index so as to pick up overlapping matches.
1573 // Stop when we get a match that ends at the string end, since no
1574 // coercible string can be more right-ward without the same terminus.
1576 while ((next = re[t.COERCERTL].exec(version)) &&
1577 (!match || match.index + match[0].length !== version.length)
1580 next.index + next[0].length !== match.index + match[0].length) {
1583 re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length
1585 // leave it in a clean state
1586 re[t.COERCERTL].lastIndex = -1
1589 if (match === null) {
1593 return parse(match[2] +
1594 '.' + (match[3] || '0') +
1595 '.' + (match[4] || '0'), options)