semver.js
   1  exports = module.exports = SemVer
   2  
   3  var debug
   4  /* istanbul ignore next */
   5  if (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.
  20  exports.SEMVER_SPEC_VERSION = '2.0.0'
  21  
  22  var MAX_LENGTH = 256
  23  var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
  24    /* istanbul ignore next */ 9007199254740991
  25  
  26  // Max safe segment length for coercion.
  27  var MAX_SAFE_COMPONENT_LENGTH = 16
  28  
  29  // The actual regexps go on exports.re
  30  var re = exports.re = []
  31  var src = exports.src = []
  32  var 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  
  40  var NUMERICIDENTIFIER = R++
  41  src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'
  42  var NUMERICIDENTIFIERLOOSE = R++
  43  src[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  
  49  var NONNUMERICIDENTIFIER = R++
  50  src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'
  51  
  52  // ## Main Version
  53  // Three dot-separated numeric identifiers.
  54  
  55  var MAINVERSION = R++
  56  src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' +
  57                     '(' + src[NUMERICIDENTIFIER] + ')\\.' +
  58                     '(' + src[NUMERICIDENTIFIER] + ')'
  59  
  60  var MAINVERSIONLOOSE = R++
  61  src[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  
  68  var PRERELEASEIDENTIFIER = R++
  69  src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] +
  70                              '|' + src[NONNUMERICIDENTIFIER] + ')'
  71  
  72  var PRERELEASEIDENTIFIERLOOSE = R++
  73  src[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  
  80  var PRERELEASE = R++
  81  src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] +
  82                    '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'
  83  
  84  var PRERELEASELOOSE = R++
  85  src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] +
  86                         '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'
  87  
  88  // ## Build Metadata Identifier
  89  // Any combination of digits, letters, or hyphens.
  90  
  91  var BUILDIDENTIFIER = R++
  92  src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'
  93  
  94  // ## Build Metadata
  95  // Plus sign, followed by one or more period-separated build metadata
  96  // identifiers.
  97  
  98  var BUILD = R++
  99  src[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  
 111  var FULL = R++
 112  var FULLPLAIN = 'v?' + src[MAINVERSION] +
 113                  src[PRERELEASE] + '?' +
 114                  src[BUILD] + '?'
 115  
 116  src[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.
 121  var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] +
 122                   src[PRERELEASELOOSE] + '?' +
 123                   src[BUILD] + '?'
 124  
 125  var LOOSE = R++
 126  src[LOOSE] = '^' + LOOSEPLAIN + '$'
 127  
 128  var GTLT = R++
 129  src[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.
 134  var XRANGEIDENTIFIERLOOSE = R++
 135  src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'
 136  var XRANGEIDENTIFIER = R++
 137  src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'
 138  
 139  var XRANGEPLAIN = R++
 140  src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' +
 141                     '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
 142                     '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
 143                     '(?:' + src[PRERELEASE] + ')?' +
 144                     src[BUILD] + '?' +
 145                     ')?)?'
 146  
 147  var XRANGEPLAINLOOSE = R++
 148  src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
 149                          '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
 150                          '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
 151                          '(?:' + src[PRERELEASELOOSE] + ')?' +
 152                          src[BUILD] + '?' +
 153                          ')?)?'
 154  
 155  var XRANGE = R++
 156  src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'
 157  var XRANGELOOSE = R++
 158  src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'
 159  
 160  // Coercion.
 161  // Extract anything that could conceivably be a part of a valid semver
 162  var COERCE = R++
 163  src[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"
 171  var LONETILDE = R++
 172  src[LONETILDE] = '(?:~>?)'
 173  
 174  var TILDETRIM = R++
 175  src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'
 176  re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g')
 177  var tildeTrimReplace = '$1~'
 178  
 179  var TILDE = R++
 180  src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'
 181  var TILDELOOSE = R++
 182  src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'
 183  
 184  // Caret ranges.
 185  // Meaning is "at least and backwards compatible with"
 186  var LONECARET = R++
 187  src[LONECARET] = '(?:\\^)'
 188  
 189  var CARETTRIM = R++
 190  src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'
 191  re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g')
 192  var caretTrimReplace = '$1^'
 193  
 194  var CARET = R++
 195  src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'
 196  var CARETLOOSE = R++
 197  src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'
 198  
 199  // A simple gt/lt/eq thing, or just "" to indicate "any version"
 200  var COMPARATORLOOSE = R++
 201  src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'
 202  var COMPARATOR = R++
 203  src[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`
 207  var COMPARATORTRIM = R++
 208  src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] +
 209                        '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'
 210  
 211  // this one has to use the /g flag
 212  re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g')
 213  var 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.
 219  var HYPHENRANGE = R++
 220  src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' +
 221                     '\\s+-\\s+' +
 222                     '(' + src[XRANGEPLAIN] + ')' +
 223                     '\\s*$'
 224  
 225  var HYPHENRANGELOOSE = R++
 226  src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' +
 227                          '\\s+-\\s+' +
 228                          '(' + src[XRANGEPLAINLOOSE] + ')' +
 229                          '\\s*$'
 230  
 231  // Star ranges basically just allow anything at all.
 232  var STAR = R++
 233  src[STAR] = '(<|>)?=?\\s*\\*'
 234  
 235  // Compile to actual regexp objects.
 236  // All are flag-free, unless they were created above with a flag.
 237  for (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  
 244  exports.parse = parse
 245  function 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  
 277  exports.valid = valid
 278  function valid (version, options) {
 279    var v = parse(version, options)
 280    return v ? v.version : null
 281  }
 282  
 283  exports.clean = clean
 284  function clean (version, options) {
 285    var s = parse(version.trim().replace(/^[=v]+/, ''), options)
 286    return s ? s.version : null
 287  }
 288  
 289  exports.SemVer = SemVer
 290  
 291  function 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  
 364  SemVer.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  
 372  SemVer.prototype.toString = function () {
 373    return this.version
 374  }
 375  
 376  SemVer.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  
 385  SemVer.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  
 395  SemVer.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.
 430  SemVer.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  
 536  exports.inc = inc
 537  function 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  
 550  exports.diff = diff
 551  function 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  
 573  exports.compareIdentifiers = compareIdentifiers
 574  
 575  var numeric = /^[0-9]+$/
 576  function 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  
 592  exports.rcompareIdentifiers = rcompareIdentifiers
 593  function rcompareIdentifiers (a, b) {
 594    return compareIdentifiers(b, a)
 595  }
 596  
 597  exports.major = major
 598  function major (a, loose) {
 599    return new SemVer(a, loose).major
 600  }
 601  
 602  exports.minor = minor
 603  function minor (a, loose) {
 604    return new SemVer(a, loose).minor
 605  }
 606  
 607  exports.patch = patch
 608  function patch (a, loose) {
 609    return new SemVer(a, loose).patch
 610  }
 611  
 612  exports.compare = compare
 613  function compare (a, b, loose) {
 614    return new SemVer(a, loose).compare(new SemVer(b, loose))
 615  }
 616  
 617  exports.compareLoose = compareLoose
 618  function compareLoose (a, b) {
 619    return compare(a, b, true)
 620  }
 621  
 622  exports.rcompare = rcompare
 623  function rcompare (a, b, loose) {
 624    return compare(b, a, loose)
 625  }
 626  
 627  exports.sort = sort
 628  function sort (list, loose) {
 629    return list.sort(function (a, b) {
 630      return exports.compare(a, b, loose)
 631    })
 632  }
 633  
 634  exports.rsort = rsort
 635  function rsort (list, loose) {
 636    return list.sort(function (a, b) {
 637      return exports.rcompare(a, b, loose)
 638    })
 639  }
 640  
 641  exports.gt = gt
 642  function gt (a, b, loose) {
 643    return compare(a, b, loose) > 0
 644  }
 645  
 646  exports.lt = lt
 647  function lt (a, b, loose) {
 648    return compare(a, b, loose) < 0
 649  }
 650  
 651  exports.eq = eq
 652  function eq (a, b, loose) {
 653    return compare(a, b, loose) === 0
 654  }
 655  
 656  exports.neq = neq
 657  function neq (a, b, loose) {
 658    return compare(a, b, loose) !== 0
 659  }
 660  
 661  exports.gte = gte
 662  function gte (a, b, loose) {
 663    return compare(a, b, loose) >= 0
 664  }
 665  
 666  exports.lte = lte
 667  function lte (a, b, loose) {
 668    return compare(a, b, loose) <= 0
 669  }
 670  
 671  exports.cmp = cmp
 672  function 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  
 713  exports.Comparator = Comparator
 714  function 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  
 748  var ANY = {}
 749  Comparator.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  
 770  Comparator.prototype.toString = function () {
 771    return this.value
 772  }
 773  
 774  Comparator.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  
 788  Comparator.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  
 834  exports.Range = Range
 835  function 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  
 880  Range.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  
 887  Range.prototype.toString = function () {
 888    return this.range
 889  }
 890  
 891  Range.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  
 931  Range.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
 948  exports.toComparators = toComparators
 949  function 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.
 960  function 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  
 973  function 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
 983  function replaceTildes (comp, options) {
 984    return comp.trim().split(/\s+/).map(function (comp) {
 985      return replaceTilde(comp, options)
 986    }).join(' ')
 987  }
 988  
 989  function 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
1023  function replaceCarets (comp, options) {
1024    return comp.trim().split(/\s+/).map(function (comp) {
1025      return replaceCaret(comp, options)
1026    }).join(' ')
1027  }
1028  
1029  function 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  
1081  function 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  
1088  function 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.
1157  function 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
1168  function 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
1197  Range.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  
1214  function 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  
1250  exports.satisfies = satisfies
1251  function 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  
1260  exports.maxSatisfying = maxSatisfying
1261  function 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  
1282  exports.minSatisfying = minSatisfying
1283  function 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  
1304  exports.minVersion = minVersion
1305  function 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  
1358  exports.validRange = validRange
1359  function 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
1370  exports.ltr = ltr
1371  function 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.
1376  exports.gtr = gtr
1377  function gtr (version, range, options) {
1378    return outside(version, range, '>', options)
1379  }
1380  
1381  exports.outside = outside
1382  function 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  
1451  exports.prerelease = prerelease
1452  function prerelease (version, options) {
1453    var parsed = parse(version, options)
1454    return (parsed && parsed.prerelease.length) ? parsed.prerelease : null
1455  }
1456  
1457  exports.intersects = intersects
1458  function intersects (r1, r2, options) {
1459    r1 = new Range(r1, options)
1460    r2 = new Range(r2, options)
1461    return r1.intersects(r2)
1462  }
1463  
1464  exports.coerce = coerce
1465  function 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  }