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 t = exports.tokens = {}
  33  var R = 0
  34  
  35  function tok (n) {
  36    t[n] = R++
  37  }
  38  
  39  // The following Regular Expressions can be used for tokenizing,
  40  // validating, and parsing SemVer version strings.
  41  
  42  // ## Numeric Identifier
  43  // A single `0`, or a non-zero digit followed by zero or more digits.
  44  
  45  tok('NUMERICIDENTIFIER')
  46  src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*'
  47  tok('NUMERICIDENTIFIERLOOSE')
  48  src[t.NUMERICIDENTIFIERLOOSE] = '[0-9]+'
  49  
  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.
  53  
  54  tok('NONNUMERICIDENTIFIER')
  55  src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'
  56  
  57  // ## Main Version
  58  // Three dot-separated numeric identifiers.
  59  
  60  tok('MAINVERSION')
  61  src[t.MAINVERSION] = '(' + src[t.NUMERICIDENTIFIER] + ')\\.' +
  62                     '(' + src[t.NUMERICIDENTIFIER] + ')\\.' +
  63                     '(' + src[t.NUMERICIDENTIFIER] + ')'
  64  
  65  tok('MAINVERSIONLOOSE')
  66  src[t.MAINVERSIONLOOSE] = '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' +
  67                          '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' +
  68                          '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')'
  69  
  70  // ## Pre-release Version Identifier
  71  // A numeric identifier, or a non-numeric identifier.
  72  
  73  tok('PRERELEASEIDENTIFIER')
  74  src[t.PRERELEASEIDENTIFIER] = '(?:' + src[t.NUMERICIDENTIFIER] +
  75                              '|' + src[t.NONNUMERICIDENTIFIER] + ')'
  76  
  77  tok('PRERELEASEIDENTIFIERLOOSE')
  78  src[t.PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[t.NUMERICIDENTIFIERLOOSE] +
  79                                   '|' + src[t.NONNUMERICIDENTIFIER] + ')'
  80  
  81  // ## Pre-release Version
  82  // Hyphen, followed by one or more dot-separated pre-release version
  83  // identifiers.
  84  
  85  tok('PRERELEASE')
  86  src[t.PRERELEASE] = '(?:-(' + src[t.PRERELEASEIDENTIFIER] +
  87                    '(?:\\.' + src[t.PRERELEASEIDENTIFIER] + ')*))'
  88  
  89  tok('PRERELEASELOOSE')
  90  src[t.PRERELEASELOOSE] = '(?:-?(' + src[t.PRERELEASEIDENTIFIERLOOSE] +
  91                         '(?:\\.' + src[t.PRERELEASEIDENTIFIERLOOSE] + ')*))'
  92  
  93  // ## Build Metadata Identifier
  94  // Any combination of digits, letters, or hyphens.
  95  
  96  tok('BUILDIDENTIFIER')
  97  src[t.BUILDIDENTIFIER] = '[0-9A-Za-z-]+'
  98  
  99  // ## Build Metadata
 100  // Plus sign, followed by one or more period-separated build metadata
 101  // identifiers.
 102  
 103  tok('BUILD')
 104  src[t.BUILD] = '(?:\\+(' + src[t.BUILDIDENTIFIER] +
 105               '(?:\\.' + src[t.BUILDIDENTIFIER] + ')*))'
 106  
 107  // ## Full Version String
 108  // A main version, followed optionally by a pre-release version and
 109  // build metadata.
 110  
 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
 114  // comparison.
 115  
 116  tok('FULL')
 117  tok('FULLPLAIN')
 118  src[t.FULLPLAIN] = 'v?' + src[t.MAINVERSION] +
 119                    src[t.PRERELEASE] + '?' +
 120                    src[t.BUILD] + '?'
 121  
 122  src[t.FULL] = '^' + src[t.FULLPLAIN] + '$'
 123  
 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.
 127  tok('LOOSEPLAIN')
 128  src[t.LOOSEPLAIN] = '[v=\\s]*' + src[t.MAINVERSIONLOOSE] +
 129                    src[t.PRERELEASELOOSE] + '?' +
 130                    src[t.BUILD] + '?'
 131  
 132  tok('LOOSE')
 133  src[t.LOOSE] = '^' + src[t.LOOSEPLAIN] + '$'
 134  
 135  tok('GTLT')
 136  src[t.GTLT] = '((?:<|>)?=?)'
 137  
 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|\\*'
 145  
 146  tok('XRANGEPLAIN')
 147  src[t.XRANGEPLAIN] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIER] + ')' +
 148                     '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' +
 149                     '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' +
 150                     '(?:' + src[t.PRERELEASE] + ')?' +
 151                     src[t.BUILD] + '?' +
 152                     ')?)?'
 153  
 154  tok('XRANGEPLAINLOOSE')
 155  src[t.XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
 156                          '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
 157                          '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' +
 158                          '(?:' + src[t.PRERELEASELOOSE] + ')?' +
 159                          src[t.BUILD] + '?' +
 160                          ')?)?'
 161  
 162  tok('XRANGE')
 163  src[t.XRANGE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAIN] + '$'
 164  tok('XRANGELOOSE')
 165  src[t.XRANGELOOSE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAINLOOSE] + '$'
 166  
 167  // Coercion.
 168  // Extract anything that could conceivably be a part of a valid semver
 169  tok('COERCE')
 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 + '}))?' +
 174                '(?:$|[^\\d])'
 175  tok('COERCERTL')
 176  re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g')
 177  
 178  // Tilde ranges.
 179  // Meaning is "reasonably at or greater than"
 180  tok('LONETILDE')
 181  src[t.LONETILDE] = '(?:~>?)'
 182  
 183  tok('TILDETRIM')
 184  src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+'
 185  re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g')
 186  var tildeTrimReplace = '$1~'
 187  
 188  tok('TILDE')
 189  src[t.TILDE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAIN] + '$'
 190  tok('TILDELOOSE')
 191  src[t.TILDELOOSE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAINLOOSE] + '$'
 192  
 193  // Caret ranges.
 194  // Meaning is "at least and backwards compatible with"
 195  tok('LONECARET')
 196  src[t.LONECARET] = '(?:\\^)'
 197  
 198  tok('CARETTRIM')
 199  src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+'
 200  re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g')
 201  var caretTrimReplace = '$1^'
 202  
 203  tok('CARET')
 204  src[t.CARET] = '^' + src[t.LONECARET] + src[t.XRANGEPLAIN] + '$'
 205  tok('CARETLOOSE')
 206  src[t.CARETLOOSE] = '^' + src[t.LONECARET] + src[t.XRANGEPLAINLOOSE] + '$'
 207  
 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] + ')$|^$'
 211  tok('COMPARATOR')
 212  src[t.COMPARATOR] = '^' + src[t.GTLT] + '\\s*(' + src[t.FULLPLAIN] + ')$|^$'
 213  
 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] + ')'
 219  
 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'
 223  
 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
 227  // later.
 228  tok('HYPHENRANGE')
 229  src[t.HYPHENRANGE] = '^\\s*(' + src[t.XRANGEPLAIN] + ')' +
 230                     '\\s+-\\s+' +
 231                     '(' + src[t.XRANGEPLAIN] + ')' +
 232                     '\\s*$'
 233  
 234  tok('HYPHENRANGELOOSE')
 235  src[t.HYPHENRANGELOOSE] = '^\\s*(' + src[t.XRANGEPLAINLOOSE] + ')' +
 236                          '\\s+-\\s+' +
 237                          '(' + src[t.XRANGEPLAINLOOSE] + ')' +
 238                          '\\s*$'
 239  
 240  // Star ranges basically just allow anything at all.
 241  tok('STAR')
 242  src[t.STAR] = '(<|>)?=?\\s*\\*'
 243  
 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++) {
 247    debug(i, src[i])
 248    if (!re[i]) {
 249      re[i] = new RegExp(src[i])
 250    }
 251  }
 252  
 253  exports.parse = parse
 254  function parse (version, options) {
 255    if (!options || typeof options !== 'object') {
 256      options = {
 257        loose: !!options,
 258        includePrerelease: false
 259      }
 260    }
 261  
 262    if (version instanceof SemVer) {
 263      return version
 264    }
 265  
 266    if (typeof version !== 'string') {
 267      return null
 268    }
 269  
 270    if (version.length > MAX_LENGTH) {
 271      return null
 272    }
 273  
 274    var r = options.loose ? re[t.LOOSE] : re[t.FULL]
 275    if (!r.test(version)) {
 276      return null
 277    }
 278  
 279    try {
 280      return new SemVer(version, options)
 281    } catch (er) {
 282      return null
 283    }
 284  }
 285  
 286  exports.valid = valid
 287  function valid (version, options) {
 288    var v = parse(version, options)
 289    return v ? v.version : null
 290  }
 291  
 292  exports.clean = clean
 293  function clean (version, options) {
 294    var s = parse(version.trim().replace(/^[=v]+/, ''), options)
 295    return s ? s.version : null
 296  }
 297  
 298  exports.SemVer = SemVer
 299  
 300  function SemVer (version, options) {
 301    if (!options || typeof options !== 'object') {
 302      options = {
 303        loose: !!options,
 304        includePrerelease: false
 305      }
 306    }
 307    if (version instanceof SemVer) {
 308      if (version.loose === options.loose) {
 309        return version
 310      } else {
 311        version = version.version
 312      }
 313    } else if (typeof version !== 'string') {
 314      throw new TypeError('Invalid Version: ' + version)
 315    }
 316  
 317    if (version.length > MAX_LENGTH) {
 318      throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
 319    }
 320  
 321    if (!(this instanceof SemVer)) {
 322      return new SemVer(version, options)
 323    }
 324  
 325    debug('SemVer', version, options)
 326    this.options = options
 327    this.loose = !!options.loose
 328  
 329    var m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])
 330  
 331    if (!m) {
 332      throw new TypeError('Invalid Version: ' + version)
 333    }
 334  
 335    this.raw = version
 336  
 337    // these are actually numbers
 338    this.major = +m[1]
 339    this.minor = +m[2]
 340    this.patch = +m[3]
 341  
 342    if (this.major > MAX_SAFE_INTEGER || this.major < 0) {
 343      throw new TypeError('Invalid major version')
 344    }
 345  
 346    if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {
 347      throw new TypeError('Invalid minor version')
 348    }
 349  
 350    if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {
 351      throw new TypeError('Invalid patch version')
 352    }
 353  
 354    // numberify any prerelease numeric ids
 355    if (!m[4]) {
 356      this.prerelease = []
 357    } else {
 358      this.prerelease = m[4].split('.').map(function (id) {
 359        if (/^[0-9]+$/.test(id)) {
 360          var num = +id
 361          if (num >= 0 && num < MAX_SAFE_INTEGER) {
 362            return num
 363          }
 364        }
 365        return id
 366      })
 367    }
 368  
 369    this.build = m[5] ? m[5].split('.') : []
 370    this.format()
 371  }
 372  
 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('.')
 377    }
 378    return this.version
 379  }
 380  
 381  SemVer.prototype.toString = function () {
 382    return this.version
 383  }
 384  
 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)
 389    }
 390  
 391    return this.compareMain(other) || this.comparePre(other)
 392  }
 393  
 394  SemVer.prototype.compareMain = function (other) {
 395    if (!(other instanceof SemVer)) {
 396      other = new SemVer(other, this.options)
 397    }
 398  
 399    return compareIdentifiers(this.major, other.major) ||
 400           compareIdentifiers(this.minor, other.minor) ||
 401           compareIdentifiers(this.patch, other.patch)
 402  }
 403  
 404  SemVer.prototype.comparePre = function (other) {
 405    if (!(other instanceof SemVer)) {
 406      other = new SemVer(other, this.options)
 407    }
 408  
 409    // NOT having a prerelease is > having one
 410    if (this.prerelease.length && !other.prerelease.length) {
 411      return -1
 412    } else if (!this.prerelease.length && other.prerelease.length) {
 413      return 1
 414    } else if (!this.prerelease.length && !other.prerelease.length) {
 415      return 0
 416    }
 417  
 418    var i = 0
 419    do {
 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) {
 424        return 0
 425      } else if (b === undefined) {
 426        return 1
 427      } else if (a === undefined) {
 428        return -1
 429      } else if (a === b) {
 430        continue
 431      } else {
 432        return compareIdentifiers(a, b)
 433      }
 434    } while (++i)
 435  }
 436  
 437  SemVer.prototype.compareBuild = function (other) {
 438    if (!(other instanceof SemVer)) {
 439      other = new SemVer(other, this.options)
 440    }
 441  
 442    var i = 0
 443    do {
 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) {
 448        return 0
 449      } else if (b === undefined) {
 450        return 1
 451      } else if (a === undefined) {
 452        return -1
 453      } else if (a === b) {
 454        continue
 455      } else {
 456        return compareIdentifiers(a, b)
 457      }
 458    } while (++i)
 459  }
 460  
 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) {
 464    switch (release) {
 465      case 'premajor':
 466        this.prerelease.length = 0
 467        this.patch = 0
 468        this.minor = 0
 469        this.major++
 470        this.inc('pre', identifier)
 471        break
 472      case 'preminor':
 473        this.prerelease.length = 0
 474        this.patch = 0
 475        this.minor++
 476        this.inc('pre', identifier)
 477        break
 478      case 'prepatch':
 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)
 485        break
 486      // If the input is a non-prerelease version, this acts the same as
 487      // prepatch.
 488      case 'prerelease':
 489        if (this.prerelease.length === 0) {
 490          this.inc('patch', identifier)
 491        }
 492        this.inc('pre', identifier)
 493        break
 494  
 495      case 'major':
 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 ||
 501            this.patch !== 0 ||
 502            this.prerelease.length === 0) {
 503          this.major++
 504        }
 505        this.minor = 0
 506        this.patch = 0
 507        this.prerelease = []
 508        break
 509      case 'minor':
 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) {
 515          this.minor++
 516        }
 517        this.patch = 0
 518        this.prerelease = []
 519        break
 520      case 'patch':
 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) {
 526          this.patch++
 527        }
 528        this.prerelease = []
 529        break
 530      // This probably shouldn't be used publicly.
 531      // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
 532      case 'pre':
 533        if (this.prerelease.length === 0) {
 534          this.prerelease = [0]
 535        } else {
 536          var i = this.prerelease.length
 537          while (--i >= 0) {
 538            if (typeof this.prerelease[i] === 'number') {
 539              this.prerelease[i]++
 540              i = -2
 541            }
 542          }
 543          if (i === -1) {
 544            // didn't increment anything
 545            this.prerelease.push(0)
 546          }
 547        }
 548        if (identifier) {
 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]
 554            }
 555          } else {
 556            this.prerelease = [identifier, 0]
 557          }
 558        }
 559        break
 560  
 561      default:
 562        throw new Error('invalid increment argument: ' + release)
 563    }
 564    this.format()
 565    this.raw = this.version
 566    return this
 567  }
 568  
 569  exports.inc = inc
 570  function inc (version, release, loose, identifier) {
 571    if (typeof (loose) === 'string') {
 572      identifier = loose
 573      loose = undefined
 574    }
 575  
 576    try {
 577      return new SemVer(version, loose).inc(release, identifier).version
 578    } catch (er) {
 579      return null
 580    }
 581  }
 582  
 583  exports.diff = diff
 584  function diff (version1, version2) {
 585    if (eq(version1, version2)) {
 586      return null
 587    } else {
 588      var v1 = parse(version1)
 589      var v2 = parse(version2)
 590      var prefix = ''
 591      if (v1.prerelease.length || v2.prerelease.length) {
 592        prefix = 'pre'
 593        var defaultResult = 'prerelease'
 594      }
 595      for (var key in v1) {
 596        if (key === 'major' || key === 'minor' || key === 'patch') {
 597          if (v1[key] !== v2[key]) {
 598            return prefix + key
 599          }
 600        }
 601      }
 602      return defaultResult // may be undefined
 603    }
 604  }
 605  
 606  exports.compareIdentifiers = compareIdentifiers
 607  
 608  var numeric = /^[0-9]+$/
 609  function compareIdentifiers (a, b) {
 610    var anum = numeric.test(a)
 611    var bnum = numeric.test(b)
 612  
 613    if (anum && bnum) {
 614      a = +a
 615      b = +b
 616    }
 617  
 618    return a === b ? 0
 619      : (anum && !bnum) ? -1
 620      : (bnum && !anum) ? 1
 621      : a < b ? -1
 622      : 1
 623  }
 624  
 625  exports.rcompareIdentifiers = rcompareIdentifiers
 626  function rcompareIdentifiers (a, b) {
 627    return compareIdentifiers(b, a)
 628  }
 629  
 630  exports.major = major
 631  function major (a, loose) {
 632    return new SemVer(a, loose).major
 633  }
 634  
 635  exports.minor = minor
 636  function minor (a, loose) {
 637    return new SemVer(a, loose).minor
 638  }
 639  
 640  exports.patch = patch
 641  function patch (a, loose) {
 642    return new SemVer(a, loose).patch
 643  }
 644  
 645  exports.compare = compare
 646  function compare (a, b, loose) {
 647    return new SemVer(a, loose).compare(new SemVer(b, loose))
 648  }
 649  
 650  exports.compareLoose = compareLoose
 651  function compareLoose (a, b) {
 652    return compare(a, b, true)
 653  }
 654  
 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)
 660  }
 661  
 662  exports.rcompare = rcompare
 663  function rcompare (a, b, loose) {
 664    return compare(b, a, loose)
 665  }
 666  
 667  exports.sort = sort
 668  function sort (list, loose) {
 669    return list.sort(function (a, b) {
 670      return exports.compareBuild(a, b, loose)
 671    })
 672  }
 673  
 674  exports.rsort = rsort
 675  function rsort (list, loose) {
 676    return list.sort(function (a, b) {
 677      return exports.compareBuild(b, a, loose)
 678    })
 679  }
 680  
 681  exports.gt = gt
 682  function gt (a, b, loose) {
 683    return compare(a, b, loose) > 0
 684  }
 685  
 686  exports.lt = lt
 687  function lt (a, b, loose) {
 688    return compare(a, b, loose) < 0
 689  }
 690  
 691  exports.eq = eq
 692  function eq (a, b, loose) {
 693    return compare(a, b, loose) === 0
 694  }
 695  
 696  exports.neq = neq
 697  function neq (a, b, loose) {
 698    return compare(a, b, loose) !== 0
 699  }
 700  
 701  exports.gte = gte
 702  function gte (a, b, loose) {
 703    return compare(a, b, loose) >= 0
 704  }
 705  
 706  exports.lte = lte
 707  function lte (a, b, loose) {
 708    return compare(a, b, loose) <= 0
 709  }
 710  
 711  exports.cmp = cmp
 712  function cmp (a, op, b, loose) {
 713    switch (op) {
 714      case '===':
 715        if (typeof a === 'object')
 716          a = a.version
 717        if (typeof b === 'object')
 718          b = b.version
 719        return a === b
 720  
 721      case '!==':
 722        if (typeof a === 'object')
 723          a = a.version
 724        if (typeof b === 'object')
 725          b = b.version
 726        return a !== b
 727  
 728      case '':
 729      case '=':
 730      case '==':
 731        return eq(a, b, loose)
 732  
 733      case '!=':
 734        return neq(a, b, loose)
 735  
 736      case '>':
 737        return gt(a, b, loose)
 738  
 739      case '>=':
 740        return gte(a, b, loose)
 741  
 742      case '<':
 743        return lt(a, b, loose)
 744  
 745      case '<=':
 746        return lte(a, b, loose)
 747  
 748      default:
 749        throw new TypeError('Invalid operator: ' + op)
 750    }
 751  }
 752  
 753  exports.Comparator = Comparator
 754  function Comparator (comp, options) {
 755    if (!options || typeof options !== 'object') {
 756      options = {
 757        loose: !!options,
 758        includePrerelease: false
 759      }
 760    }
 761  
 762    if (comp instanceof Comparator) {
 763      if (comp.loose === !!options.loose) {
 764        return comp
 765      } else {
 766        comp = comp.value
 767      }
 768    }
 769  
 770    if (!(this instanceof Comparator)) {
 771      return new Comparator(comp, options)
 772    }
 773  
 774    debug('comparator', comp, options)
 775    this.options = options
 776    this.loose = !!options.loose
 777    this.parse(comp)
 778  
 779    if (this.semver === ANY) {
 780      this.value = ''
 781    } else {
 782      this.value = this.operator + this.semver.version
 783    }
 784  
 785    debug('comp', this)
 786  }
 787  
 788  var ANY = {}
 789  Comparator.prototype.parse = function (comp) {
 790    var r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
 791    var m = comp.match(r)
 792  
 793    if (!m) {
 794      throw new TypeError('Invalid comparator: ' + comp)
 795    }
 796  
 797    this.operator = m[1] !== undefined ? m[1] : ''
 798    if (this.operator === '=') {
 799      this.operator = ''
 800    }
 801  
 802    // if it literally is just '>' or '' then allow anything.
 803    if (!m[2]) {
 804      this.semver = ANY
 805    } else {
 806      this.semver = new SemVer(m[2], this.options.loose)
 807    }
 808  }
 809  
 810  Comparator.prototype.toString = function () {
 811    return this.value
 812  }
 813  
 814  Comparator.prototype.test = function (version) {
 815    debug('Comparator.test', version, this.options.loose)
 816  
 817    if (this.semver === ANY || version === ANY) {
 818      return true
 819    }
 820  
 821    if (typeof version === 'string') {
 822      try {
 823        version = new SemVer(version, this.options)
 824      } catch (er) {
 825        return false
 826      }
 827    }
 828  
 829    return cmp(version, this.operator, this.semver, this.options)
 830  }
 831  
 832  Comparator.prototype.intersects = function (comp, options) {
 833    if (!(comp instanceof Comparator)) {
 834      throw new TypeError('a Comparator is required')
 835    }
 836  
 837    if (!options || typeof options !== 'object') {
 838      options = {
 839        loose: !!options,
 840        includePrerelease: false
 841      }
 842    }
 843  
 844    var rangeTmp
 845  
 846    if (this.operator === '') {
 847      if (this.value === '') {
 848        return true
 849      }
 850      rangeTmp = new Range(comp.value, options)
 851      return satisfies(this.value, rangeTmp, options)
 852    } else if (comp.operator === '') {
 853      if (comp.value === '') {
 854        return true
 855      }
 856      rangeTmp = new Range(this.value, options)
 857      return satisfies(comp.semver, rangeTmp, options)
 858    }
 859  
 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 === '>'))
 878  
 879    return sameDirectionIncreasing || sameDirectionDecreasing ||
 880      (sameSemVer && differentDirectionsInclusive) ||
 881      oppositeDirectionsLessThan || oppositeDirectionsGreaterThan
 882  }
 883  
 884  exports.Range = Range
 885  function Range (range, options) {
 886    if (!options || typeof options !== 'object') {
 887      options = {
 888        loose: !!options,
 889        includePrerelease: false
 890      }
 891    }
 892  
 893    if (range instanceof Range) {
 894      if (range.loose === !!options.loose &&
 895          range.includePrerelease === !!options.includePrerelease) {
 896        return range
 897      } else {
 898        return new Range(range.raw, options)
 899      }
 900    }
 901  
 902    if (range instanceof Comparator) {
 903      return new Range(range.value, options)
 904    }
 905  
 906    if (!(this instanceof Range)) {
 907      return new Range(range, options)
 908    }
 909  
 910    this.options = options
 911    this.loose = !!options.loose
 912    this.includePrerelease = !!options.includePrerelease
 913  
 914    // First, split based on boolean or ||
 915    this.raw = range
 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
 920      return c.length
 921    })
 922  
 923    if (!this.set.length) {
 924      throw new TypeError('Invalid SemVer Range: ' + range)
 925    }
 926  
 927    this.format()
 928  }
 929  
 930  Range.prototype.format = function () {
 931    this.range = this.set.map(function (comps) {
 932      return comps.join(' ').trim()
 933    }).join('||').trim()
 934    return this.range
 935  }
 936  
 937  Range.prototype.toString = function () {
 938    return this.range
 939  }
 940  
 941  Range.prototype.parseRange = function (range) {
 942    var loose = this.options.loose
 943    range = range.trim()
 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])
 951  
 952    // `~ 1.2.3` => `~1.2.3`
 953    range = range.replace(re[t.TILDETRIM], tildeTrimReplace)
 954  
 955    // `^ 1.2.3` => `^1.2.3`
 956    range = range.replace(re[t.CARETTRIM], caretTrimReplace)
 957  
 958    // normalize spaces
 959    range = range.split(/\s+/).join(' ')
 960  
 961    // At this point, the range is completely trimmed and
 962    // ready to be split into comparators.
 963  
 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)
 972      })
 973    }
 974    set = set.map(function (comp) {
 975      return new Comparator(comp, this.options)
 976    }, this)
 977  
 978    return set
 979  }
 980  
 981  Range.prototype.intersects = function (range, options) {
 982    if (!(range instanceof Range)) {
 983      throw new TypeError('a Range is required')
 984    }
 985  
 986    return this.set.some(function (thisComparators) {
 987      return (
 988        isSatisfiable(thisComparators, options) &&
 989        range.set.some(function (rangeComparators) {
 990          return (
 991            isSatisfiable(rangeComparators, options) &&
 992            thisComparators.every(function (thisComparator) {
 993              return rangeComparators.every(function (rangeComparator) {
 994                return thisComparator.intersects(rangeComparator, options)
 995              })
 996            })
 997          )
 998        })
 999      )
1000    })
1001  }
1002  
1003  // take a set of comparators and determine whether there
1004  // exists a version which can satisfy it
1005  function isSatisfiable (comparators, options) {
1006    var result = true
1007    var remainingComparators = comparators.slice()
1008    var testComparator = remainingComparators.pop()
1009  
1010    while (result && remainingComparators.length) {
1011      result = remainingComparators.every(function (otherComparator) {
1012        return testComparator.intersects(otherComparator, options)
1013      })
1014  
1015      testComparator = remainingComparators.pop()
1016    }
1017  
1018    return result
1019  }
1020  
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) {
1026        return c.value
1027      }).join(' ').trim().split(' ')
1028    })
1029  }
1030  
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)
1044    return comp
1045  }
1046  
1047  function isX (id) {
1048    return !id || id.toLowerCase() === 'x' || id === '*'
1049  }
1050  
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)
1060    }).join(' ')
1061  }
1062  
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)
1067      var ret
1068  
1069      if (isX(M)) {
1070        ret = ''
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'
1076      } else if (pr) {
1077        debug('replaceTilde pr', pr)
1078        ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1079              ' <' + M + '.' + (+m + 1) + '.0'
1080      } else {
1081        // ~1.2.3 == >=1.2.3 <1.3.0
1082        ret = '>=' + M + '.' + m + '.' + p +
1083              ' <' + M + '.' + (+m + 1) + '.0'
1084      }
1085  
1086      debug('tilde return', ret)
1087      return ret
1088    })
1089  }
1090  
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)
1100    }).join(' ')
1101  }
1102  
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)
1108      var ret
1109  
1110      if (isX(M)) {
1111        ret = ''
1112      } else if (isX(m)) {
1113        ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
1114      } else if (isX(p)) {
1115        if (M === '0') {
1116          ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
1117        } else {
1118          ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'
1119        }
1120      } else if (pr) {
1121        debug('replaceCaret pr', pr)
1122        if (M === '0') {
1123          if (m === '0') {
1124            ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1125                  ' <' + M + '.' + m + '.' + (+p + 1)
1126          } else {
1127            ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1128                  ' <' + M + '.' + (+m + 1) + '.0'
1129          }
1130        } else {
1131          ret = '>=' + M + '.' + m + '.' + p + '-' + pr +
1132                ' <' + (+M + 1) + '.0.0'
1133        }
1134      } else {
1135        debug('no pr')
1136        if (M === '0') {
1137          if (m === '0') {
1138            ret = '>=' + M + '.' + m + '.' + p +
1139                  ' <' + M + '.' + m + '.' + (+p + 1)
1140          } else {
1141            ret = '>=' + M + '.' + m + '.' + p +
1142                  ' <' + M + '.' + (+m + 1) + '.0'
1143          }
1144        } else {
1145          ret = '>=' + M + '.' + m + '.' + p +
1146                ' <' + (+M + 1) + '.0.0'
1147        }
1148      }
1149  
1150      debug('caret return', ret)
1151      return ret
1152    })
1153  }
1154  
1155  function replaceXRanges (comp, options) {
1156    debug('replaceXRanges', comp, options)
1157    return comp.split(/\s+/).map(function (comp) {
1158      return replaceXRange(comp, options)
1159    }).join(' ')
1160  }
1161  
1162  function replaceXRange (comp, options) {
1163    comp = comp.trim()
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)
1167      var xM = isX(M)
1168      var xm = xM || isX(m)
1169      var xp = xm || isX(p)
1170      var anyX = xp
1171  
1172      if (gtlt === '=' && anyX) {
1173        gtlt = ''
1174      }
1175  
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' : ''
1179  
1180      if (xM) {
1181        if (gtlt === '>' || gtlt === '<') {
1182          // nothing is allowed
1183          ret = '<0.0.0-0'
1184        } else {
1185          // nothing is forbidden
1186          ret = '*'
1187        }
1188      } else if (gtlt && anyX) {
1189        // we know patch is an x, because we have any x at all.
1190        // replace X with 0
1191        if (xm) {
1192          m = 0
1193        }
1194        p = 0
1195  
1196        if (gtlt === '>') {
1197          // >1 => >=2.0.0
1198          // >1.2 => >=1.3.0
1199          // >1.2.3 => >= 1.2.4
1200          gtlt = '>='
1201          if (xm) {
1202            M = +M + 1
1203            m = 0
1204            p = 0
1205          } else {
1206            m = +m + 1
1207            p = 0
1208          }
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.
1212          gtlt = '<'
1213          if (xm) {
1214            M = +M + 1
1215          } else {
1216            m = +m + 1
1217          }
1218        }
1219  
1220        ret = gtlt + M + '.' + m + '.' + p + pr
1221      } else if (xm) {
1222        ret = '>=' + M + '.0.0' + pr + ' <' + (+M + 1) + '.0.0' + pr
1223      } else if (xp) {
1224        ret = '>=' + M + '.' + m + '.0' + pr +
1225          ' <' + M + '.' + (+m + 1) + '.0' + pr
1226      }
1227  
1228      debug('xRange return', ret)
1229  
1230      return ret
1231    })
1232  }
1233  
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], '')
1240  }
1241  
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) {
1250    if (isX(fM)) {
1251      from = ''
1252    } else if (isX(fm)) {
1253      from = '>=' + fM + '.0.0'
1254    } else if (isX(fp)) {
1255      from = '>=' + fM + '.' + fm + '.0'
1256    } else {
1257      from = '>=' + from
1258    }
1259  
1260    if (isX(tM)) {
1261      to = ''
1262    } else if (isX(tm)) {
1263      to = '<' + (+tM + 1) + '.0.0'
1264    } else if (isX(tp)) {
1265      to = '<' + tM + '.' + (+tm + 1) + '.0'
1266    } else if (tpr) {
1267      to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr
1268    } else {
1269      to = '<=' + to
1270    }
1271  
1272    return (from + ' ' + to).trim()
1273  }
1274  
1275  // if ANY of the sets match ALL of its comparators, then pass
1276  Range.prototype.test = function (version) {
1277    if (!version) {
1278      return false
1279    }
1280  
1281    if (typeof version === 'string') {
1282      try {
1283        version = new SemVer(version, this.options)
1284      } catch (er) {
1285        return false
1286      }
1287    }
1288  
1289    for (var i = 0; i < this.set.length; i++) {
1290      if (testSet(this.set[i], version, this.options)) {
1291        return true
1292      }
1293    }
1294    return false
1295  }
1296  
1297  function testSet (set, version, options) {
1298    for (var i = 0; i < set.length; i++) {
1299      if (!set[i].test(version)) {
1300        return false
1301      }
1302    }
1303  
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) {
1313          continue
1314        }
1315  
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) {
1321            return true
1322          }
1323        }
1324      }
1325  
1326      // Version has a -pre, but it's not one of the ones we like.
1327      return false
1328    }
1329  
1330    return true
1331  }
1332  
1333  exports.satisfies = satisfies
1334  function satisfies (version, range, options) {
1335    try {
1336      range = new Range(range, options)
1337    } catch (er) {
1338      return false
1339    }
1340    return range.test(version)
1341  }
1342  
1343  exports.maxSatisfying = maxSatisfying
1344  function maxSatisfying (versions, range, options) {
1345    var max = null
1346    var maxSV = null
1347    try {
1348      var rangeObj = new Range(range, options)
1349    } catch (er) {
1350      return null
1351    }
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)
1357          max = v
1358          maxSV = new SemVer(max, options)
1359        }
1360      }
1361    })
1362    return max
1363  }
1364  
1365  exports.minSatisfying = minSatisfying
1366  function minSatisfying (versions, range, options) {
1367    var min = null
1368    var minSV = null
1369    try {
1370      var rangeObj = new Range(range, options)
1371    } catch (er) {
1372      return null
1373    }
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)
1379          min = v
1380          minSV = new SemVer(min, options)
1381        }
1382      }
1383    })
1384    return min
1385  }
1386  
1387  exports.minVersion = minVersion
1388  function minVersion (range, loose) {
1389    range = new Range(range, loose)
1390  
1391    var minver = new SemVer('0.0.0')
1392    if (range.test(minver)) {
1393      return minver
1394    }
1395  
1396    minver = new SemVer('0.0.0-0')
1397    if (range.test(minver)) {
1398      return minver
1399    }
1400  
1401    minver = null
1402    for (var i = 0; i < range.set.length; ++i) {
1403      var comparators = range.set[i]
1404  
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) {
1409          case '>':
1410            if (compver.prerelease.length === 0) {
1411              compver.patch++
1412            } else {
1413              compver.prerelease.push(0)
1414            }
1415            compver.raw = compver.format()
1416            /* fallthrough */
1417          case '':
1418          case '>=':
1419            if (!minver || gt(minver, compver)) {
1420              minver = compver
1421            }
1422            break
1423          case '<':
1424          case '<=':
1425            /* Ignore maximum versions */
1426            break
1427          /* istanbul ignore next */
1428          default:
1429            throw new Error('Unexpected operation: ' + comparator.operator)
1430        }
1431      })
1432    }
1433  
1434    if (minver && range.test(minver)) {
1435      return minver
1436    }
1437  
1438    return null
1439  }
1440  
1441  exports.validRange = validRange
1442  function validRange (range, options) {
1443    try {
1444      // Return '*' instead of '' so that truthiness works.
1445      // This will throw if it's invalid anyway
1446      return new Range(range, options).range || '*'
1447    } catch (er) {
1448      return null
1449    }
1450  }
1451  
1452  // Determine if version is less than all the versions possible in the range
1453  exports.ltr = ltr
1454  function ltr (version, range, options) {
1455    return outside(version, range, '<', options)
1456  }
1457  
1458  // Determine if version is greater than all the versions possible in the range.
1459  exports.gtr = gtr
1460  function gtr (version, range, options) {
1461    return outside(version, range, '>', options)
1462  }
1463  
1464  exports.outside = outside
1465  function outside (version, range, hilo, options) {
1466    version = new SemVer(version, options)
1467    range = new Range(range, options)
1468  
1469    var gtfn, ltefn, ltfn, comp, ecomp
1470    switch (hilo) {
1471      case '>':
1472        gtfn = gt
1473        ltefn = lte
1474        ltfn = lt
1475        comp = '>'
1476        ecomp = '>='
1477        break
1478      case '<':
1479        gtfn = lt
1480        ltefn = gte
1481        ltfn = gt
1482        comp = '<'
1483        ecomp = '<='
1484        break
1485      default:
1486        throw new TypeError('Must provide a hilo val of "<" or ">"')
1487    }
1488  
1489    // If it satisifes the range it is not outside
1490    if (satisfies(version, range, options)) {
1491      return false
1492    }
1493  
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.
1496  
1497    for (var i = 0; i < range.set.length; ++i) {
1498      var comparators = range.set[i]
1499  
1500      var high = null
1501      var low = null
1502  
1503      comparators.forEach(function (comparator) {
1504        if (comparator.semver === ANY) {
1505          comparator = new Comparator('>=0.0.0')
1506        }
1507        high = high || comparator
1508        low = low || comparator
1509        if (gtfn(comparator.semver, high.semver, options)) {
1510          high = comparator
1511        } else if (ltfn(comparator.semver, low.semver, options)) {
1512          low = comparator
1513        }
1514      })
1515  
1516      // If the edge version comparator has a operator then our version
1517      // isn't outside it
1518      if (high.operator === comp || high.operator === ecomp) {
1519        return false
1520      }
1521  
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)) {
1526        return false
1527      } else if (low.operator === ecomp && ltfn(version, low.semver)) {
1528        return false
1529      }
1530    }
1531    return true
1532  }
1533  
1534  exports.prerelease = prerelease
1535  function prerelease (version, options) {
1536    var parsed = parse(version, options)
1537    return (parsed && parsed.prerelease.length) ? parsed.prerelease : null
1538  }
1539  
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)
1545  }
1546  
1547  exports.coerce = coerce
1548  function coerce (version, options) {
1549    if (version instanceof SemVer) {
1550      return version
1551    }
1552  
1553    if (typeof version === 'number') {
1554      version = String(version)
1555    }
1556  
1557    if (typeof version !== 'string') {
1558      return null
1559    }
1560  
1561    options = options || {}
1562  
1563    var match = null
1564    if (!options.rtl) {
1565      match = version.match(re[t.COERCE])
1566    } else {
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'
1570      //
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.
1575      var next
1576      while ((next = re[t.COERCERTL].exec(version)) &&
1577        (!match || match.index + match[0].length !== version.length)
1578      ) {
1579        if (!match ||
1580            next.index + next[0].length !== match.index + match[0].length) {
1581          match = next
1582        }
1583        re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length
1584      }
1585      // leave it in a clean state
1586      re[t.COERCERTL].lastIndex = -1
1587    }
1588  
1589    if (match === null) {
1590      return null
1591    }
1592  
1593    return parse(match[2] +
1594      '.' + (match[3] || '0') +
1595      '.' + (match[4] || '0'), options)
1596  }