2020-11-12 22:32:53 +00:00
|
|
|
import { Version } from "./version";
|
|
|
|
|
2020-11-13 22:07:41 +00:00
|
|
|
/**
|
|
|
|
* A requirement is a comparator (such as ">" or "=" or "")
|
|
|
|
* and a version to compare against.
|
|
|
|
*/
|
2020-11-12 22:32:53 +00:00
|
|
|
interface Requirement {
|
2020-11-13 22:07:41 +00:00
|
|
|
/**
|
|
|
|
* A comparator is the operation to use with this requirement.
|
|
|
|
*
|
|
|
|
* Valid options are as follows:
|
|
|
|
*
|
|
|
|
* - `""` or `"="`: Precisely this version
|
|
|
|
* - `">`": A version newer than this one
|
|
|
|
* - `">`=": A version newer or equal to this one
|
|
|
|
* - `"<"`: A version older than this one
|
|
|
|
* - `"<="`: A version older or equal to this one
|
|
|
|
* - `"^"`: A version that is compatible with this one
|
|
|
|
*/
|
2020-11-12 22:32:53 +00:00
|
|
|
comparator: string;
|
2020-11-13 22:07:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The version to perform the test against.
|
|
|
|
*/
|
2020-11-12 22:32:53 +00:00
|
|
|
version: Version;
|
|
|
|
}
|
2019-10-20 19:13:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents a set of version requirements.
|
|
|
|
*/
|
2020-11-12 22:32:53 +00:00
|
|
|
export class VersionRange {
|
2020-11-13 22:07:41 +00:00
|
|
|
/**
|
|
|
|
* The list of requirements used by this version range.
|
|
|
|
*
|
|
|
|
* This is a disjunctive normal form - that is, an OR of ANDs.
|
|
|
|
*
|
|
|
|
* If all requirements of a single inner array match, the range is
|
|
|
|
* considered successful.
|
|
|
|
*/
|
2020-11-12 23:47:40 +00:00
|
|
|
readonly requirements: Requirement[][];
|
2020-11-12 22:32:53 +00:00
|
|
|
|
2020-11-13 22:07:41 +00:00
|
|
|
/**
|
|
|
|
* Constructs a range of versions as specified by the given requirements.
|
|
|
|
*
|
|
|
|
* If you wish to construct this object from a string representation,
|
2020-11-13 22:20:57 +00:00
|
|
|
* then use [[fromRequirementString]].
|
2020-11-13 22:07:41 +00:00
|
|
|
*
|
|
|
|
* @param requirements Requirements to set this range by
|
|
|
|
*/
|
2020-11-12 22:32:53 +00:00
|
|
|
constructor(requirements: Requirement[][]) {
|
2019-10-20 19:13:00 +00:00
|
|
|
this.requirements = requirements;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine if a given version satisfies this range.
|
2020-05-12 22:24:41 +00:00
|
|
|
*
|
2020-11-13 22:07:41 +00:00
|
|
|
* @param fver A version object to test against.
|
|
|
|
* @return Whether or not the given version matches this range
|
2019-10-20 19:13:00 +00:00
|
|
|
*/
|
2020-11-13 22:20:07 +00:00
|
|
|
satisfiedBy(fver: Version): boolean {
|
2019-10-20 19:13:00 +00:00
|
|
|
for (let i = 0; i < this.requirements.length; i += 1) {
|
|
|
|
let matches = true;
|
|
|
|
|
2020-05-22 09:43:18 +00:00
|
|
|
for (let j = 0; j < this.requirements[i].length; j += 1) {
|
2020-11-12 22:32:53 +00:00
|
|
|
const comparator = this.requirements[i][j].comparator;
|
|
|
|
const version = this.requirements[i][j].version;
|
2019-10-20 19:13:00 +00:00
|
|
|
|
2020-05-12 22:24:41 +00:00
|
|
|
matches =
|
2020-11-13 21:52:30 +00:00
|
|
|
matches && version.isStableOrCompatiblePrerelease(fver);
|
2019-10-20 19:13:00 +00:00
|
|
|
|
|
|
|
if (comparator === "" || comparator === "=") {
|
2020-11-13 21:51:53 +00:00
|
|
|
matches = matches && version.isEqual(fver);
|
2019-10-20 19:13:00 +00:00
|
|
|
} else if (comparator === ">") {
|
2020-11-13 21:51:18 +00:00
|
|
|
matches = matches && fver.hasPrecedenceOver(version);
|
2019-10-20 19:13:00 +00:00
|
|
|
} else if (comparator === ">=") {
|
2020-05-12 22:24:41 +00:00
|
|
|
matches =
|
|
|
|
matches &&
|
2020-11-13 21:51:18 +00:00
|
|
|
(fver.hasPrecedenceOver(version) ||
|
2020-11-13 21:51:53 +00:00
|
|
|
version.isEqual(fver));
|
2019-10-20 19:13:00 +00:00
|
|
|
} else if (comparator === "<") {
|
2020-11-13 21:51:18 +00:00
|
|
|
matches = matches && version.hasPrecedenceOver(fver);
|
2019-10-20 19:13:00 +00:00
|
|
|
} else if (comparator === "<=") {
|
2020-05-12 22:24:41 +00:00
|
|
|
matches =
|
|
|
|
matches &&
|
2020-11-13 21:51:18 +00:00
|
|
|
(version.hasPrecedenceOver(fver) ||
|
2020-11-13 21:51:53 +00:00
|
|
|
version.isEqual(fver));
|
2019-10-20 19:13:00 +00:00
|
|
|
} else if (comparator === "^") {
|
2020-11-13 21:50:45 +00:00
|
|
|
matches = matches && version.isCompatibleWith(fver);
|
2019-10-20 19:13:00 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-22 09:43:18 +00:00
|
|
|
|
|
|
|
if (matches) {
|
|
|
|
return true;
|
|
|
|
}
|
2019-10-20 19:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a requirement string into a version range.
|
2020-05-12 22:24:41 +00:00
|
|
|
*
|
2020-11-13 22:07:41 +00:00
|
|
|
* @param requirement The version requirements, consisting of a
|
2019-10-20 19:13:00 +00:00
|
|
|
* series of space-separated strings, each one being a semver version
|
2020-11-13 22:07:41 +00:00
|
|
|
* optionally prefixed by a comparator or a separator.
|
|
|
|
*
|
|
|
|
* Valid comparators are:
|
|
|
|
* - `""` or `"="`: Precisely this version
|
|
|
|
* - `">`": A version newer than this one
|
|
|
|
* - `">`=": A version newer or equal to this one
|
|
|
|
* - `"<"`: A version older than this one
|
|
|
|
* - `"<="`: A version older or equal to this one
|
|
|
|
* - `"^"`: A version that is compatible with this one
|
|
|
|
*
|
|
|
|
* A separator is `"||`" which splits the requirement string into
|
|
|
|
* left OR right.
|
|
|
|
*
|
|
|
|
* @return A version range object.
|
2019-10-20 19:13:00 +00:00
|
|
|
*/
|
2020-11-13 22:20:57 +00:00
|
|
|
static fromRequirementString(requirement: string): VersionRange {
|
2020-11-12 22:32:53 +00:00
|
|
|
const components = requirement.split(" ");
|
|
|
|
let requirement_set: Requirement[] = [];
|
|
|
|
const requirements: Requirement[][] = [];
|
2019-10-20 19:13:00 +00:00
|
|
|
|
|
|
|
for (let i = 0; i < components.length; i += 1) {
|
|
|
|
if (components[i] === "||") {
|
|
|
|
if (requirement_set.length > 0) {
|
|
|
|
requirements.push(requirement_set);
|
|
|
|
requirement_set = [];
|
|
|
|
}
|
2020-05-22 09:43:18 +00:00
|
|
|
} else if (components[i].length > 0) {
|
2020-11-12 22:32:53 +00:00
|
|
|
const match = /[0-9]/.exec(components[i]);
|
|
|
|
if (match) {
|
|
|
|
const comparator = components[i]
|
|
|
|
.slice(0, match.index)
|
|
|
|
.trim();
|
2020-11-13 21:49:38 +00:00
|
|
|
const version = Version.fromSemver(
|
2020-11-12 22:32:53 +00:00
|
|
|
components[i].slice(match.index).trim()
|
|
|
|
);
|
2019-10-20 19:13:00 +00:00
|
|
|
|
2020-11-12 22:32:53 +00:00
|
|
|
requirement_set.push({ comparator, version });
|
|
|
|
}
|
2019-10-20 19:13:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (requirement_set.length > 0) {
|
|
|
|
requirements.push(requirement_set);
|
|
|
|
}
|
2019-11-17 20:14:24 +00:00
|
|
|
|
2020-05-22 09:43:18 +00:00
|
|
|
return new VersionRange(requirements);
|
2019-10-20 19:13:00 +00:00
|
|
|
}
|
2020-11-12 22:32:53 +00:00
|
|
|
}
|