mirror of
https://kevinblog.sytes.net/Code/Jibo-Revival-Group/JiboViteDocs.git
synced 2026-06-15 21:56:30 +00:00
560 lines
15 KiB
JavaScript
560 lines
15 KiB
JavaScript
import { cmp } from './cmp'
|
|
import { ANY } from './constants'
|
|
import { debug } from './debug'
|
|
import {
|
|
HYPHENRANGELOOSE,
|
|
HYPHENRANGE,
|
|
COMPARATORTRIM,
|
|
comparatorTrimReplace,
|
|
TILDETRIM,
|
|
tildeTrimReplace,
|
|
CARETTRIM,
|
|
caretTrimReplace,
|
|
COMPARATORLOOSE,
|
|
COMPARATOR,
|
|
TILDELOOSE,
|
|
TILDE,
|
|
CARETLOOSE,
|
|
CARET,
|
|
XRANGELOOSE,
|
|
XRANGE,
|
|
STAR,
|
|
re
|
|
} from './src'
|
|
import { SemVer } from './semver'
|
|
|
|
export function Range (range, options) {
|
|
if (!options || typeof options !== 'object') {
|
|
options = { loose: !!options, includePrerelease: false }
|
|
}
|
|
if (range instanceof Range) {
|
|
if (
|
|
range.loose === !!options.loose &&
|
|
range.includePrerelease === !!options.includePrerelease
|
|
) {
|
|
return range
|
|
} else {
|
|
return new Range(range.raw, options)
|
|
}
|
|
}
|
|
if (range instanceof Comparator) {
|
|
return new Range(range.value, options)
|
|
}
|
|
if (!(this instanceof Range)) {
|
|
return new Range(range, options)
|
|
}
|
|
this.options = options
|
|
this.loose = !!options.loose
|
|
this.includePrerelease = !!options.includePrerelease
|
|
// First, split based on boolean or ||
|
|
this.raw = range
|
|
this.set = range
|
|
.split(/\s*\|\|\s*/)
|
|
.map(function (range) {
|
|
return this.parseRange(range.trim())
|
|
}, this)
|
|
.filter(function (c) {
|
|
// throw out any that are not relevant for whatever reason
|
|
return c.length
|
|
})
|
|
if (!this.set.length) {
|
|
throw new TypeError('Invalid SemVer Range: ' + range)
|
|
}
|
|
this.format()
|
|
}
|
|
Range.prototype.format = function () {
|
|
this.range = this.set
|
|
.map(function (comps) {
|
|
return comps.join(' ').trim()
|
|
})
|
|
.join('||')
|
|
.trim()
|
|
return this.range
|
|
}
|
|
Range.prototype.toString = function () {
|
|
return this.range
|
|
}
|
|
Range.prototype.parseRange = function (range) {
|
|
var loose = this.options.loose
|
|
range = range.trim()
|
|
// `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
|
|
var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]
|
|
range = range.replace(hr, hyphenReplace)
|
|
debug('hyphen replace', range)
|
|
// `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
|
|
range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace)
|
|
debug('comparator trim', range, re[COMPARATORTRIM])
|
|
// `~ 1.2.3` => `~1.2.3`
|
|
range = range.replace(re[TILDETRIM], tildeTrimReplace)
|
|
// `^ 1.2.3` => `^1.2.3`
|
|
range = range.replace(re[CARETTRIM], caretTrimReplace)
|
|
// normalize spaces
|
|
range = range.split(/\s+/).join(' ')
|
|
// At this point, the range is completely trimmed and
|
|
// ready to be split into comparators.
|
|
var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
|
|
var set = range
|
|
.split(' ')
|
|
.map(function (comp) {
|
|
return parseComparator(comp, this.options)
|
|
}, this)
|
|
.join(' ')
|
|
.split(/\s+/)
|
|
if (this.options.loose) {
|
|
// in loose mode, throw out any that are not valid comparators
|
|
set = set.filter(function (comp) {
|
|
return !!comp.match(compRe)
|
|
})
|
|
}
|
|
set = set.map(function (comp) {
|
|
return new Comparator(comp, this.options)
|
|
}, this)
|
|
return set
|
|
}
|
|
Range.prototype.intersects = function (range, options) {
|
|
if (!(range instanceof Range)) {
|
|
throw new TypeError('a Range is required')
|
|
}
|
|
return this.set.some(function (thisComparators) {
|
|
return thisComparators.every(function (thisComparator) {
|
|
return range.set.some(function (rangeComparators) {
|
|
return rangeComparators.every(function (rangeComparator) {
|
|
return thisComparator.intersects(rangeComparator, options)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
// Mostly just for testing and legacy API reasons
|
|
export function toComparators (range, options) {
|
|
return new Range(range, options).set.map(function (comp) {
|
|
return comp
|
|
.map(function (c) {
|
|
return c.value
|
|
})
|
|
.join(' ')
|
|
.trim()
|
|
.split(' ')
|
|
})
|
|
}
|
|
// comprised of xranges, tildes, stars, and gtlt's at this point.
|
|
// already replaced the hyphen ranges
|
|
// turn into a set of JUST comparators.
|
|
function parseComparator (comp, options) {
|
|
debug('comp', comp, options)
|
|
comp = replaceCarets(comp, options)
|
|
debug('caret', comp)
|
|
comp = replaceTildes(comp, options)
|
|
debug('tildes', comp)
|
|
comp = replaceXRanges(comp, options)
|
|
debug('xrange', comp)
|
|
comp = replaceStars(comp, options)
|
|
debug('stars', comp)
|
|
return comp
|
|
}
|
|
function isX (id) {
|
|
return !id || id.toLowerCase() === 'x' || id === '*'
|
|
}
|
|
// ~, ~> --> * (any, kinda silly)
|
|
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
|
|
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
|
|
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
|
|
// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
|
|
// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
|
|
function replaceTildes (comp, options) {
|
|
return comp
|
|
.trim()
|
|
.split(/\s+/)
|
|
.map(function (comp) {
|
|
return replaceTilde(comp, options)
|
|
})
|
|
.join(' ')
|
|
}
|
|
function replaceTilde (comp, options) {
|
|
if (!options || typeof options !== 'object') {
|
|
options = { loose: !!options, includePrerelease: false }
|
|
}
|
|
var r = options.loose ? re[TILDELOOSE] : re[TILDE]
|
|
return comp.replace(r, function (_, M, m, p, pr) {
|
|
debug('tilde', comp, _, M, m, p, pr)
|
|
var ret
|
|
if (isX(M)) {
|
|
ret = ''
|
|
} else if (isX(m)) {
|
|
ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
|
|
} else if (isX(p)) {
|
|
// ~1.2 == >=1.2.0 <1.3.0
|
|
ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
|
|
} else if (pr) {
|
|
debug('replaceTilde pr', pr)
|
|
if (pr.charAt(0) !== '-') {
|
|
pr = '-' + pr
|
|
}
|
|
ret =
|
|
'>=' + M + '.' + m + '.' + p + pr + ' <' + M + '.' + (+m + 1) + '.0'
|
|
} else {
|
|
// ~1.2.3 == >=1.2.3 <1.3.0
|
|
ret = '>=' + M + '.' + m + '.' + p + ' <' + M + '.' + (+m + 1) + '.0'
|
|
}
|
|
debug('tilde return', ret)
|
|
return ret
|
|
})
|
|
}
|
|
// ^ --> * (any, kinda silly)
|
|
// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
|
|
// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
|
|
// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
|
|
// ^1.2.3 --> >=1.2.3 <2.0.0
|
|
// ^1.2.0 --> >=1.2.0 <2.0.0
|
|
function replaceCarets (comp, options) {
|
|
return comp
|
|
.trim()
|
|
.split(/\s+/)
|
|
.map(function (comp) {
|
|
return replaceCaret(comp, options)
|
|
})
|
|
.join(' ')
|
|
}
|
|
function replaceCaret (comp, options) {
|
|
debug('caret', comp, options)
|
|
if (!options || typeof options !== 'object') {
|
|
options = { loose: !!options, includePrerelease: false }
|
|
}
|
|
var r = options.loose ? re[CARETLOOSE] : re[CARET]
|
|
return comp.replace(r, function (_, M, m, p, pr) {
|
|
debug('caret', comp, _, M, m, p, pr)
|
|
var ret
|
|
if (isX(M)) {
|
|
ret = ''
|
|
} else if (isX(m)) {
|
|
ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
|
|
} else if (isX(p)) {
|
|
if (M === '0') {
|
|
ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
|
|
} else {
|
|
ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'
|
|
}
|
|
} else if (pr) {
|
|
debug('replaceCaret pr', pr)
|
|
if (pr.charAt(0) !== '-') {
|
|
pr = '-' + pr
|
|
}
|
|
if (M === '0') {
|
|
if (m === '0') {
|
|
ret =
|
|
'>=' +
|
|
M +
|
|
'.' +
|
|
m +
|
|
'.' +
|
|
p +
|
|
pr +
|
|
' <' +
|
|
M +
|
|
'.' +
|
|
m +
|
|
'.' +
|
|
(+p + 1)
|
|
} else {
|
|
ret =
|
|
'>=' +
|
|
M +
|
|
'.' +
|
|
m +
|
|
'.' +
|
|
p +
|
|
pr +
|
|
' <' +
|
|
M +
|
|
'.' +
|
|
(+m + 1) +
|
|
'.0'
|
|
}
|
|
} else {
|
|
ret = '>=' + M + '.' + m + '.' + p + pr + ' <' + (+M + 1) + '.0.0'
|
|
}
|
|
} else {
|
|
debug('no pr')
|
|
if (M === '0') {
|
|
if (m === '0') {
|
|
ret =
|
|
'>=' + M + '.' + m + '.' + p + ' <' + M + '.' + m + '.' + (+p + 1)
|
|
} else {
|
|
ret = '>=' + M + '.' + m + '.' + p + ' <' + M + '.' + (+m + 1) + '.0'
|
|
}
|
|
} else {
|
|
ret = '>=' + M + '.' + m + '.' + p + ' <' + (+M + 1) + '.0.0'
|
|
}
|
|
}
|
|
debug('caret return', ret)
|
|
return ret
|
|
})
|
|
}
|
|
function replaceXRanges (comp, options) {
|
|
debug('replaceXRanges', comp, options)
|
|
return comp
|
|
.split(/\s+/)
|
|
.map(function (comp) {
|
|
return replaceXRange(comp, options)
|
|
})
|
|
.join(' ')
|
|
}
|
|
function replaceXRange (comp, options) {
|
|
comp = comp.trim()
|
|
if (!options || typeof options !== 'object') {
|
|
options = { loose: !!options, includePrerelease: false }
|
|
}
|
|
var r = options.loose ? re[XRANGELOOSE] : re[XRANGE]
|
|
return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
|
|
debug('xRange', comp, ret, gtlt, M, m, p, pr)
|
|
var xM = isX(M)
|
|
var xm = xM || isX(m)
|
|
var xp = xm || isX(p)
|
|
var anyX = xp
|
|
if (gtlt === '=' && anyX) {
|
|
gtlt = ''
|
|
}
|
|
if (xM) {
|
|
if (gtlt === '>' || gtlt === '<') {
|
|
// nothing is allowed
|
|
ret = '<0.0.0'
|
|
} else {
|
|
// nothing is forbidden
|
|
ret = '*'
|
|
}
|
|
} else if (gtlt && anyX) {
|
|
// replace X with 0
|
|
if (xm) {
|
|
m = 0
|
|
}
|
|
if (xp) {
|
|
p = 0
|
|
}
|
|
if (gtlt === '>') {
|
|
// >1 => >=2.0.0
|
|
// >1.2 => >=1.3.0
|
|
// >1.2.3 => >= 1.2.4
|
|
gtlt = '>='
|
|
if (xm) {
|
|
M = +M + 1
|
|
m = 0
|
|
p = 0
|
|
} else if (xp) {
|
|
m = +m + 1
|
|
p = 0
|
|
}
|
|
} else if (gtlt === '<=') {
|
|
// <=0.7.x is actually <0.8.0, since any 0.7.x should
|
|
// pass. Similarly, <=7.x is actually <8.0.0, etc.
|
|
gtlt = '<'
|
|
if (xm) {
|
|
M = +M + 1
|
|
} else {
|
|
m = +m + 1
|
|
}
|
|
}
|
|
ret = gtlt + M + '.' + m + '.' + p
|
|
} else if (xm) {
|
|
ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
|
|
} else if (xp) {
|
|
ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
|
|
}
|
|
debug('xRange return', ret)
|
|
return ret
|
|
})
|
|
}
|
|
// Because * is AND-ed with everything else in the comparator,
|
|
// and '' means "any version", just remove the *s entirely.
|
|
function replaceStars (comp, options) {
|
|
debug('replaceStars', comp, options)
|
|
// Looseness is ignored here. star is always as loose as it gets!
|
|
return comp.trim().replace(re[STAR], '')
|
|
}
|
|
// This function is passed to string.replace(re[HYPHENRANGE])
|
|
// M, m, patch, prerelease, build
|
|
// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
|
|
// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
|
|
// 1.2 - 3.4 => >=1.2.0 <3.5.0
|
|
function hyphenReplace ($0, from, fM, fm, fp, fpr, fb, to, tM, tm, tp, tpr, tb) {
|
|
if (isX(fM)) {
|
|
from = ''
|
|
} else if (isX(fm)) {
|
|
from = '>=' + fM + '.0.0'
|
|
} else if (isX(fp)) {
|
|
from = '>=' + fM + '.' + fm + '.0'
|
|
} else {
|
|
from = '>=' + from
|
|
}
|
|
if (isX(tM)) {
|
|
to = ''
|
|
} else if (isX(tm)) {
|
|
to = '<' + (+tM + 1) + '.0.0'
|
|
} else if (isX(tp)) {
|
|
to = '<' + tM + '.' + (+tm + 1) + '.0'
|
|
} else if (tpr) {
|
|
to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr
|
|
} else {
|
|
to = '<=' + to
|
|
}
|
|
return (from + ' ' + to).trim()
|
|
}
|
|
// if ANY of the sets match ALL of its comparators, then pass
|
|
Range.prototype.test = function (version) {
|
|
if (!version) {
|
|
return false
|
|
}
|
|
if (typeof version === 'string') {
|
|
version = new SemVer(version, this.options)
|
|
}
|
|
for (var i = 0; i < this.set.length; i++) {
|
|
if (testSet(this.set[i], version, this.options)) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
function testSet (set, version, options) {
|
|
for (var i = 0; i < set.length; i++) {
|
|
if (!set[i].test(version)) {
|
|
return false
|
|
}
|
|
}
|
|
if (!options) {
|
|
options = {}
|
|
}
|
|
if (version.prerelease.length && !options.includePrerelease) {
|
|
// Find the set of versions that are allowed to have prereleases
|
|
// For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
|
|
// That should allow `1.2.3-pr.2` to pass.
|
|
// However, `1.2.4-alpha.notready` should NOT be allowed,
|
|
// even though it's within the range set by the comparators.
|
|
for (i = 0; i < set.length; i++) {
|
|
debug(set[i].semver)
|
|
if (set[i].semver === ANY) {
|
|
continue
|
|
}
|
|
if (set[i].semver.prerelease.length > 0) {
|
|
var allowed = set[i].semver
|
|
if (
|
|
allowed.major === version.major &&
|
|
allowed.minor === version.minor &&
|
|
allowed.patch === version.patch
|
|
) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
// Version has a -pre, but it's not one of the ones we like.
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
export function Comparator (comp, options) {
|
|
if (!options || typeof options !== 'object') {
|
|
options = { loose: !!options, includePrerelease: false }
|
|
}
|
|
if (comp instanceof Comparator) {
|
|
if (comp.loose === !!options.loose) {
|
|
return comp
|
|
} else {
|
|
comp = comp.value
|
|
}
|
|
}
|
|
if (!(this instanceof Comparator)) {
|
|
return new Comparator(comp, options)
|
|
}
|
|
debug('comparator', comp, options)
|
|
this.options = options
|
|
this.loose = !!options.loose
|
|
this.parse(comp)
|
|
if (this.semver === ANY) {
|
|
this.value = ''
|
|
} else {
|
|
this.value = this.operator + this.semver.version
|
|
}
|
|
debug('comp', this)
|
|
}
|
|
|
|
Comparator.prototype.parse = function (comp) {
|
|
var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
|
|
var m = comp.match(r)
|
|
if (!m) {
|
|
throw new TypeError('Invalid comparator: ' + comp)
|
|
}
|
|
this.operator = m[1]
|
|
if (this.operator === '=') {
|
|
this.operator = ''
|
|
}
|
|
// if it literally is just '>' or '' then allow anything.
|
|
if (!m[2]) {
|
|
this.semver = ANY
|
|
} else {
|
|
this.semver = new SemVer(m[2], this.options.loose)
|
|
}
|
|
}
|
|
Comparator.prototype.toString = function () {
|
|
return this.value
|
|
}
|
|
Comparator.prototype.test = function (version) {
|
|
debug('Comparator.test', version, this.options.loose)
|
|
if (this.semver === ANY) {
|
|
return true
|
|
}
|
|
if (typeof version === 'string') {
|
|
version = new SemVer(version, this.options)
|
|
}
|
|
return cmp(version, this.operator, this.semver, this.options)
|
|
}
|
|
Comparator.prototype.intersects = function (comp, options) {
|
|
if (!(comp instanceof Comparator)) {
|
|
throw new TypeError('a Comparator is required')
|
|
}
|
|
if (!options || typeof options !== 'object') {
|
|
options = { loose: !!options, includePrerelease: false }
|
|
}
|
|
var rangeTmp
|
|
if (this.operator === '') {
|
|
rangeTmp = new Range(comp.value, options)
|
|
return satisfies(this.value, rangeTmp, options)
|
|
} else if (comp.operator === '') {
|
|
rangeTmp = new Range(this.value, options)
|
|
return satisfies(comp.semver, rangeTmp, options)
|
|
}
|
|
var sameDirectionIncreasing =
|
|
(this.operator === '>=' || this.operator === '>') &&
|
|
(comp.operator === '>=' || comp.operator === '>')
|
|
var sameDirectionDecreasing =
|
|
(this.operator === '<=' || this.operator === '<') &&
|
|
(comp.operator === '<=' || comp.operator === '<')
|
|
var sameSemVer = this.semver.version === comp.semver.version
|
|
var differentDirectionsInclusive =
|
|
(this.operator === '>=' || this.operator === '<=') &&
|
|
(comp.operator === '>=' || comp.operator === '<=')
|
|
var oppositeDirectionsLessThan =
|
|
cmp(this.semver, '<', comp.semver, options) &&
|
|
((this.operator === '>=' || this.operator === '>') &&
|
|
(comp.operator === '<=' || comp.operator === '<'))
|
|
var oppositeDirectionsGreaterThan =
|
|
cmp(this.semver, '>', comp.semver, options) &&
|
|
((this.operator === '<=' || this.operator === '<') &&
|
|
(comp.operator === '>=' || comp.operator === '>'))
|
|
return (
|
|
sameDirectionIncreasing ||
|
|
sameDirectionDecreasing ||
|
|
(sameSemVer && differentDirectionsInclusive) ||
|
|
oppositeDirectionsLessThan ||
|
|
oppositeDirectionsGreaterThan
|
|
)
|
|
}
|
|
|
|
export function satisfies (version, range, options) {
|
|
try {
|
|
range = new Range(range, options)
|
|
} catch (er) {
|
|
return false
|
|
}
|
|
return range.test(version)
|
|
}
|