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 }