1 /** 2 * License: <a href="http://opensource.org/licenses/MIT">MIT</a>. 3 * Authors: Dragos Carp 4 * 5 * See_Also: <a href="http://semver.org">Semantic Versioning 2.0</a>, 6 * <a href="https://github.com/isaacs/node-semver">The semantic versioner for npm</a> 7 */ 8 9 module semver; 10 11 import std.algorithm; 12 import std.range; 13 14 /** 15 * The version part of a version number. 16 */ 17 enum VersionPart 18 { 19 /** major number */ 20 MAJOR, 21 /** minor number */ 22 MINOR, 23 /** patch number */ 24 PATCH, 25 /** prerelease suffix */ 26 PRERELEASE, 27 /** build suffix */ 28 BUILD, 29 }; 30 31 /** 32 * Represent a semantic version number MAJOR[.MINOR[.PATCH]][-PRERELEASE][+BUILD]. 33 */ 34 struct SemVer 35 { 36 private uint[3] ids; 37 private string[] prerelease; 38 private string[] build; 39 40 private bool _isValid; 41 42 /** 43 * Creates and validates a version number from a string. 44 * 45 * If string format is invalid it just sets the $(D_PARAM isValid) property to $(D_KEYWORD false). 46 */ 47 this(string semVer) 48 { 49 import std.array : array; 50 import std.conv : to; 51 import std.regex : matchAll, regex; 52 53 _isValid = false; 54 if (semVer.empty) 55 return; 56 if (!semVer.skipOver('v')) 57 semVer.skipOver('='); 58 59 auto re = regex(`^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([a-zA-Z\d-.]+))?(?:\+([a-zA-Z\d-.]+))?$`); 60 auto m = semVer.matchAll(re); 61 if (m.empty) 62 return; 63 64 foreach (i, ref id; ids) 65 { 66 if (!m.captures[i+1].empty) 67 id = m.captures[i+1].to!uint; 68 } 69 70 if (!m.captures[4].empty) 71 { 72 prerelease = m.captures[4].splitter('.').array; 73 if (prerelease.any!empty) 74 return; 75 } 76 77 if (!m.captures[5].empty) 78 { 79 build = m.captures[5].splitter('.').array; 80 if (build.any!empty) 81 return; 82 } 83 84 _isValid = true; 85 } 86 87 /** 88 * Return the canonical string format. 89 */ 90 string toString() const 91 { 92 import std.string : format; 93 94 if (!_isValid) 95 return "<invalid_semver>"; 96 97 string semVer = "%(%s.%)".format(ids); 98 if (!prerelease.empty) 99 semVer ~= "-" ~ "%-(%s.%)".format(prerelease); 100 if (!build.empty) 101 semVer ~= "+" ~ "%-(%s.%)".format(build); 102 return semVer; 103 } 104 105 deprecated("Please use `isValid` instead.") 106 @property bool valid() const 107 { 108 return isValid; 109 } 110 111 /** 112 * Property that indicates whether this $(D_PSYMBOL SemVer) is valid. 113 */ 114 @property bool isValid() const 115 { 116 return _isValid; 117 } 118 119 /** 120 * Property that indicates whether this $(D_PSYMBOL SemVer) is stable. 121 */ 122 @property bool isStable() const 123 { 124 return prerelease.empty; 125 } 126 127 deprecated("Please use `increment` instead.") 128 SemVer inc(VersionPart versionPart) const 129 { 130 return increment(versionPart); 131 } 132 133 /** 134 * Increment version number. 135 */ 136 SemVer increment(VersionPart versionPart) const 137 in 138 { 139 assert(this.isValid); 140 } 141 out(result) 142 { 143 assert(result.isValid); 144 } 145 body 146 { 147 SemVer result = "0"; 148 foreach (i; VersionPart.MAJOR .. versionPart) 149 result.ids[i] = this.ids[i]; 150 if (versionPart != VersionPart.PRERELEASE) 151 result.ids[versionPart] = this.ids[versionPart]+1; 152 return result; 153 } 154 155 private SemVer appendPrerelease0() 156 { 157 if (prerelease.empty) 158 prerelease ~= "0"; 159 return this; 160 } 161 162 unittest 163 { 164 assert(SemVer("1.2.3").increment(VersionPart.MAJOR) == SemVer("2.0.0")); 165 assert(SemVer("1.2.3").increment(VersionPart.MINOR) == SemVer("1.3.0")); 166 assert(SemVer("1.2.3-alpha").increment(VersionPart.MINOR) == SemVer("1.3.0")); 167 assert(SemVer("1.2.3").increment(VersionPart.PATCH) == SemVer("1.2.4")); 168 assert(SemVer("1.2.3-alpha").increment(VersionPart.PATCH) == SemVer("1.2.4")); 169 assert(SemVer("1.2.3").increment(VersionPart.PRERELEASE) == SemVer("1.2.3")); 170 assert(SemVer("1.2.3-alpha").increment(VersionPart.PRERELEASE) == SemVer("1.2.3")); 171 } 172 173 /** 174 * Compare this $(D_PSYMBOL SemVer) with the $(D_PARAM other) $(D_PSYMBOL SemVer). 175 * 176 * Note that the build parts are considered for this operation. 177 * Please use $(D_PSYMBOL differAt) to find whether the versions differ only on the build part. 178 */ 179 int opCmp(ref const SemVer other) const 180 in 181 { 182 assert(this.isValid); 183 assert(other.isValid); 184 } 185 body 186 { 187 foreach (i; 0..ids.length) 188 { 189 if (ids[i] != other.ids[i]) 190 return ids[i] < other.ids[i] ? -1 : 1; 191 } 192 193 int compareSufix(const string[] suffix, const string[] anotherSuffix) 194 { 195 import std.conv : to; 196 import std.string : isNumeric; 197 198 if (!suffix.empty && anotherSuffix.empty) 199 return -1; 200 if (suffix.empty && !anotherSuffix.empty) 201 return 1; 202 203 foreach (a, b; lockstep(suffix, anotherSuffix)) 204 { 205 if (a.isNumeric && b.isNumeric) 206 { 207 if (a.to!uint != b.to!uint) 208 return a.to!uint < b.to!uint ? -1 : 1; 209 else 210 continue; 211 } 212 if (a != b) 213 return a < b ? -1 : 1; 214 } 215 if (suffix.length != anotherSuffix.length) 216 return suffix.length < anotherSuffix.length ? -1 : 1; 217 else 218 return 0; 219 } 220 221 auto result = compareSufix(prerelease, other.prerelease); 222 if (result != 0) 223 return result; 224 else 225 return compareSufix(build, other.build); 226 } 227 228 /// ditto 229 int opCmp(in SemVer other) const 230 { 231 return this.opCmp(other); 232 } 233 234 /** 235 * Check for equality between this $(D_PSYMBOL SemVer) and the $(D_PARAM other) $(D_PSYMBOL SemVer). 236 * 237 * Note that the build parts are considered for this operation. 238 * Please use $(D_PSYMBOL differAt) to find whether the versions differ only on the build part. 239 */ 240 bool opEquals(ref const SemVer other) const 241 { 242 return this.opCmp(other) == 0; 243 } 244 245 /// ditto 246 bool opEquals(in SemVer other) const 247 { 248 return this.opEquals(other); 249 } 250 251 /** 252 * Compare two $(B different) versions and return the parte they differ on. 253 */ 254 VersionPart differAt(ref const SemVer other) const 255 in 256 { 257 assert(this != other); 258 } 259 body 260 { 261 foreach (i; VersionPart.MAJOR .. VersionPart.PRERELEASE) 262 { 263 if (ids[i] != other.ids[i]) 264 return i; 265 } 266 267 if (prerelease != other.prerelease) 268 return VersionPart.PRERELEASE; 269 270 if (build != other.build) 271 return VersionPart.BUILD; 272 273 assert(0, "Call 'differAt' for unequal versions only"); 274 } 275 276 /// ditto 277 VersionPart differAt(in SemVer other) const 278 { 279 return this.differAt(other); 280 } 281 } 282 283 unittest 284 { 285 assert(!SemVer().isValid); 286 assert(!SemVer("1.2-.alpha.32").isValid); 287 assert(!SemVer("1.2-alpha+").isValid); 288 assert(!SemVer("1.2-alpha_").isValid); 289 assert(!SemVer("1.2+32.").isValid); 290 assert(!SemVer("1.2.5.6").isValid); 291 assert(!SemVer("").isValid); 292 assert(SemVer("1").isStable); 293 assert(SemVer("1.0").isStable); 294 assert(SemVer("1.0.0").isStable); 295 assert(SemVer("1.0+build3.").isStable); 296 assert(SemVer("1.0.0+build.5").isStable); 297 assert(!SemVer("1.0.0-alpha").isStable); 298 assert(!SemVer("1.0.0-alpha.1").isStable); 299 300 assert(SemVer("1.0.0-alpha") < SemVer("1.0.0-alpha.1")); 301 assert(SemVer("1.0.0-alpha.1") < SemVer("1.0.0-alpha.beta")); 302 assert(SemVer("1.0.0-alpha.beta") < SemVer("1.0.0-beta")); 303 assert(SemVer("1.0.0-beta") < SemVer("1.0.0-beta.2")); 304 assert(SemVer("1.0.0-beta.2") < SemVer("1.0.0-beta.11")); 305 assert(SemVer("1.0.0-beta.11") < SemVer("1.0.0-rc.1")); 306 assert(SemVer("1.0.0-rc.1") < SemVer("1.0.0")); 307 assert(SemVer("1.0.0-rc.1") > SemVer("1.0.0-rc.1+build.5")); 308 assert(SemVer("1.0.0-rc.1+build.5") == SemVer("1.0.0-rc.1+build.5")); 309 310 assert(SemVer("1.0.0").differAt(SemVer("2")) == VersionPart.MAJOR); 311 assert(SemVer("1.0.0").differAt(SemVer("1.1.1")) == VersionPart.MINOR); 312 assert(SemVer("1.0.0-rc.1").differAt(SemVer("1.0.1-rc.1")) == VersionPart.PATCH); 313 assert(SemVer("1.0.0-alpha").differAt(SemVer("1.0.0-beta")) == VersionPart.PRERELEASE); 314 assert(SemVer("1.0.0-rc.1").differAt(SemVer("1.0.0")) == VersionPart.PRERELEASE); 315 assert(SemVer("1.0.0-rc.1").differAt(SemVer("1.0.0-rc.1+build.5")) == VersionPart.BUILD); 316 } 317 318 /** 319 * Represent a semantic version range [~|~>|^|<|<=|=|>=|>]MAJOR[.MINOR[.PATCH]]. 320 */ 321 struct SemVerRange 322 { 323 private struct SimpleRange 324 { 325 string op; 326 SemVer semVer; 327 328 string toString() const 329 { 330 return op ~ semVer.toString; 331 } 332 } 333 334 private SimpleRange[][] ranges; 335 336 invariant() 337 { 338 assert(ranges.all!(r => r.all!(r => ["<", "<=", "=", ">=", ">"].canFind(r.op)))); 339 } 340 341 private bool _isValid; 342 343 /** 344 * Creates and validates a semantic version range from a string. 345 * 346 * If string format is invalid it just sets the $(D_PARAM isValid) property to $(D_KEYWORD false). 347 */ 348 this(string semVerRange) 349 { 350 import std.exception : enforce; 351 import std.regex : matchFirst, regex; 352 import std.string : format, strip, stripLeft; 353 354 _isValid = false; 355 auto re = regex(`(~|~>|\^|<|<=|=|>=|>)?[v]?(\d+|\*|X|x)(?:\.(\d+|\*|X|x))?(?:\.(\d+|\*|X|x))?([\S]*)`); 356 357 ranges = [SimpleRange[].init]; 358 359 while (!semVerRange.stripLeft.empty) 360 { 361 auto m = semVerRange.matchFirst(re); 362 if (m.empty) 363 return; 364 365 auto operator = m.captures[1]; 366 auto wildcard = wildcardAt([m.captures[2], m.captures[3], m.captures[4]]); 367 auto expanded = expand([m.captures[2], m.captures[3], m.captures[4], m.captures[5]]); 368 if (expanded.empty) 369 return; 370 371 auto semVer = SemVer(expanded); 372 if (!semVer.isValid) 373 return; 374 375 switch (m.captures.pre.strip) 376 { 377 case "": 378 break; 379 case "-": 380 if (ranges[$-1].empty || ranges[$-1][$-1].op != "=" || 381 operator != "" || wildcard != VersionPart.PRERELEASE) 382 return; 383 ranges[$-1][$-1].op = ">="; 384 operator = "<="; 385 break; 386 case "||": 387 ranges ~= SimpleRange[].init; 388 break; 389 default: 390 return; 391 } 392 393 switch (operator) 394 { 395 case "": 396 case "=": 397 final switch (wildcard) 398 { 399 case VersionPart.MAJOR: 400 assert(semVer == SemVer("0.0.0")); 401 ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0); 402 break; 403 case VersionPart.MINOR: 404 case VersionPart.PATCH: 405 ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0); 406 ranges[$-1] ~= SimpleRange("<", semVer.increment(--wildcard).appendPrerelease0); 407 break; 408 case VersionPart.PRERELEASE: 409 ranges[$-1] ~= SimpleRange("=", semVer); 410 break; 411 case VersionPart.BUILD: 412 assert(0, "Unexpected build part wildcard"); 413 } 414 break; 415 case "<": 416 ranges[$-1] ~= SimpleRange(operator, semVer.appendPrerelease0); 417 break; 418 case "<=": 419 case ">=": 420 case ">": 421 if (wildcard < VersionPart.PRERELEASE) 422 semVer.appendPrerelease0; 423 ranges[$-1] ~= SimpleRange(operator, semVer); 424 break; 425 case "~": 426 final switch (wildcard) 427 { 428 case VersionPart.MAJOR: 429 return; 430 case VersionPart.MINOR: 431 case VersionPart.PATCH: 432 --wildcard; 433 break; 434 case VersionPart.PRERELEASE: 435 --wildcard; 436 --wildcard; 437 break; 438 case VersionPart.BUILD: 439 assert(0, "Unexpected build part wildcard"); 440 } 441 ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0); 442 ranges[$-1] ~= SimpleRange("<", semVer.increment(wildcard).appendPrerelease0); 443 break; 444 case "~>": 445 final switch (wildcard) 446 { 447 case VersionPart.MAJOR: 448 return; 449 case VersionPart.MINOR: 450 --wildcard; 451 break; 452 case VersionPart.PATCH: 453 case VersionPart.PRERELEASE: 454 --wildcard; 455 --wildcard; 456 break; 457 case VersionPart.BUILD: 458 assert(0, "Unexpected build part wildcard"); 459 } 460 ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0); 461 ranges[$-1] ~= SimpleRange("<", semVer.increment(wildcard).appendPrerelease0); 462 break; 463 case "^": 464 if (wildcard == VersionPart.MAJOR || !semVer.prerelease.empty) 465 return; 466 if (semVer.ids[VersionPart.MAJOR] != 0) 467 { 468 ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0); 469 ranges[$-1] ~= SimpleRange("<", semVer.increment(VersionPart.MAJOR).appendPrerelease0); 470 } 471 else if (semVer.ids[VersionPart.MINOR] != 0) 472 { 473 ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0); 474 ranges[$-1] ~= SimpleRange("<", semVer.increment(VersionPart.MINOR).appendPrerelease0); 475 } 476 else 477 { 478 ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0); 479 ranges[$-1] ~= SimpleRange("<", semVer.increment(VersionPart.PATCH).appendPrerelease0); 480 } 481 break; 482 default: 483 enforce(false, "Unexpected operator %s".format(operator)); 484 break; 485 } 486 semVerRange = m.captures.post; 487 } 488 _isValid = true; 489 } 490 491 private static VersionPart wildcardAt(string[3] semVer) 492 { 493 foreach (i; VersionPart.MAJOR..VersionPart.PRERELEASE) 494 { 495 if (["", "*", "X", "x"].canFind(semVer[i])) 496 return i; 497 } 498 return VersionPart.PRERELEASE; 499 } 500 501 unittest 502 { 503 assert(wildcardAt(["*", "", ""]) == VersionPart.MAJOR); 504 assert(wildcardAt(["X", "", ""]) == VersionPart.MAJOR); 505 assert(wildcardAt(["1", "", ""]) == VersionPart.MINOR); 506 assert(wildcardAt(["1", "x", ""]) == VersionPart.MINOR); 507 assert(wildcardAt(["1", "2", ""]) == VersionPart.PATCH); 508 assert(wildcardAt(["1", "2", "x"]) == VersionPart.PATCH); 509 assert(wildcardAt(["1", "2", "3"]) == VersionPart.PRERELEASE); 510 } 511 512 private static string expand(string[4] semVer) 513 { 514 import std.string : format; 515 516 VersionPart wildcard = wildcardAt(semVer[0..3]); 517 if (wildcard != VersionPart.PRERELEASE) 518 { 519 if (semVer[wildcard+1..$].any!`!["", "*", "X", "x"].canFind(a)`) 520 return ""; 521 foreach (j; wildcard..VersionPart.PRERELEASE) 522 semVer[j] = "0"; 523 } 524 string result = "%-(%s.%)".format(semVer[0..3]); 525 if (!semVer[3].empty) 526 result ~= semVer[3]; 527 return result; 528 } 529 530 unittest 531 { 532 assert(expand(["*", "", "", ""]) == "0.0.0"); 533 assert(expand(["X", "", "", ""]) == "0.0.0"); 534 assert(expand(["1", "2", "3", ""]) == "1.2.3"); 535 assert(expand(["1", "2", "3", "-abc"]) == "1.2.3-abc"); 536 assert(expand(["1", "2", "", ""]) == "1.2.0"); 537 assert(expand(["1", "2", "", "-abc"]) == ""); 538 assert(expand(["1", "2", "x", ""]) == "1.2.0"); 539 assert(expand(["1", "", "", ""]) == "1.0.0"); 540 assert(expand(["1", "x", "", ""]) == "1.0.0"); 541 } 542 543 /** 544 * Return expanded string representation. 545 */ 546 string toString() const 547 { 548 import std.string : format; 549 550 if (!_isValid) 551 return "<invalid_semver_range>"; 552 553 return "%(%(%s %) || %)".format(ranges); 554 } 555 556 deprecated("Please use semver.SemVerRange.isValid instead.") 557 @property bool valid() const 558 { 559 return isValid; 560 } 561 562 /** 563 * Property that indicates whether this $(D_PSYMBOL SemVerRange) is valid. 564 */ 565 @property bool isValid() const 566 { 567 return _isValid; 568 } 569 570 private static bool simpleRangeSatisfiedBy(SimpleRange simpleRange, SemVer semVer) 571 in 572 { 573 assert(semVer.isValid); 574 assert(["<", "<=", "=", ">=", ">"].canFind(simpleRange.op)); 575 assert(simpleRange.semVer.isValid); 576 } 577 body 578 { 579 semVer.build = null; 580 581 switch (simpleRange.op) 582 { 583 case "<": 584 return semVer < simpleRange.semVer; 585 case "<=": 586 return semVer <= simpleRange.semVer; 587 case "=": 588 return semVer == simpleRange.semVer; 589 case ">=": 590 return semVer >= simpleRange.semVer; 591 case ">": 592 return semVer > simpleRange.semVer; 593 default: 594 return false; 595 } 596 } 597 598 /** 599 * Check if the $(D_PSYMBOL SemVer) $(D_PARAM semVer) satisfies this $(D_PSYMBOL SemVerRange). 600 */ 601 bool satisfiedBy(SemVer semVer) 602 in 603 { 604 assert(semVer.isValid); 605 assert(isValid); 606 } 607 body 608 { 609 return ranges.any!(r => r.all!(s => simpleRangeSatisfiedBy(s, semVer))); 610 } 611 612 } 613 614 /** 615 * Check if the $(D_PSYMBOL SemVer) $(D_PARAM semVer) satisfies $(LREF SemVerRange) $(D_PARAM semVerRange). 616 */ 617 bool satisfies(SemVer semVer, SemVerRange semVerRange) 618 { 619 return semVerRange.satisfiedBy(semVer); 620 } 621 622 /** 623 * Return the latest $(D_PSYMBOL Semver) from $(D_PARAM semVers) array that satisfies 624 * $(D_PARAM semVerRange) $(D_PSYMBOL SemVerRange). 625 */ 626 SemVer maxSatisfying(SemVer[] semVers, SemVerRange semVerRange) 627 in 628 { 629 assert(semVers.all!"a.isValid"); 630 assert(semVerRange.isValid); 631 } 632 body 633 { 634 auto found = semVers.sort!"a > b".find!(a => satisfies(a, semVerRange)); 635 return found.empty ? SemVer("invalid") : found[0]; 636 } 637 638 unittest 639 { 640 assert(!SemVerRange().isValid); 641 assert(SemVerRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3").isValid); 642 assert(!SemVerRange("blerg").isValid); 643 assert(!SemVerRange("git+https://user:password0123@github.com/foo").isValid); 644 645 assert(SemVer("1.2.3").satisfies(SemVerRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3"))); 646 647 assert(SemVer("1.2.3").satisfies(SemVerRange("1.0.0 - 2.0.0"))); 648 assert(SemVer("1.0.0").satisfies(SemVerRange("1.0.0"))); 649 assert(SemVer("1.0.0+build.5").satisfies(SemVerRange("1.0.0"))); 650 assert(SemVer("0.2.4").satisfies(SemVerRange(">=*"))); 651 assert(SemVer("1.2.3").satisfies(SemVerRange("*"))); 652 assert(SemVer("v1.2.3-foo").satisfies(SemVerRange("*"))); 653 assert(SemVer("1.0.0").satisfies(SemVerRange(">=1.0.0"))); 654 assert(SemVer("1.0.1").satisfies(SemVerRange(">=1.0.0"))); 655 assert(SemVer("1.1.0").satisfies(SemVerRange(">=1.0.0"))); 656 assert(SemVer("1.0.1").satisfies(SemVerRange(">1.0.0"))); 657 assert(SemVer("1.1.0").satisfies(SemVerRange(">1.0.0"))); 658 assert(SemVer("2.0.0").satisfies(SemVerRange("<=2.0.0"))); 659 assert(SemVer("1.9999.9999").satisfies(SemVerRange("<=2.0.0"))); 660 assert(SemVer("0.2.9").satisfies(SemVerRange("<=2.0.0"))); 661 assert(SemVer("1.9999.9999").satisfies(SemVerRange("<2.0.0"))); 662 assert(SemVer("0.2.9").satisfies(SemVerRange("<2.0.0"))); 663 assert(SemVer("1.0.0").satisfies(SemVerRange(">=1.0.0"))); 664 assert(SemVer("1.0.1").satisfies(SemVerRange(">=1.0.0"))); 665 assert(SemVer("1.1.0").satisfies(SemVerRange(">=1.0.0"))); 666 assert(SemVer("1.0.1").satisfies(SemVerRange(">1.0.0"))); 667 assert(SemVer("1.1.0").satisfies(SemVerRange(">1.0.0"))); 668 assert(SemVer("2.0.0").satisfies(SemVerRange("<=2.0.0"))); 669 assert(SemVer("1.9999.9999").satisfies(SemVerRange("<=2.0.0"))); 670 assert(SemVer("0.2.9").satisfies(SemVerRange("<=2.0.0"))); 671 assert(SemVer("1.9999.9999").satisfies(SemVerRange("<2.0.0"))); 672 assert(SemVer("0.2.9").satisfies(SemVerRange("<2.0.0"))); 673 assert(SemVer("v0.1.97").satisfies(SemVerRange(">=0.1.97"))); 674 assert(SemVer("0.1.97").satisfies(SemVerRange(">=0.1.97"))); 675 assert(SemVer("1.2.4").satisfies(SemVerRange("0.1.20 || 1.2.4"))); 676 assert(SemVer("0.0.0").satisfies(SemVerRange(">=0.2.3 || <0.0.1"))); 677 assert(SemVer("0.2.3").satisfies(SemVerRange(">=0.2.3 || <0.0.1"))); 678 assert(SemVer("0.2.4").satisfies(SemVerRange(">=0.2.3 || <0.0.1"))); 679 assert(SemVer("2.1.3").satisfies(SemVerRange("2.x.x"))); 680 assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.x"))); 681 assert(SemVer("2.1.3").satisfies(SemVerRange("1.2.x || 2.x"))); 682 assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.x || 2.x"))); 683 assert(SemVer("1.2.3").satisfies(SemVerRange("x"))); 684 assert(SemVer("2.1.3").satisfies(SemVerRange("2.*.*"))); 685 assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.*"))); 686 assert(SemVer("2.1.3").satisfies(SemVerRange("1.2.* || 2.*"))); 687 assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.* || 2.*"))); 688 assert(SemVer("1.2.3").satisfies(SemVerRange("*"))); 689 assert(SemVer("2.1.2").satisfies(SemVerRange("2"))); 690 assert(SemVer("2.3.1").satisfies(SemVerRange("2.3"))); 691 assert(SemVer("2.4.0").satisfies(SemVerRange("~2.4"))); 692 assert(SemVer("2.4.5").satisfies(SemVerRange("~2.4"))); 693 assert(SemVer("3.2.2").satisfies(SemVerRange("~>3.2.1"))); 694 assert(SemVer("1.2.3").satisfies(SemVerRange("~1"))); 695 assert(SemVer("1.2.3").satisfies(SemVerRange("~>1"))); 696 assert(SemVer("1.0.2").satisfies(SemVerRange("~1.0"))); 697 assert(SemVer("1.0.12").satisfies(SemVerRange("~1.0.3"))); 698 assert(SemVer("1.0.0").satisfies(SemVerRange(">=1"))); 699 assert(SemVer("1.1.1").satisfies(SemVerRange("<1.2"))); 700 assert(SemVer("1.1.9").satisfies(SemVerRange("<=1.2"))); 701 assert(SemVer("1.0.0-bet").satisfies(SemVerRange("1"))); 702 assert(SemVer("0.5.5").satisfies(SemVerRange("~v0.5.4-pre"))); 703 assert(SemVer("0.5.4").satisfies(SemVerRange("~v0.5.4-pre"))); 704 assert(SemVer("0.7.2").satisfies(SemVerRange("=0.7.x"))); 705 assert(SemVer("0.7.2").satisfies(SemVerRange(">=0.7.x"))); 706 assert(SemVer("0.7.0-asdf").satisfies(SemVerRange("=0.7.x"))); 707 assert(SemVer("0.7.0-asdf").satisfies(SemVerRange(">=0.7.x"))); 708 assert(SemVer("0.6.2").satisfies(SemVerRange("<=0.7.x"))); 709 assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 >=1.2.3"))); 710 assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 =1.2.3"))); 711 assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3"))); 712 assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 >=1.2.3 1.2.3"))); 713 assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3 >=1.2.3"))); 714 assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3"))); 715 assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.1 1.2.3"))); 716 assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.3 >=1.2.1"))); 717 assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.3 >=1.2.1"))); 718 assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.1 >=1.2.3"))); 719 assert(SemVer("1.2.3-beta").satisfies(SemVerRange("<=1.2.3"))); 720 assert(SemVer("1.3.0-beta").satisfies(SemVerRange(">1.2"))); 721 assert(SemVer("1.2.8").satisfies(SemVerRange(">=1.2"))); 722 assert(SemVer("1.8.1").satisfies(SemVerRange("^1.2.3"))); 723 assert(SemVer("1.2.3-beta").satisfies(SemVerRange("^1.2.3"))); 724 assert(SemVer("0.1.2").satisfies(SemVerRange("^0.1.2"))); 725 assert(SemVer("0.1.2").satisfies(SemVerRange("^0.1"))); 726 assert(SemVer("1.4.2").satisfies(SemVerRange("^1.2"))); 727 assert(SemVer("1.4.2").satisfies(SemVerRange("^1.2 ^1"))); 728 assert(SemVer("1.2.0-pre").satisfies(SemVerRange("^1.2"))); 729 assert(SemVer("1.2.3-pre").satisfies(SemVerRange("^1.2.3"))); 730 731 assert(!SemVer("2.2.3").satisfies(SemVerRange("1.0.0 - 2.0.0"))); 732 assert(!SemVer("1.0.1").satisfies(SemVerRange("1.0.0"))); 733 assert(!SemVer("0.0.0").satisfies(SemVerRange(">=1.0.0"))); 734 assert(!SemVer("0.0.1").satisfies(SemVerRange(">=1.0.0"))); 735 assert(!SemVer("0.1.0").satisfies(SemVerRange(">=1.0.0"))); 736 assert(!SemVer("0.0.1").satisfies(SemVerRange(">1.0.0"))); 737 assert(!SemVer("0.1.0").satisfies(SemVerRange(">1.0.0"))); 738 assert(!SemVer("3.0.0").satisfies(SemVerRange("<=2.0.0"))); 739 assert(!SemVer("2.9999.9999").satisfies(SemVerRange("<=2.0.0"))); 740 assert(!SemVer("2.2.9").satisfies(SemVerRange("<=2.0.0"))); 741 assert(!SemVer("2.9999.9999").satisfies(SemVerRange("<2.0.0"))); 742 assert(!SemVer("2.2.9").satisfies(SemVerRange("<2.0.0"))); 743 assert(!SemVer("v0.1.93").satisfies(SemVerRange(">=0.1.97"))); 744 assert(!SemVer("0.1.93").satisfies(SemVerRange(">=0.1.97"))); 745 assert(!SemVer("1.2.3").satisfies(SemVerRange("0.1.20 || 1.2.4"))); 746 assert(!SemVer("0.0.3").satisfies(SemVerRange(">=0.2.3 || <0.0.1"))); 747 assert(!SemVer("0.2.2").satisfies(SemVerRange(">=0.2.3 || <0.0.1"))); 748 assert(!SemVer("1.1.3").satisfies(SemVerRange("2.x.x"))); 749 assert(!SemVer("3.1.3").satisfies(SemVerRange("2.x.x"))); 750 assert(!SemVer("1.3.3").satisfies(SemVerRange("1.2.x"))); 751 assert(!SemVer("3.1.3").satisfies(SemVerRange("1.2.x || 2.x"))); 752 assert(!SemVer("1.1.3").satisfies(SemVerRange("1.2.x || 2.x"))); 753 assert(!SemVer("1.1.3").satisfies(SemVerRange("2.*.*"))); 754 assert(!SemVer("3.1.3").satisfies(SemVerRange("2.*.*"))); 755 assert(!SemVer("1.3.3").satisfies(SemVerRange("1.2.*"))); 756 assert(!SemVer("3.1.3").satisfies(SemVerRange("1.2.* || 2.*"))); 757 assert(!SemVer("1.1.3").satisfies(SemVerRange("1.2.* || 2.*"))); 758 assert(!SemVer("1.1.2").satisfies(SemVerRange("2"))); 759 assert(!SemVer("2.4.1").satisfies(SemVerRange("2.3"))); 760 assert(!SemVer("2.5.0").satisfies(SemVerRange("~2.4"))); 761 assert(!SemVer("2.3.9").satisfies(SemVerRange("~2.4"))); 762 assert(!SemVer("3.3.2").satisfies(SemVerRange("~>3.2.1"))); 763 assert(!SemVer("3.2.0").satisfies(SemVerRange("~>3.2.1"))); 764 assert(!SemVer("0.2.3").satisfies(SemVerRange("~1"))); 765 assert(!SemVer("2.2.3").satisfies(SemVerRange("~>1"))); 766 assert(!SemVer("1.1.0").satisfies(SemVerRange("~1.0"))); 767 assert(!SemVer("1.0.0").satisfies(SemVerRange("<1"))); 768 assert(!SemVer("1.1.1").satisfies(SemVerRange(">=1.2"))); 769 assert(!SemVer("1.3.0").satisfies(SemVerRange("<=1.2"))); 770 assert(!SemVer("2.0.0-beta").satisfies(SemVerRange("1"))); 771 assert(!SemVer("0.5.4-alpha").satisfies(SemVerRange("~v0.5.4-beta"))); 772 assert(!SemVer("1.0.0-beta").satisfies(SemVerRange("<1"))); 773 assert(!SemVer("0.8.2").satisfies(SemVerRange("=0.7.x"))); 774 assert(!SemVer("0.6.2").satisfies(SemVerRange(">=0.7.x"))); 775 assert(!SemVer("0.7.2").satisfies(SemVerRange("<=0.7.x"))); 776 assert(!SemVer("1.2.3-beta").satisfies(SemVerRange("<1.2.3"))); 777 assert(!SemVer("1.2.3-beta").satisfies(SemVerRange("=1.2.3"))); 778 assert(!SemVer("1.2.8").satisfies(SemVerRange(">1.3"))); 779 assert(!SemVer("2.0.0-alpha").satisfies(SemVerRange("^1.2.3"))); 780 assert(!SemVer("1.2.2").satisfies(SemVerRange("^1.2.3"))); 781 assert(!SemVer("1.1.9").satisfies(SemVerRange("^1.2"))); 782 assert(!SemVer("2.0.0-pre").satisfies(SemVerRange("^1.2.3"))); 783 784 auto semVers = [SemVer("1.1.0"), SemVer("1.0.0"), SemVer("0.8.0")]; 785 assert(semVers.maxSatisfying(SemVerRange("<=1.0.0")) == SemVer("1.0.0")); 786 assert(semVers.maxSatisfying(SemVerRange(">=1.0")) == SemVer("1.1.0")); 787 788 semVers = [SemVer("1.0.0+build.3"), SemVer("1.0.0+build.1"), SemVer("1.1.0")]; 789 assert(semVers.maxSatisfying(SemVerRange("<=1.0.0")) == SemVer("1.0.0+build.3")); 790 assert(semVers.maxSatisfying(SemVerRange(">=1.0")) == SemVer("1.1.0")); 791 }