Fix <= and > comparisons when compared against prerelease versions (#50915)

* Fix <= and > comparisons when compared against prerelease versions

* Improve coverage for semver
This commit is contained in:
Ron Buckton 2022-09-28 18:46:06 -04:00 committed by GitHub
parent fbfe9340a9
commit 865848fcfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 817 additions and 118 deletions

View File

@ -15,12 +15,14 @@ namespace ts {
// > alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers
// > MUST NOT include leading zeroes.
const prereleaseRegExp = /^(?:0|[1-9]\d*|[a-z-][a-z0-9-]*)(?:\.(?:0|[1-9]\d*|[a-z-][a-z0-9-]*))*$/i;
const prereleasePartRegExp = /^(?:0|[1-9]\d*|[a-z-][a-z0-9-]*)$/i;
// https://semver.org/#spec-item-10
// > Build metadata MAY be denoted by appending a plus sign and a series of dot separated
// > identifiers immediately following the patch or pre-release version. Identifiers MUST
// > comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.
const buildRegExp = /^[a-z0-9-]+(?:\.[a-z0-9-]+)*$/i;
const buildPartRegExp = /^[a-z0-9-]+$/i;
// https://semver.org/#spec-item-9
// > Numeric identifiers MUST NOT include leading zeroes.
@ -30,7 +32,7 @@ namespace ts {
* Describes a precise semantic version number, https://semver.org
*/
export class Version {
static readonly zero = new Version(0, 0, 0);
static readonly zero = new Version(0, 0, 0, ["0"]);
readonly major: number;
readonly minor: number;
@ -39,8 +41,8 @@ namespace ts {
readonly build: readonly string[];
constructor(text: string);
constructor(major: number, minor?: number, patch?: number, prerelease?: string, build?: string);
constructor(major: number | string, minor = 0, patch = 0, prerelease = "", build = "") {
constructor(major: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[]);
constructor(major: number | string, minor = 0, patch = 0, prerelease: string | readonly string[] = "", build: string | readonly string[] = "") {
if (typeof major === "string") {
const result = Debug.checkDefined(tryParseComponents(major), "Invalid version");
({ major, minor, patch, prerelease, build } = result);
@ -49,13 +51,18 @@ namespace ts {
Debug.assert(major >= 0, "Invalid argument: major");
Debug.assert(minor >= 0, "Invalid argument: minor");
Debug.assert(patch >= 0, "Invalid argument: patch");
Debug.assert(!prerelease || prereleaseRegExp.test(prerelease), "Invalid argument: prerelease");
Debug.assert(!build || buildRegExp.test(build), "Invalid argument: build");
const prereleaseArray = prerelease ? isArray(prerelease) ? prerelease : prerelease.split(".") : emptyArray;
const buildArray = build ? isArray(build) ? build : build.split(".") : emptyArray;
Debug.assert(every(prereleaseArray, s => prereleasePartRegExp.test(s)), "Invalid argument: prerelease");
Debug.assert(every(buildArray, s => buildPartRegExp.test(s)), "Invalid argument: build");
this.major = major;
this.minor = minor;
this.patch = patch;
this.prerelease = prerelease ? prerelease.split(".") : emptyArray;
this.build = build ? build.split(".") : emptyArray;
this.prerelease = prereleaseArray;
this.build = buildArray;
}
static tryParse(text: string) {
@ -96,6 +103,17 @@ namespace ts {
}
}
with(fields: { major?: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[] }) {
const {
major = this.major,
minor = this.minor,
patch = this.patch,
prerelease = this.prerelease,
build = this.build
} = fields;
return new Version(major, minor, patch, prerelease, build);
}
toString() {
let result = `${this.major}.${this.minor}.${this.patch}`;
if (some(this.prerelease)) result += `-${this.prerelease.join(".")}`;
@ -184,6 +202,10 @@ namespace ts {
return undefined;
}
/**
* Tests whether a version matches the range. This is equivalent to `satisfies(version, range, { includePrerelease: true })`.
* in `node-semver`.
*/
test(version: Version | string) {
if (typeof version === "string") version = new Version(version);
return testDisjunction(version, this._alternatives);
@ -311,20 +333,22 @@ namespace ts {
break;
case "<":
case ">=":
comparators.push(createComparator(operator, version));
comparators.push(
isWildcard(minor) || isWildcard(patch) ? createComparator(operator, version.with({ prerelease: "0" })) :
createComparator(operator, version));
break;
case "<=":
case ">":
comparators.push(
isWildcard(minor) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("major")) :
isWildcard(patch) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("minor")) :
isWildcard(minor) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("major").with({ prerelease: "0" })) :
isWildcard(patch) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("minor").with({ prerelease: "0" })) :
createComparator(operator, version));
break;
case "=":
case undefined:
if (isWildcard(minor) || isWildcard(patch)) {
comparators.push(createComparator(">=", version));
comparators.push(createComparator("<", version.increment(isWildcard(minor) ? "major" : "minor")));
comparators.push(createComparator(">=", version.with({ prerelease: "0" })));
comparators.push(createComparator("<", version.increment(isWildcard(minor) ? "major" : "minor").with({ prerelease: "0" })));
}
else {
comparators.push(createComparator("=", version));
@ -389,4 +413,4 @@ namespace ts {
function formatComparator(comparator: Comparator) {
return `${comparator.operator}${comparator.operand}`;
}
}
}

View File

@ -1,29 +1,6 @@
namespace ts {
import theory = Utils.theory;
describe("unittests:: semver", () => {
describe("VersionRange", () => {
function assertVersionRange(version: string, good: string[], bad: string[]): () => void {
return () => {
const range = VersionRange.tryParse(version)!;
assert(range);
for (const g of good) {
assert.isTrue(range.test(g), g);
}
for (const b of bad) {
assert.isFalse(range.test(b), b);
}
};
}
it("< works", assertVersionRange("<3.8.0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
it("<= works", assertVersionRange("<=3.8.0", ["3.6", "3.7", "3.8"], ["3.9", "4.0"]));
it("> works", assertVersionRange(">3.8.0", ["3.9", "4.0"], ["3.6", "3.7", "3.8"]));
it(">= works", assertVersionRange(">=3.8.0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
it("< works with prerelease", assertVersionRange("<3.8.0-0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
it("<= works with prerelease", assertVersionRange("<=3.8.0-0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
it("> works with prerelease", assertVersionRange(">3.8.0-0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
it(">= works with prerelease", assertVersionRange(">=3.8.0-0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
});
describe("Version", () => {
function assertVersion(version: Version, [major, minor, patch, prerelease, build]: [number, number, number, string[]?, string[]?]) {
assert.strictEqual(version.major, major);
@ -38,6 +15,7 @@ namespace ts {
});
it("parts", () => {
assertVersion(new Version(1, 2, 3, "pre.4", "build.5"), [1, 2, 3, ["pre", "4"], ["build", "5"]]);
assertVersion(new Version(1, 2, 3, ["pre", "4"], ["build", "5"]), [1, 2, 3, ["pre", "4"], ["build", "5"]]);
assertVersion(new Version(1, 2, 3), [1, 2, 3]);
assertVersion(new Version(1, 2), [1, 2, 0]);
assertVersion(new Version(1), [1, 0, 0]);
@ -120,129 +98,826 @@ namespace ts {
});
});
describe("VersionRange", () => {
function assertRange(rangeText: string, versionText: string, inRange = true) {
it("major wildcard types treated the same", () => {
const versionStrings = [
"",
"*",
"*.*",
"*.*.*",
"x",
"x.x",
"x.x.x",
"X",
"X.X",
"X.X.X",
];
for (let i = 0; i < versionStrings.length; i++) {
for (let j = i + 1; j < versionStrings.length; j++) {
const left = new VersionRange(versionStrings[i]);
const right = new VersionRange(versionStrings[j]);
assert.strictEqual(left.toString(), right.toString());
}
}
});
it("minor wildcard types treated the same", () => {
const versionStrings = [
"1.*",
"1.*.*",
"1.x",
"1.x.x",
"1.X",
"1.X.X",
];
for (let i = 0; i < versionStrings.length; i++) {
for (let j = i + 1; j < versionStrings.length; j++) {
const left = new VersionRange(versionStrings[i]);
const right = new VersionRange(versionStrings[j]);
assert.strictEqual(left.toString(), right.toString());
}
}
});
it("patch wildcard types treated the same", () => {
const versionStrings = [
"1.2.*",
"1.2.x",
"1.2.X",
];
for (let i = 0; i < versionStrings.length; i++) {
for (let j = i + 1; j < versionStrings.length; j++) {
const left = new VersionRange(versionStrings[i]);
const right = new VersionRange(versionStrings[j]);
assert.strictEqual(left.toString(), right.toString());
}
}
});
function assertVersionRange(version: string, good: string[], bad: string[]): () => void {
return () => {
const range = VersionRange.tryParse(version)!;
assert(range);
for (const g of good) {
assert.isTrue(range.test(g), g);
}
for (const b of bad) {
assert.isFalse(range.test(b), b);
}
};
}
it("< works", assertVersionRange("<3.8.0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
it("<= works", assertVersionRange("<=3.8.0", ["3.6", "3.7", "3.8"], ["3.9", "4.0"]));
it("> works", assertVersionRange(">3.8.0", ["3.9", "4.0"], ["3.6", "3.7", "3.8"]));
it(">= works", assertVersionRange(">=3.8.0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
it("< works with prerelease", assertVersionRange("<3.8.0-0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
it("<= works with prerelease", assertVersionRange("<=3.8.0-0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
it("> works with prerelease", assertVersionRange(">3.8.0-0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
it(">= works with prerelease", assertVersionRange(">=3.8.0-0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
function assertRange(rangeText: string, versionText: string, inRange: boolean) {
const range = new VersionRange(rangeText);
const version = new Version(versionText);
assert.strictEqual(range.test(version), inRange, `Expected version '${version}' ${inRange ? `to be` : `to not be`} in range '${rangeText}' (${range})`);
}
theory("comparators", assertRange, [
["", "1.0.0"],
["*", "1.0.0"],
["1", "1.0.0"],
// empty (matches everything)
["", "2.0.0", true],
["", "2.0.0-0", true],
["", "1.1.0", true],
["", "1.1.0-0", true],
["", "1.0.1", true],
["", "1.0.1-0", true],
["", "1.0.0", true],
["", "1.0.0-0", true],
["", "0.0.0", true],
["", "0.0.0-0", true],
// wildcard major (matches everything)
["*", "2.0.0", true],
["*", "2.0.0-0", true],
["*", "1.1.0", true],
["*", "1.1.0-0", true],
["*", "1.0.1", true],
["*", "1.0.1-0", true],
["*", "1.0.0", true],
["*", "1.0.0-0", true],
["*", "0.0.0", true],
["*", "0.0.0-0", true],
// wildcard minor
["1", "2.0.0", false],
["1.0", "1.0.0"],
["1", "2.0.0-0", false],
["1", "1.1.0", true],
["1", "1.1.0-0", true],
["1", "1.0.1", true],
["1", "1.0.1-0", true],
["1", "1.0.0", true],
["1", "1.0.0-0", true],
["1", "0.0.0", false],
["1", "0.0.0-0", false],
// wildcard patch
["1.1", "2.0.0", false],
["1.1", "2.0.0-0", false],
["1.1", "1.1.0", true],
["1.1", "1.1.0-0", true],
["1.1", "1.0.1", false],
["1.1", "1.0.1-0", false],
["1.1", "1.0.0", false],
["1.1", "1.0.0-0", false],
["1.1", "0.0.0", false],
["1.1", "0.0.0-0", false],
["1.0", "2.0.0", false],
["1.0", "2.0.0-0", false],
["1.0", "1.1.0", false],
["1.0.0", "1.0.0"],
["1.0", "1.1.0-0", false],
["1.0", "1.0.1", true],
["1.0", "1.0.1-0", true],
["1.0", "1.0.0", true],
["1.0", "1.0.0-0", true],
["1.0", "0.0.0", false],
["1.0", "0.0.0-0", false],
// exact
["1.1.0", "2.0.0", false],
["1.1.0", "2.0.0-0", false],
["1.1.0", "1.1.0", true],
["1.1.0", "1.1.0-0", false],
["1.1.0", "1.0.1", false],
["1.1.0", "1.0.1-0", false],
["1.1.0", "1.0.0-0", false],
["1.1.0", "1.0.0", false],
["1.1.0", "0.0.0", false],
["1.1.0", "0.0.0-0", false],
["1.1.0-0", "2.0.0", false],
["1.1.0-0", "2.0.0-0", false],
["1.1.0-0", "1.1.0", false],
["1.1.0-0", "1.1.0-0", true],
["1.1.0-0", "1.0.1", false],
["1.1.0-0", "1.0.1-0", false],
["1.1.0-0", "1.0.0-0", false],
["1.1.0-0", "1.0.0", false],
["1.1.0-0", "0.0.0", false],
["1.1.0-0", "0.0.0-0", false],
["1.0.1", "2.0.0", false],
["1.0.1", "2.0.0-0", false],
["1.0.1", "1.1.0", false],
["1.0.1", "1.1.0-0", false],
["1.0.1", "1.0.1", true],
["1.0.1", "1.0.1-0", false],
["1.0.1", "1.0.0-0", false],
["1.0.1", "1.0.0", false],
["1.0.1", "0.0.0", false],
["1.0.1", "0.0.0-0", false],
["1.0.1-0", "2.0.0", false],
["1.0.1-0", "2.0.0-0", false],
["1.0.1-0", "1.1.0", false],
["1.0.1-0", "1.1.0-0", false],
["1.0.1-0", "1.0.1", false],
["1.0.1-0", "1.0.1-0", true],
["1.0.1-0", "1.0.0-0", false],
["1.0.1-0", "1.0.0", false],
["1.0.1-0", "0.0.0", false],
["1.0.1-0", "0.0.0-0", false],
["1.0.0", "2.0.0", false],
["1.0.0", "2.0.0-0", false],
["1.0.0", "1.1.0", false],
["1.0.0", "1.1.0-0", false],
["1.0.0", "1.0.1", false],
["1.*", "1.0.0"],
["1.*", "2.0.0", false],
["1.x", "1.0.0"],
["1.x", "2.0.0", false],
["=1", "1.0.0"],
["=1", "1.1.0"],
["=1", "1.0.1"],
["=1.0", "1.0.0"],
["=1.0", "1.0.1"],
["=1.0.0", "1.0.0"],
["=*", "0.0.0"],
["=*", "1.0.0"],
[">1", "2"],
[">1.0", "1.1"],
[">1.0.0", "1.0.1"],
[">1.0.0", "1.0.1-pre"],
[">*", "0.0.0", false],
["1.0.0", "1.0.1-0", false],
["1.0.0", "1.0.0-0", false],
["1.0.0", "1.0.0", true],
["1.0.0", "0.0.0", false],
["1.0.0", "0.0.0-0", false],
["1.0.0-0", "2.0.0", false],
["1.0.0-0", "2.0.0-0", false],
["1.0.0-0", "1.1.0", false],
["1.0.0-0", "1.1.0-0", false],
["1.0.0-0", "1.0.1", false],
["1.0.0-0", "1.0.1-0", false],
["1.0.0-0", "1.0.0", false],
["1.0.0-0", "1.0.0-0", true],
// = wildcard major (matches everything)
["=*", "2.0.0", true],
["=*", "2.0.0-0", true],
["=*", "1.1.0", true],
["=*", "1.1.0-0", true],
["=*", "1.0.1", true],
["=*", "1.0.1-0", true],
["=*", "1.0.0", true],
["=*", "1.0.0-0", true],
["=*", "0.0.0", true],
["=*", "0.0.0-0", true],
// = wildcard minor
["=1", "2.0.0", false],
["=1", "2.0.0-0", false],
["=1", "1.1.0", true],
["=1", "1.1.0-0", true],
["=1", "1.0.1", true],
["=1", "1.0.1-0", true],
["=1", "1.0.0", true],
["=1", "1.0.0-0", true],
["=1", "0.0.0", false],
["=1", "0.0.0-0", false],
// = wildcard patch
["=1.1", "2.0.0", false],
["=1.1", "2.0.0-0", false],
["=1.1", "1.1.0", true],
["=1.1", "1.1.0-0", true],
["=1.1", "1.0.1", false],
["=1.1", "1.0.1-0", false],
["=1.1", "1.0.0", false],
["=1.1", "1.0.0-0", false],
["=1.1", "0.0.0", false],
["=1.1", "0.0.0-0", false],
["=1.0", "2.0.0", false],
["=1.0", "2.0.0-0", false],
["=1.0", "1.1.0", false],
["=1.0", "1.1.0-0", false],
["=1.0", "1.0.1", true],
["=1.0", "1.0.1-0", true],
["=1.0", "1.0.0", true],
["=1.0", "1.0.0-0", true],
["=1.0", "0.0.0", false],
["=1.0", "0.0.0-0", false],
// = exact
["=1.1.0", "2.0.0", false],
["=1.1.0", "2.0.0-0", false],
["=1.1.0", "1.1.0", true],
["=1.1.0", "1.1.0-0", false],
["=1.1.0", "1.0.1", false],
["=1.1.0", "1.0.1-0", false],
["=1.1.0", "1.0.0-0", false],
["=1.1.0", "1.0.0", false],
["=1.1.0", "0.0.0", false],
["=1.1.0", "0.0.0-0", false],
["=1.1.0-0", "2.0.0", false],
["=1.1.0-0", "2.0.0-0", false],
["=1.1.0-0", "1.1.0", false],
["=1.1.0-0", "1.1.0-0", true],
["=1.1.0-0", "1.0.1", false],
["=1.1.0-0", "1.0.1-0", false],
["=1.1.0-0", "1.0.0-0", false],
["=1.1.0-0", "1.0.0", false],
["=1.1.0-0", "0.0.0", false],
["=1.1.0-0", "0.0.0-0", false],
["=1.0.1", "2.0.0", false],
["=1.0.1", "2.0.0-0", false],
["=1.0.1", "1.1.0", false],
["=1.0.1", "1.1.0-0", false],
["=1.0.1", "1.0.1", true],
["=1.0.1", "1.0.1-0", false],
["=1.0.1", "1.0.0-0", false],
["=1.0.1", "1.0.0", false],
["=1.0.1", "0.0.0", false],
["=1.0.1", "0.0.0-0", false],
["=1.0.1-0", "2.0.0", false],
["=1.0.1-0", "2.0.0-0", false],
["=1.0.1-0", "1.1.0", false],
["=1.0.1-0", "1.1.0-0", false],
["=1.0.1-0", "1.0.1", false],
["=1.0.1-0", "1.0.1-0", true],
["=1.0.1-0", "1.0.0-0", false],
["=1.0.1-0", "1.0.0", false],
["=1.0.1-0", "0.0.0", false],
["=1.0.1-0", "0.0.0-0", false],
["=1.0.0", "2.0.0", false],
["=1.0.0", "2.0.0-0", false],
["=1.0.0", "1.1.0", false],
["=1.0.0", "1.1.0-0", false],
["=1.0.0", "1.0.1", false],
["=1.0.0", "1.0.1-0", false],
["=1.0.0", "1.0.0-0", false],
["=1.0.0", "1.0.0", true],
["=1.0.0", "0.0.0", false],
["=1.0.0", "0.0.0-0", false],
["=1.0.0-0", "2.0.0", false],
["=1.0.0-0", "2.0.0-0", false],
["=1.0.0-0", "1.1.0", false],
["=1.0.0-0", "1.1.0-0", false],
["=1.0.0-0", "1.0.1", false],
["=1.0.0-0", "1.0.1-0", false],
["=1.0.0-0", "1.0.0", false],
["=1.0.0-0", "1.0.0-0", true],
// > wildcard major (matches nothing)
[">*", "2.0.0", false],
[">*", "2.0.0-0", false],
[">*", "1.1.0", false],
[">*", "1.1.0-0", false],
[">*", "1.0.1", false],
[">*", "1.0.1-0", false],
[">*", "1.0.0", false],
[">=1", "1.0.0"],
[">=1.0", "1.0.0"],
[">=1.0.0", "1.0.0"],
[">=1.0.0", "1.0.1-pre"],
[">=*", "0.0.0"],
[">=*", "1.0.0"],
["<2", "1.0.0"],
["<2.1", "2.0.0"],
["<2.0.1", "2.0.0"],
["<2.0.0", "2.0.0-pre"],
["<*", "0.0.0", false],
[">*", "1.0.0-0", false],
[">*", "0.0.0", false],
[">*", "0.0.0-0", false],
// > wildcard minor
[">1", "2.0.0", true],
[">1", "2.0.0-0", true],
[">1", "1.1.0", false],
[">1", "1.1.0-0", false],
[">1", "1.0.1", false],
[">1", "1.0.1-0", false],
[">1", "1.0.0", false],
[">1", "1.0.0-0", false],
[">1", "0.0.0", false],
[">1", "0.0.0-0", false],
// > wildcard patch
[">1.1", "2.0.0", true],
[">1.1", "2.0.0-0", true],
[">1.1", "1.1.0", false],
[">1.1", "1.1.0-0", false],
[">1.1", "1.0.1", false],
[">1.1", "1.0.1-0", false],
[">1.1", "1.0.0", false],
[">1.1", "1.0.0-0", false],
[">1.1", "0.0.0", false],
[">1.1", "0.0.0-0", false],
[">1.0", "2.0.0", true],
[">1.0", "2.0.0-0", true],
[">1.0", "1.1.0", true],
[">1.0", "1.1.0-0", true],
[">1.0", "1.0.1", false],
[">1.0", "1.0.1-0", false],
[">1.0", "1.0.0", false],
[">1.0", "1.0.0-0", false],
[">1.0", "0.0.0", false],
[">1.0", "0.0.0-0", false],
// > exact
[">1.1.0", "2.0.0", true],
[">1.1.0", "2.0.0-0", true],
[">1.1.0", "1.1.0", false],
[">1.1.0", "1.1.0-0", false],
[">1.1.0", "1.0.1", false],
[">1.1.0", "1.0.1-0", false],
[">1.1.0", "1.0.0", false],
[">1.1.0", "1.0.0-0", false],
[">1.1.0", "0.0.0", false],
[">1.1.0", "0.0.0-0", false],
[">1.1.0-0", "2.0.0", true],
[">1.1.0-0", "2.0.0-0", true],
[">1.1.0-0", "1.1.0", true],
[">1.1.0-0", "1.1.0-0", false],
[">1.1.0-0", "1.0.1", false],
[">1.1.0-0", "1.0.1-0", false],
[">1.1.0-0", "1.0.0", false],
[">1.1.0-0", "1.0.0-0", false],
[">1.1.0-0", "0.0.0", false],
[">1.1.0-0", "0.0.0-0", false],
[">1.0.1", "2.0.0", true],
[">1.0.1", "2.0.0-0", true],
[">1.0.1", "1.1.0", true],
[">1.0.1", "1.1.0-0", true],
[">1.0.1", "1.0.1", false],
[">1.0.1", "1.0.1-0", false],
[">1.0.1", "1.0.0", false],
[">1.0.1", "1.0.0-0", false],
[">1.0.1", "0.0.0", false],
[">1.0.1", "0.0.0-0", false],
[">1.0.1-0", "2.0.0", true],
[">1.0.1-0", "2.0.0-0", true],
[">1.0.1-0", "1.1.0", true],
[">1.0.1-0", "1.1.0-0", true],
[">1.0.1-0", "1.0.1", true],
[">1.0.1-0", "1.0.1-0", false],
[">1.0.1-0", "1.0.0", false],
[">1.0.1-0", "1.0.0-0", false],
[">1.0.1-0", "0.0.0", false],
[">1.0.1-0", "0.0.0-0", false],
[">1.0.0", "2.0.0", true],
[">1.0.0", "2.0.0-0", true],
[">1.0.0", "1.1.0", true],
[">1.0.0", "1.1.0-0", true],
[">1.0.0", "1.0.1", true],
[">1.0.0", "1.0.1-0", true],
[">1.0.0", "1.0.0", false],
[">1.0.0", "1.0.0-0", false],
[">1.0.0", "0.0.0", false],
[">1.0.0", "0.0.0-0", false],
[">1.0.0-0", "2.0.0", true],
[">1.0.0-0", "2.0.0-0", true],
[">1.0.0-0", "1.1.0", true],
[">1.0.0-0", "1.1.0-0", true],
[">1.0.0-0", "1.0.1", true],
[">1.0.0-0", "1.0.1-0", true],
[">1.0.0-0", "1.0.0", true],
[">1.0.0-0", "1.0.0-0", false],
[">1.0.0-0", "0.0.0", false],
[">1.0.0-0", "0.0.0-0", false],
// >= wildcard major (matches everything)
[">=*", "2.0.0", true],
[">=*", "2.0.0-0", true],
[">=*", "1.1.0", true],
[">=*", "1.1.0-0", true],
[">=*", "1.0.1", true],
[">=*", "1.0.1-0", true],
[">=*", "1.0.0", true],
[">=*", "1.0.0-0", true],
[">=*", "0.0.0", true],
[">=*", "0.0.0-0", true],
// >= wildcard minor
[">=1", "2.0.0", true],
[">=1", "2.0.0-0", true],
[">=1", "1.1.0", true],
[">=1", "1.1.0-0", true],
[">=1", "1.0.1", true],
[">=1", "1.0.1-0", true],
[">=1", "1.0.0", true],
[">=1", "1.0.0-0", true],
[">=1", "0.0.0", false],
[">=1", "0.0.0-0", false],
// >= wildcard patch
[">=1.1", "2.0.0", true],
[">=1.1", "2.0.0-0", true],
[">=1.1", "1.1.0", true],
[">=1.1", "1.1.0-0", true],
[">=1.1", "1.0.1", false],
[">=1.1", "1.0.1-0", false],
[">=1.1", "1.0.0", false],
[">=1.1", "1.0.0-0", false],
[">=1.1", "0.0.0", false],
[">=1.1", "0.0.0-0", false],
[">=1.0", "2.0.0", true],
[">=1.0", "2.0.0-0", true],
[">=1.0", "1.1.0", true],
[">=1.0", "1.1.0-0", true],
[">=1.0", "1.0.1", true],
[">=1.0", "1.0.1-0", true],
[">=1.0", "1.0.0", true],
[">=1.0", "1.0.0-0", true],
[">=1.0", "0.0.0", false],
[">=1.0", "0.0.0-0", false],
// >= exact
[">=1.1.0", "2.0.0", true],
[">=1.1.0", "2.0.0-0", true],
[">=1.1.0", "1.1.0", true],
[">=1.1.0", "1.1.0-0", false],
[">=1.1.0", "1.0.1", false],
[">=1.1.0", "1.0.1-0", false],
[">=1.1.0", "1.0.0", false],
[">=1.1.0", "1.0.0-0", false],
[">=1.1.0", "0.0.0", false],
[">=1.1.0", "0.0.0-0", false],
[">=1.1.0-0", "2.0.0", true],
[">=1.1.0-0", "2.0.0-0", true],
[">=1.1.0-0", "1.1.0", true],
[">=1.1.0-0", "1.1.0-0", true],
[">=1.1.0-0", "1.0.1", false],
[">=1.1.0-0", "1.0.1-0", false],
[">=1.1.0-0", "1.0.0", false],
[">=1.1.0-0", "1.0.0-0", false],
[">=1.1.0-0", "0.0.0", false],
[">=1.1.0-0", "0.0.0-0", false],
[">=1.0.1", "2.0.0", true],
[">=1.0.1", "2.0.0-0", true],
[">=1.0.1", "1.1.0", true],
[">=1.0.1", "1.1.0-0", true],
[">=1.0.1", "1.0.1", true],
[">=1.0.1", "1.0.1-0", false],
[">=1.0.1", "1.0.0", false],
[">=1.0.1", "1.0.0-0", false],
[">=1.0.1", "0.0.0", false],
[">=1.0.1", "0.0.0-0", false],
[">=1.0.1-0", "2.0.0", true],
[">=1.0.1-0", "2.0.0-0", true],
[">=1.0.1-0", "1.1.0", true],
[">=1.0.1-0", "1.1.0-0", true],
[">=1.0.1-0", "1.0.1", true],
[">=1.0.1-0", "1.0.1-0", true],
[">=1.0.1-0", "1.0.0", false],
[">=1.0.1-0", "1.0.0-0", false],
[">=1.0.1-0", "0.0.0", false],
[">=1.0.1-0", "0.0.0-0", false],
[">=1.0.0", "2.0.0", true],
[">=1.0.0", "2.0.0-0", true],
[">=1.0.0", "1.1.0", true],
[">=1.0.0", "1.1.0-0", true],
[">=1.0.0", "1.0.1", true],
[">=1.0.0", "1.0.1-0", true],
[">=1.0.0", "1.0.0", true],
[">=1.0.0", "1.0.0-0", false],
[">=1.0.0", "0.0.0", false],
[">=1.0.0", "0.0.0-0", false],
[">=1.0.0-0", "2.0.0", true],
[">=1.0.0-0", "2.0.0-0", true],
[">=1.0.0-0", "1.1.0", true],
[">=1.0.0-0", "1.1.0-0", true],
[">=1.0.0-0", "1.0.1", true],
[">=1.0.0-0", "1.0.1-0", true],
[">=1.0.0-0", "1.0.0", true],
[">=1.0.0-0", "1.0.0-0", true],
[">=1.0.0-0", "0.0.0", false],
[">=1.0.0-0", "0.0.0-0", false],
// < wildcard major (matches nothing)
["<*", "2.0.0", false],
["<*", "2.0.0-0", false],
["<*", "1.1.0", false],
["<*", "1.1.0-0", false],
["<*", "1.0.1", false],
["<*", "1.0.1-0", false],
["<*", "1.0.0", false],
["<=2", "2.0.0"],
["<=2.1", "2.1.0"],
["<=2.0.1", "2.0.1"],
["<=*", "0.0.0"],
["<=*", "1.0.0"],
["<*", "1.0.0-0", false],
["<*", "0.0.0", false],
["<*", "0.0.0-0", false],
// < wildcard minor
["<1", "2.0.0", false],
["<1", "2.0.0-0", false],
["<1", "1.1.0", false],
["<1", "1.1.0-0", false],
["<1", "1.0.1", false],
["<1", "1.0.1-0", false],
["<1", "1.0.0", false],
["<1", "1.0.0-0", false],
["<1", "0.0.0", true],
["<1", "0.0.0-0", true],
// < wildcard patch
["<1.1", "2.0.0", false],
["<1.1", "2.0.0-0", false],
["<1.1", "1.1.0", false],
["<1.1", "1.1.0-0", false],
["<1.1", "1.0.1", true],
["<1.1", "1.0.1-0", true],
["<1.1", "1.0.0", true],
["<1.1", "1.0.0-0", true],
["<1.1", "0.0.0", true],
["<1.1", "0.0.0-0", true],
["<1.0", "2.0.0", false],
["<1.0", "2.0.0-0", false],
["<1.0", "1.1.0", false],
["<1.0", "1.1.0-0", false],
["<1.0", "1.0.1", false],
["<1.0", "1.0.1-0", false],
["<1.0", "1.0.0", false],
["<1.0", "1.0.0-0", false],
["<1.0", "0.0.0", true],
["<1.0", "0.0.0-0", true],
// < exact
["<1.1.0", "2.0.0", false],
["<1.1.0", "2.0.0-0", false],
["<1.1.0", "1.1.0", false],
["<1.1.0", "1.1.0-0", true],
["<1.1.0", "1.0.1", true],
["<1.1.0", "1.0.1-0", true],
["<1.1.0", "1.0.0", true],
["<1.1.0", "1.0.0-0", true],
["<1.1.0", "0.0.0", true],
["<1.1.0", "0.0.0-0", true],
["<1.1.0-0", "2.0.0", false],
["<1.1.0-0", "2.0.0-0", false],
["<1.1.0-0", "1.1.0", false],
["<1.1.0-0", "1.1.0-0", false],
["<1.1.0-0", "1.0.1", true],
["<1.1.0-0", "1.0.1-0", true],
["<1.1.0-0", "1.0.0", true],
["<1.1.0-0", "1.0.0-0", true],
["<1.1.0-0", "0.0.0", true],
["<1.1.0-0", "0.0.0-0", true],
["<1.0.1", "2.0.0", false],
["<1.0.1", "2.0.0-0", false],
["<1.0.1", "1.1.0", false],
["<1.0.1", "1.1.0-0", false],
["<1.0.1", "1.0.1", false],
["<1.0.1", "1.0.1-0", true],
["<1.0.1", "1.0.0", true],
["<1.0.1", "1.0.0-0", true],
["<1.0.1", "0.0.0", true],
["<1.0.1", "0.0.0-0", true],
["<1.0.1-0", "2.0.0", false],
["<1.0.1-0", "2.0.0-0", false],
["<1.0.1-0", "1.1.0", false],
["<1.0.1-0", "1.1.0-0", false],
["<1.0.1-0", "1.0.1", false],
["<1.0.1-0", "1.0.1-0", false],
["<1.0.1-0", "1.0.0", true],
["<1.0.1-0", "1.0.0-0", true],
["<1.0.1-0", "0.0.0", true],
["<1.0.1-0", "0.0.0-0", true],
["<1.0.0", "2.0.0", false],
["<1.0.0", "2.0.0-0", false],
["<1.0.0", "1.1.0", false],
["<1.0.0", "1.1.0-0", false],
["<1.0.0", "1.0.1", false],
["<1.0.0", "1.0.1-0", false],
["<1.0.0", "1.0.0", false],
["<1.0.0", "1.0.0-0", true],
["<1.0.0", "0.0.0", true],
["<1.0.0", "0.0.0-0", true],
["<1.0.0-0", "2.0.0", false],
["<1.0.0-0", "2.0.0-0", false],
["<1.0.0-0", "1.1.0", false],
["<1.0.0-0", "1.1.0-0", false],
["<1.0.0-0", "1.0.1", false],
["<1.0.0-0", "1.0.1-0", false],
["<1.0.0-0", "1.0.0", false],
["<1.0.0-0", "1.0.0-0", false],
["<1.0.0-0", "0.0.0", true],
["<1.0.0-0", "0.0.0-0", true],
// <= wildcard major (matches everything)
["<=*", "2.0.0", true],
["<=*", "2.0.0-0", true],
["<=*", "1.1.0", true],
["<=*", "1.1.0-0", true],
["<=*", "1.0.1", true],
["<=*", "1.0.1-0", true],
["<=*", "1.0.0", true],
["<=*", "1.0.0-0", true],
["<=*", "0.0.0", true],
["<=*", "0.0.0-0", true],
// <= wildcard minor
["<=1", "2.0.0", false],
["<=1", "2.0.0-0", false],
["<=1", "1.1.0", true],
["<=1", "1.1.0-0", true],
["<=1", "1.0.1", true],
["<=1", "1.0.1-0", true],
["<=1", "1.0.0", true],
["<=1", "1.0.0-0", true],
["<=1", "0.0.0", true],
["<=1", "0.0.0-0", true],
// <= wildcard patch
["<=1.1", "2.0.0", false],
["<=1.1", "2.0.0-0", false],
["<=1.1", "1.1.0", true],
["<=1.1", "1.1.0-0", true],
["<=1.1", "1.0.1", true],
["<=1.1", "1.0.1-0", true],
["<=1.1", "1.0.0", true],
["<=1.1", "1.0.0-0", true],
["<=1.1", "0.0.0", true],
["<=1.1", "0.0.0-0", true],
["<=1.0", "2.0.0", false],
["<=1.0", "2.0.0-0", false],
["<=1.0", "1.1.0", false],
["<=1.0", "1.1.0-0", false],
["<=1.0", "1.0.1", true],
["<=1.0", "1.0.1-0", true],
["<=1.0", "1.0.0", true],
["<=1.0", "1.0.0-0", true],
["<=1.0", "0.0.0", true],
["<=1.0", "0.0.0-0", true],
// <= exact
["<=1.1.0", "2.0.0", false],
["<=1.1.0", "2.0.0-0", false],
["<=1.1.0", "1.1.0", true],
["<=1.1.0", "1.1.0-0", true],
["<=1.1.0", "1.0.1", true],
["<=1.1.0", "1.0.1-0", true],
["<=1.1.0", "1.0.0", true],
["<=1.1.0", "1.0.0-0", true],
["<=1.1.0", "0.0.0", true],
["<=1.1.0", "0.0.0-0", true],
["<=1.1.0-0", "2.0.0", false],
["<=1.1.0-0", "2.0.0-0", false],
["<=1.1.0-0", "1.1.0", false],
["<=1.1.0-0", "1.1.0-0", true],
["<=1.1.0-0", "1.0.1", true],
["<=1.1.0-0", "1.0.1-0", true],
["<=1.1.0-0", "1.0.0", true],
["<=1.1.0-0", "1.0.0-0", true],
["<=1.1.0-0", "0.0.0", true],
["<=1.1.0-0", "0.0.0-0", true],
["<=1.0.1", "2.0.0", false],
["<=1.0.1", "2.0.0-0", false],
["<=1.0.1", "1.1.0", false],
["<=1.0.1", "1.1.0-0", false],
["<=1.0.1", "1.0.1", true],
["<=1.0.1", "1.0.1-0", true],
["<=1.0.1", "1.0.0", true],
["<=1.0.1", "1.0.0-0", true],
["<=1.0.1", "0.0.0", true],
["<=1.0.1", "0.0.0-0", true],
["<=1.0.1-0", "2.0.0", false],
["<=1.0.1-0", "2.0.0-0", false],
["<=1.0.1-0", "1.1.0", false],
["<=1.0.1-0", "1.1.0-0", false],
["<=1.0.1-0", "1.0.1", false],
["<=1.0.1-0", "1.0.1-0", true],
["<=1.0.1-0", "1.0.0", true],
["<=1.0.1-0", "1.0.0-0", true],
["<=1.0.1-0", "0.0.0", true],
["<=1.0.1-0", "0.0.0-0", true],
["<=1.0.0", "2.0.0", false],
["<=1.0.0", "2.0.0-0", false],
["<=1.0.0", "1.1.0", false],
["<=1.0.0", "1.1.0-0", false],
["<=1.0.0", "1.0.1", false],
["<=1.0.0", "1.0.1-0", false],
["<=1.0.0", "1.0.0", true],
["<=1.0.0", "1.0.0-0", true],
["<=1.0.0", "0.0.0", true],
["<=1.0.0", "0.0.0-0", true],
["<=1.0.0-0", "2.0.0", false],
["<=1.0.0-0", "2.0.0-0", false],
["<=1.0.0-0", "1.1.0", false],
["<=1.0.0-0", "1.1.0-0", false],
["<=1.0.0-0", "1.0.1", false],
["<=1.0.0-0", "1.0.1-0", false],
["<=1.0.0-0", "1.0.0", false],
["<=1.0.0-0", "1.0.0-0", true],
["<=1.0.0-0", "0.0.0", true],
["<=1.0.0-0", "0.0.0-0", true],
// https://github.com/microsoft/TypeScript/issues/50909
[">4.8", "4.9.0-beta", true],
[">=4.9", "4.9.0-beta", true],
["<4.9", "4.9.0-beta", false],
["<=4.8", "4.9.0-beta", false],
]);
theory("conjunctions", assertRange, [
[">1.0.0 <2.0.0", "1.0.1"],
[">1.0.0 <2.0.0", "1.0.1", true],
[">1.0.0 <2.0.0", "2.0.0", false],
[">1.0.0 <2.0.0", "1.0.0", false],
[">1 >2", "3.0.0"],
[">1 >2", "3.0.0", true],
]);
theory("disjunctions", assertRange, [
[">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "1.0.0"],
[">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "1.0.0", true],
[">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "2.0.0", false],
[">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "3.0.0"],
[">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "3.0.0", true],
]);
theory("hyphen", assertRange, [
["1.0.0 - 2.0.0", "1.0.0"],
["1.0.0 - 2.0.0", "2.0.0"],
["1.0.0 - 2.0.0", "1.0.0", true],
["1.0.0 - 2.0.0", "2.0.0", true],
["1.0.0 - 2.0.0", "3.0.0", false],
]);
theory("tilde", assertRange, [
["~0", "0.0.0"],
["~0", "0.1.0"],
["~0", "0.1.2"],
["~0", "0.1.9"],
["~0", "0.0.0", true],
["~0", "0.1.0", true],
["~0", "0.1.2", true],
["~0", "0.1.9", true],
["~0", "1.0.0", false],
["~0.1", "0.1.0"],
["~0.1", "0.1.2"],
["~0.1", "0.1.9"],
["~0.1", "0.1.0", true],
["~0.1", "0.1.2", true],
["~0.1", "0.1.9", true],
["~0.1", "0.2.0", false],
["~0.1.2", "0.1.2"],
["~0.1.2", "0.1.9"],
["~0.1.2", "0.1.2", true],
["~0.1.2", "0.1.9", true],
["~0.1.2", "0.2.0", false],
["~1", "1.0.0"],
["~1", "1.2.0"],
["~1", "1.2.3"],
["~1", "1.2.0"],
["~1", "1.2.3"],
["~1", "1.0.0", true],
["~1", "1.2.0", true],
["~1", "1.2.3", true],
["~1", "1.2.0", true],
["~1", "1.2.3", true],
["~1", "0.0.0", false],
["~1", "2.0.0", false],
["~1.2", "1.2.0"],
["~1.2", "1.2.3"],
["~1.2", "1.2.0", true],
["~1.2", "1.2.3", true],
["~1.2", "1.1.0", false],
["~1.2", "1.3.0", false],
["~1.2.3", "1.2.3"],
["~1.2.3", "1.2.9"],
["~1.2.3", "1.2.3", true],
["~1.2.3", "1.2.9", true],
["~1.2.3", "1.1.0", false],
["~1.2.3", "1.3.0", false],
]);
theory("caret", assertRange, [
["^0", "0.0.0"],
["^0", "0.1.0"],
["^0", "0.9.0"],
["^0", "0.1.2"],
["^0", "0.1.9"],
["^0", "0.0.0", true],
["^0", "0.1.0", true],
["^0", "0.9.0", true],
["^0", "0.1.2", true],
["^0", "0.1.9", true],
["^0", "1.0.0", false],
["^0.1", "0.1.0"],
["^0.1", "0.1.2"],
["^0.1", "0.1.9"],
["^0.1.2", "0.1.2"],
["^0.1.2", "0.1.9"],
["^0.1", "0.1.0", true],
["^0.1", "0.1.2", true],
["^0.1", "0.1.9", true],
["^0.1.2", "0.1.2", true],
["^0.1.2", "0.1.9", true],
["^0.1.2", "0.0.0", false],
["^0.1.2", "0.2.0", false],
["^0.1.2", "1.0.0", false],
["^1", "1.0.0"],
["^1", "1.2.0"],
["^1", "1.2.3"],
["^1", "1.9.0"],
["^1", "1.0.0", true],
["^1", "1.2.0", true],
["^1", "1.2.3", true],
["^1", "1.9.0", true],
["^1", "0.0.0", false],
["^1", "2.0.0", false],
["^1.2", "1.2.0"],
["^1.2", "1.2.3"],
["^1.2", "1.9.0"],
["^1.2", "1.2.0", true],
["^1.2", "1.2.3", true],
["^1.2", "1.9.0", true],
["^1.2", "1.1.0", false],
["^1.2", "2.0.0", false],
["^1.2.3", "1.2.3"],
["^1.2.3", "1.9.0"],
["^1.2.3", "1.2.3", true],
["^1.2.3", "1.9.0", true],
["^1.2.3", "1.2.2", false],
["^1.2.3", "2.0.0", false],
]);