forked from public/fvtt-cthulhu-eternal
393 lines
12 KiB
JavaScript
393 lines
12 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const shortSemverRegEx = /^([~\^])?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?$/;
|
||
|
const semverRegEx = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\da-z-]+(?:\.[\da-z-]+)*))?(\+[\da-z-]+)?$/i;
|
||
|
exports.semverRegEx = semverRegEx;
|
||
|
exports.shortSemverRegEx = shortSemverRegEx;
|
||
|
|
||
|
const MAJOR = Symbol('major');
|
||
|
const MINOR = Symbol('minor');
|
||
|
const PATCH = Symbol('patch');
|
||
|
const PRE = Symbol('pre');
|
||
|
const BUILD = Symbol('build');
|
||
|
const TAG = Symbol('tag');
|
||
|
|
||
|
let numRegEx = /^\d+$/;
|
||
|
class Semver {
|
||
|
constructor (version) {
|
||
|
let semver = version.match(semverRegEx);
|
||
|
if (!semver) {
|
||
|
this[TAG] = version;
|
||
|
return;
|
||
|
}
|
||
|
this[MAJOR] = parseInt(semver[1], 10);
|
||
|
this[MINOR] = parseInt(semver[2], 10);
|
||
|
this[PATCH] = parseInt(semver[3], 10);
|
||
|
this[PRE] = semver[4] && semver[4].split('.');
|
||
|
this[BUILD] = semver[5];
|
||
|
}
|
||
|
get major () {
|
||
|
return this[MAJOR];
|
||
|
}
|
||
|
get minor () {
|
||
|
return this[MINOR];
|
||
|
}
|
||
|
get patch () {
|
||
|
return this[PATCH];
|
||
|
}
|
||
|
get pre () {
|
||
|
return this[PRE];
|
||
|
}
|
||
|
get build () {
|
||
|
return this[BUILD];
|
||
|
}
|
||
|
get tag () {
|
||
|
return this[TAG];
|
||
|
}
|
||
|
gt (version) {
|
||
|
return Semver.compare(this, version) === 1;
|
||
|
}
|
||
|
lt (version) {
|
||
|
return Semver.compare(this, version) === -1;
|
||
|
}
|
||
|
eq (version) {
|
||
|
if (!(version instanceof Semver))
|
||
|
version = new Semver(version);
|
||
|
|
||
|
if (this[TAG] && version[TAG])
|
||
|
return this[TAG] === version[TAG];
|
||
|
if (this[TAG] || version[TAG])
|
||
|
return false;
|
||
|
if (this[MAJOR] !== version[MAJOR])
|
||
|
return false;
|
||
|
if (this[MINOR] !== version[MINOR])
|
||
|
return false;
|
||
|
if (this[PATCH] !== version[PATCH])
|
||
|
return false;
|
||
|
if (this[PRE] === undefined && version[PRE] === undefined)
|
||
|
return true;
|
||
|
if (this[PRE] === undefined || version[PRE] === undefined)
|
||
|
return false;
|
||
|
if (this[PRE].length !== version[PRE].length)
|
||
|
return false;
|
||
|
for (let i = 0; i < this[PRE].length; i++) {
|
||
|
if (this[PRE][i] !== version[PRE][i])
|
||
|
return false;
|
||
|
}
|
||
|
return this[BUILD] === version[BUILD];
|
||
|
}
|
||
|
matches (range, unstable = false) {
|
||
|
if (!(range instanceof SemverRange))
|
||
|
range = new SemverRange(range);
|
||
|
return range.has(this, unstable);
|
||
|
}
|
||
|
toString () {
|
||
|
if (this[TAG])
|
||
|
return this[TAG];
|
||
|
return this[MAJOR] + '.' + this[MINOR] + '.' + this[PATCH] + (this[PRE] ? '-' + this[PRE].join('.') : '') + (this[BUILD] ? this[BUILD] : '');
|
||
|
}
|
||
|
toJSON() {
|
||
|
return this.toString();
|
||
|
}
|
||
|
static isValid (version) {
|
||
|
let semver = version.match(semverRegEx);
|
||
|
return semver && semver[2] !== undefined && semver[3] !== undefined;
|
||
|
}
|
||
|
static compare (v1, v2) {
|
||
|
if (!(v1 instanceof Semver))
|
||
|
v1 = new Semver(v1);
|
||
|
if (!(v2 instanceof Semver))
|
||
|
v2 = new Semver(v2);
|
||
|
|
||
|
// not semvers - tags have equal precedence
|
||
|
if (v1[TAG] && v2[TAG])
|
||
|
return 0;
|
||
|
// semver beats tag version
|
||
|
if (v1[TAG])
|
||
|
return -1;
|
||
|
if (v2[TAG])
|
||
|
return 1;
|
||
|
// compare version numbers
|
||
|
if (v1[MAJOR] !== v2[MAJOR])
|
||
|
return v1[MAJOR] > v2[MAJOR] ? 1 : -1;
|
||
|
if (v1[MINOR] !== v2[MINOR])
|
||
|
return v1[MINOR] > v2[MINOR] ? 1 : -1;
|
||
|
if (v1[PATCH] !== v2[PATCH])
|
||
|
return v1[PATCH] > v2[PATCH] ? 1 : -1;
|
||
|
if (!v1[PRE] && !v2[PRE])
|
||
|
return 0;
|
||
|
if (!v1[PRE])
|
||
|
return 1;
|
||
|
if (!v2[PRE])
|
||
|
return -1;
|
||
|
// prerelease comparison
|
||
|
return prereleaseCompare(v1[PRE], v2[PRE]);
|
||
|
}
|
||
|
}
|
||
|
exports.Semver = Semver;
|
||
|
|
||
|
function prereleaseCompare (v1Pre, v2Pre) {
|
||
|
for (let i = 0, l = Math.min(v1Pre.length, v2Pre.length); i < l; i++) {
|
||
|
if (v1Pre[i] !== v2Pre[i]) {
|
||
|
let isNum1 = v1Pre[i].match(numRegEx);
|
||
|
let isNum2 = v2Pre[i].match(numRegEx);
|
||
|
// numeric has lower precedence
|
||
|
if (isNum1 && !isNum2)
|
||
|
return -1;
|
||
|
if (isNum2 && !isNum1)
|
||
|
return 1;
|
||
|
// compare parts
|
||
|
if (isNum1 && isNum2)
|
||
|
return parseInt(v1Pre[i], 10) > parseInt(v2Pre[i], 10) ? 1 : -1;
|
||
|
else
|
||
|
return v1Pre[i] > v2Pre[i] ? 1 : -1;
|
||
|
}
|
||
|
}
|
||
|
if (v1Pre.length === v2Pre.length)
|
||
|
return 0;
|
||
|
// more pre-release fields win if equal
|
||
|
return v1Pre.length > v2Pre.length ? 1 : -1;
|
||
|
|
||
|
}
|
||
|
|
||
|
const WILDCARD_RANGE = 0;
|
||
|
const MAJOR_RANGE = 1;
|
||
|
const STABLE_RANGE = 2;
|
||
|
const EXACT_RANGE = 3;
|
||
|
|
||
|
const TYPE = Symbol('type');
|
||
|
const VERSION = Symbol('version');
|
||
|
|
||
|
class SemverRange {
|
||
|
constructor (versionRange) {
|
||
|
if (versionRange === '*' || versionRange === '') {
|
||
|
this[TYPE] = WILDCARD_RANGE;
|
||
|
return;
|
||
|
}
|
||
|
let shortSemver = versionRange.match(shortSemverRegEx);
|
||
|
if (shortSemver) {
|
||
|
if (shortSemver[1])
|
||
|
versionRange = versionRange.substr(1);
|
||
|
if (shortSemver[3] === undefined) {
|
||
|
// ^, ~ mean the same thing for a single major
|
||
|
this[VERSION] = new Semver(versionRange + '.0.0');
|
||
|
this[TYPE] = MAJOR_RANGE;
|
||
|
}
|
||
|
else {
|
||
|
this[VERSION] = new Semver(versionRange + '.0');
|
||
|
// ^ only becomes major range for major > 0
|
||
|
if (shortSemver[1] === '^' && shortSemver[2] !== '0')
|
||
|
this[TYPE] = MAJOR_RANGE;
|
||
|
else
|
||
|
this[TYPE] = STABLE_RANGE;
|
||
|
}
|
||
|
// empty pre array === support prerelease ranges
|
||
|
this[VERSION][PRE] = this[VERSION][PRE] || [];
|
||
|
}
|
||
|
// forces hat on 0.x versions
|
||
|
else if (versionRange.startsWith('^^')) {
|
||
|
this[VERSION] = new Semver(versionRange.substr(2));
|
||
|
this[TYPE] = MAJOR_RANGE;
|
||
|
}
|
||
|
else if (versionRange[0] === '^') {
|
||
|
this[VERSION] = new Semver(versionRange.substr(1));
|
||
|
if (this[VERSION][MAJOR] === 0) {
|
||
|
if (this[VERSION][MINOR] === 0)
|
||
|
this[TYPE] = EXACT_RANGE;
|
||
|
else
|
||
|
this[TYPE] = STABLE_RANGE;
|
||
|
}
|
||
|
else {
|
||
|
this[TYPE] = MAJOR_RANGE;
|
||
|
}
|
||
|
}
|
||
|
else if (versionRange[0] === '~') {
|
||
|
this[VERSION] = new Semver(versionRange.substr(1));
|
||
|
this[TYPE] = STABLE_RANGE;
|
||
|
}
|
||
|
else {
|
||
|
this[VERSION] = new Semver(versionRange);
|
||
|
this[TYPE] = EXACT_RANGE;
|
||
|
}
|
||
|
if (this[VERSION][TAG] && this[TYPE] !== EXACT_RANGE)
|
||
|
this[TYPE] = EXACT_RANGE;
|
||
|
}
|
||
|
get isExact () {
|
||
|
return this[TYPE] === EXACT_RANGE;
|
||
|
}
|
||
|
get isExactSemver () {
|
||
|
return this[TYPE] === EXACT_RANGE && this.version[TAG] === undefined;
|
||
|
}
|
||
|
get isExactTag () {
|
||
|
return this[TYPE] === EXACT_RANGE && this.version[TAG] !== undefined;
|
||
|
}
|
||
|
get isStable () {
|
||
|
return this[TYPE] === STABLE_RANGE;
|
||
|
}
|
||
|
get isMajor () {
|
||
|
return this[TYPE] === MAJOR_RANGE;
|
||
|
}
|
||
|
get isWildcard () {
|
||
|
return this[TYPE] === WILDCARD_RANGE;
|
||
|
}
|
||
|
get type () {
|
||
|
switch (this[TYPE]) {
|
||
|
case WILDCARD_RANGE:
|
||
|
return 'wildcard';
|
||
|
case MAJOR_RANGE:
|
||
|
return 'major';
|
||
|
case STABLE_RANGE:
|
||
|
return 'stable';
|
||
|
case EXACT_RANGE:
|
||
|
return 'exact';
|
||
|
}
|
||
|
}
|
||
|
get version () {
|
||
|
return this[VERSION];
|
||
|
}
|
||
|
gt (range) {
|
||
|
return SemverRange.compare(this, range) === 1;
|
||
|
}
|
||
|
lt (range) {
|
||
|
return SemverRange.compare(this, range) === -1;
|
||
|
}
|
||
|
eq (range) {
|
||
|
return SemverRange.compare(this, range) === 0;
|
||
|
}
|
||
|
has (version, unstable = false) {
|
||
|
if (!(version instanceof Semver))
|
||
|
version = new Semver(version);
|
||
|
if (this[TYPE] === WILDCARD_RANGE)
|
||
|
return unstable || (!version[PRE] && !version[TAG]);
|
||
|
if (this[TYPE] === EXACT_RANGE)
|
||
|
return this[VERSION].eq(version);
|
||
|
if (version[TAG])
|
||
|
return false;
|
||
|
if (this[VERSION][MAJOR] !== version[MAJOR])
|
||
|
return false;
|
||
|
if (this[TYPE] === MAJOR_RANGE ? this[VERSION][MINOR] > version[MINOR] : this[VERSION][MINOR] !== version[MINOR])
|
||
|
return false;
|
||
|
if ((this[TYPE] === MAJOR_RANGE ? this[VERSION][MINOR] === version[MINOR] : true) && this[VERSION][PATCH] > version[PATCH])
|
||
|
return false;
|
||
|
if (version[PRE] === undefined || version[PRE].length === 0)
|
||
|
return true;
|
||
|
if (this[VERSION][PRE] === undefined || this[VERSION][PRE].length === 0)
|
||
|
return unstable;
|
||
|
if (unstable === false && (this[VERSION][MINOR] !== version[MINOR] || this[VERSION][PATCH] !== version[PATCH]))
|
||
|
return false;
|
||
|
return prereleaseCompare(this[VERSION][PRE], version[PRE]) !== 1;
|
||
|
}
|
||
|
contains (range) {
|
||
|
if (!(range instanceof SemverRange))
|
||
|
range = new SemverRange(range);
|
||
|
if (this[TYPE] === WILDCARD_RANGE)
|
||
|
return true;
|
||
|
if (range[TYPE] === WILDCARD_RANGE)
|
||
|
return false;
|
||
|
return range[TYPE] >= this[TYPE] && this.has(range[VERSION], true);
|
||
|
}
|
||
|
intersect (range) {
|
||
|
if (!(range instanceof SemverRange))
|
||
|
range = new SemverRange(range);
|
||
|
|
||
|
if (this[TYPE] === WILDCARD_RANGE && range[TYPE] === WILDCARD_RANGE)
|
||
|
return this;
|
||
|
if (this[TYPE] === WILDCARD_RANGE)
|
||
|
return range;
|
||
|
if (range[TYPE] === WILDCARD_RANGE)
|
||
|
return this;
|
||
|
|
||
|
if (this[TYPE] === EXACT_RANGE)
|
||
|
return range.has(this[VERSION], true) ? this : undefined;
|
||
|
if (range[TYPE] === EXACT_RANGE)
|
||
|
return this.has(range[VERSION], true) ? range : undefined;
|
||
|
|
||
|
let higherRange, lowerRange, polarity;
|
||
|
if (range[VERSION].gt(this[VERSION])) {
|
||
|
higherRange = range;
|
||
|
lowerRange = this;
|
||
|
polarity = true;
|
||
|
}
|
||
|
else {
|
||
|
higherRange = this;
|
||
|
lowerRange = range;
|
||
|
polarity = false;
|
||
|
}
|
||
|
|
||
|
if (!lowerRange.has(higherRange[VERSION], true))
|
||
|
return;
|
||
|
|
||
|
if (lowerRange[TYPE] === MAJOR_RANGE)
|
||
|
return polarity ? range : this;
|
||
|
|
||
|
let intersection = new SemverRange(higherRange[VERSION].toString());
|
||
|
intersection[TYPE] = STABLE_RANGE;
|
||
|
return intersection;
|
||
|
}
|
||
|
bestMatch (versions, unstable = false) {
|
||
|
let maxSemver;
|
||
|
versions.forEach(version => {
|
||
|
if (!(version instanceof Semver))
|
||
|
version = new Semver(version);
|
||
|
if (!this.has(version, unstable))
|
||
|
return;
|
||
|
if (!maxSemver)
|
||
|
maxSemver = version;
|
||
|
else if (Semver.compare(version, maxSemver) === 1)
|
||
|
maxSemver = version;
|
||
|
});
|
||
|
return maxSemver;
|
||
|
}
|
||
|
toString () {
|
||
|
let version = this[VERSION];
|
||
|
switch (this[TYPE]) {
|
||
|
case WILDCARD_RANGE:
|
||
|
return '*';
|
||
|
case MAJOR_RANGE:
|
||
|
if (version[MAJOR] === 0 && version[MINOR] === 0 && version[PATCH] === 0)
|
||
|
return '0';
|
||
|
if (version[PRE] && version[PRE].length === 0 && version[PATCH] === 0)
|
||
|
return '^' + version[MAJOR] + '.' + version[MINOR];
|
||
|
return '^' + version.toString();
|
||
|
case STABLE_RANGE:
|
||
|
if (version[PRE] && version[PRE].length === 0 && version[PATCH] === 0 || version[MAJOR] === 0 && version[MINOR] === 0)
|
||
|
return version[MAJOR] + '.' + version[MINOR];
|
||
|
return '~' + version.toString();
|
||
|
case EXACT_RANGE:
|
||
|
return version.toString();
|
||
|
}
|
||
|
}
|
||
|
toJSON() {
|
||
|
return this.toString();
|
||
|
}
|
||
|
static match (range, version, unstable = false) {
|
||
|
if (!(version instanceof Semver))
|
||
|
version = new Semver(version);
|
||
|
return version.matches(range, unstable);
|
||
|
}
|
||
|
static isValid (range) {
|
||
|
let semverRange = new SemverRange(range);
|
||
|
return semverRange[TYPE] !== EXACT_RANGE || semverRange[VERSION][TAG] === undefined;
|
||
|
}
|
||
|
static compare (r1, r2) {
|
||
|
if (!(r1 instanceof SemverRange))
|
||
|
r1 = new SemverRange(r1);
|
||
|
if (!(r2 instanceof SemverRange))
|
||
|
r2 = new SemverRange(r2);
|
||
|
if (r1[TYPE] === WILDCARD_RANGE && r2[TYPE] === WILDCARD_RANGE)
|
||
|
return 0;
|
||
|
if (r1[TYPE] === WILDCARD_RANGE)
|
||
|
return 1;
|
||
|
if (r2[TYPE] === WILDCARD_RANGE)
|
||
|
return -1;
|
||
|
let cmp = Semver.compare(r1[VERSION], r2[VERSION]);
|
||
|
if (cmp !== 0) {
|
||
|
return cmp;
|
||
|
}
|
||
|
if (r1[TYPE] === r2[TYPE])
|
||
|
return 0;
|
||
|
return r1[TYPE] > r2[TYPE] ? 1 : -1;
|
||
|
}
|
||
|
}
|
||
|
exports.SemverRange = SemverRange;
|