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