[d24f17c] | 1 | // hoisted class for cyclic dependency
|
---|
| 2 | class Range {
|
---|
| 3 | constructor (range, options) {
|
---|
| 4 | options = parseOptions(options)
|
---|
| 5 |
|
---|
| 6 | if (range instanceof Range) {
|
---|
| 7 | if (
|
---|
| 8 | range.loose === !!options.loose &&
|
---|
| 9 | range.includePrerelease === !!options.includePrerelease
|
---|
| 10 | ) {
|
---|
| 11 | return range
|
---|
| 12 | } else {
|
---|
| 13 | return new Range(range.raw, options)
|
---|
| 14 | }
|
---|
| 15 | }
|
---|
| 16 |
|
---|
| 17 | if (range instanceof Comparator) {
|
---|
| 18 | // just put it in the set and return
|
---|
| 19 | this.raw = range.value
|
---|
| 20 | this.set = [[range]]
|
---|
| 21 | this.format()
|
---|
| 22 | return this
|
---|
| 23 | }
|
---|
| 24 |
|
---|
| 25 | this.options = options
|
---|
| 26 | this.loose = !!options.loose
|
---|
| 27 | this.includePrerelease = !!options.includePrerelease
|
---|
| 28 |
|
---|
| 29 | // First reduce all whitespace as much as possible so we do not have to rely
|
---|
| 30 | // on potentially slow regexes like \s*. This is then stored and used for
|
---|
| 31 | // future error messages as well.
|
---|
| 32 | this.raw = range
|
---|
| 33 | .trim()
|
---|
| 34 | .split(/\s+/)
|
---|
| 35 | .join(' ')
|
---|
| 36 |
|
---|
| 37 | // First, split on ||
|
---|
| 38 | this.set = this.raw
|
---|
| 39 | .split('||')
|
---|
| 40 | // map the range to a 2d array of comparators
|
---|
| 41 | .map(r => this.parseRange(r.trim()))
|
---|
| 42 | // throw out any comparator lists that are empty
|
---|
| 43 | // this generally means that it was not a valid range, which is allowed
|
---|
| 44 | // in loose mode, but will still throw if the WHOLE range is invalid.
|
---|
| 45 | .filter(c => c.length)
|
---|
| 46 |
|
---|
| 47 | if (!this.set.length) {
|
---|
| 48 | throw new TypeError(`Invalid SemVer Range: ${this.raw}`)
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | // if we have any that are not the null set, throw out null sets.
|
---|
| 52 | if (this.set.length > 1) {
|
---|
| 53 | // keep the first one, in case they're all null sets
|
---|
| 54 | const first = this.set[0]
|
---|
| 55 | this.set = this.set.filter(c => !isNullSet(c[0]))
|
---|
| 56 | if (this.set.length === 0) {
|
---|
| 57 | this.set = [first]
|
---|
| 58 | } else if (this.set.length > 1) {
|
---|
| 59 | // if we have any that are *, then the range is just *
|
---|
| 60 | for (const c of this.set) {
|
---|
| 61 | if (c.length === 1 && isAny(c[0])) {
|
---|
| 62 | this.set = [c]
|
---|
| 63 | break
|
---|
| 64 | }
|
---|
| 65 | }
|
---|
| 66 | }
|
---|
| 67 | }
|
---|
| 68 |
|
---|
| 69 | this.format()
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | format () {
|
---|
| 73 | this.range = this.set
|
---|
| 74 | .map((comps) => comps.join(' ').trim())
|
---|
| 75 | .join('||')
|
---|
| 76 | .trim()
|
---|
| 77 | return this.range
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | toString () {
|
---|
| 81 | return this.range
|
---|
| 82 | }
|
---|
| 83 |
|
---|
| 84 | parseRange (range) {
|
---|
| 85 | // memoize range parsing for performance.
|
---|
| 86 | // this is a very hot path, and fully deterministic.
|
---|
| 87 | const memoOpts =
|
---|
| 88 | (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) |
|
---|
| 89 | (this.options.loose && FLAG_LOOSE)
|
---|
| 90 | const memoKey = memoOpts + ':' + range
|
---|
| 91 | const cached = cache.get(memoKey)
|
---|
| 92 | if (cached) {
|
---|
| 93 | return cached
|
---|
| 94 | }
|
---|
| 95 |
|
---|
| 96 | const loose = this.options.loose
|
---|
| 97 | // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
|
---|
| 98 | const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]
|
---|
| 99 | range = range.replace(hr, hyphenReplace(this.options.includePrerelease))
|
---|
| 100 | debug('hyphen replace', range)
|
---|
| 101 |
|
---|
| 102 | // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
|
---|
| 103 | range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
|
---|
| 104 | debug('comparator trim', range)
|
---|
| 105 |
|
---|
| 106 | // `~ 1.2.3` => `~1.2.3`
|
---|
| 107 | range = range.replace(re[t.TILDETRIM], tildeTrimReplace)
|
---|
| 108 | debug('tilde trim', range)
|
---|
| 109 |
|
---|
| 110 | // `^ 1.2.3` => `^1.2.3`
|
---|
| 111 | range = range.replace(re[t.CARETTRIM], caretTrimReplace)
|
---|
| 112 | debug('caret trim', range)
|
---|
| 113 |
|
---|
| 114 | // At this point, the range is completely trimmed and
|
---|
| 115 | // ready to be split into comparators.
|
---|
| 116 |
|
---|
| 117 | let rangeList = range
|
---|
| 118 | .split(' ')
|
---|
| 119 | .map(comp => parseComparator(comp, this.options))
|
---|
| 120 | .join(' ')
|
---|
| 121 | .split(/\s+/)
|
---|
| 122 | // >=0.0.0 is equivalent to *
|
---|
| 123 | .map(comp => replaceGTE0(comp, this.options))
|
---|
| 124 |
|
---|
| 125 | if (loose) {
|
---|
| 126 | // in loose mode, throw out any that are not valid comparators
|
---|
| 127 | rangeList = rangeList.filter(comp => {
|
---|
| 128 | debug('loose invalid filter', comp, this.options)
|
---|
| 129 | return !!comp.match(re[t.COMPARATORLOOSE])
|
---|
| 130 | })
|
---|
| 131 | }
|
---|
| 132 | debug('range list', rangeList)
|
---|
| 133 |
|
---|
| 134 | // if any comparators are the null set, then replace with JUST null set
|
---|
| 135 | // if more than one comparator, remove any * comparators
|
---|
| 136 | // also, don't include the same comparator more than once
|
---|
| 137 | const rangeMap = new Map()
|
---|
| 138 | const comparators = rangeList.map(comp => new Comparator(comp, this.options))
|
---|
| 139 | for (const comp of comparators) {
|
---|
| 140 | if (isNullSet(comp)) {
|
---|
| 141 | return [comp]
|
---|
| 142 | }
|
---|
| 143 | rangeMap.set(comp.value, comp)
|
---|
| 144 | }
|
---|
| 145 | if (rangeMap.size > 1 && rangeMap.has('')) {
|
---|
| 146 | rangeMap.delete('')
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 | const result = [...rangeMap.values()]
|
---|
| 150 | cache.set(memoKey, result)
|
---|
| 151 | return result
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | intersects (range, options) {
|
---|
| 155 | if (!(range instanceof Range)) {
|
---|
| 156 | throw new TypeError('a Range is required')
|
---|
| 157 | }
|
---|
| 158 |
|
---|
| 159 | return this.set.some((thisComparators) => {
|
---|
| 160 | return (
|
---|
| 161 | isSatisfiable(thisComparators, options) &&
|
---|
| 162 | range.set.some((rangeComparators) => {
|
---|
| 163 | return (
|
---|
| 164 | isSatisfiable(rangeComparators, options) &&
|
---|
| 165 | thisComparators.every((thisComparator) => {
|
---|
| 166 | return rangeComparators.every((rangeComparator) => {
|
---|
| 167 | return thisComparator.intersects(rangeComparator, options)
|
---|
| 168 | })
|
---|
| 169 | })
|
---|
| 170 | )
|
---|
| 171 | })
|
---|
| 172 | )
|
---|
| 173 | })
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 | // if ANY of the sets match ALL of its comparators, then pass
|
---|
| 177 | test (version) {
|
---|
| 178 | if (!version) {
|
---|
| 179 | return false
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | if (typeof version === 'string') {
|
---|
| 183 | try {
|
---|
| 184 | version = new SemVer(version, this.options)
|
---|
| 185 | } catch (er) {
|
---|
| 186 | return false
|
---|
| 187 | }
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | for (let i = 0; i < this.set.length; i++) {
|
---|
| 191 | if (testSet(this.set[i], version, this.options)) {
|
---|
| 192 | return true
|
---|
| 193 | }
|
---|
| 194 | }
|
---|
| 195 | return false
|
---|
| 196 | }
|
---|
| 197 | }
|
---|
| 198 |
|
---|
| 199 | module.exports = Range
|
---|
| 200 |
|
---|
| 201 | const LRU = require('lru-cache')
|
---|
| 202 | const cache = new LRU({ max: 1000 })
|
---|
| 203 |
|
---|
| 204 | const parseOptions = require('../internal/parse-options')
|
---|
| 205 | const Comparator = require('./comparator')
|
---|
| 206 | const debug = require('../internal/debug')
|
---|
| 207 | const SemVer = require('./semver')
|
---|
| 208 | const {
|
---|
| 209 | safeRe: re,
|
---|
| 210 | t,
|
---|
| 211 | comparatorTrimReplace,
|
---|
| 212 | tildeTrimReplace,
|
---|
| 213 | caretTrimReplace,
|
---|
| 214 | } = require('../internal/re')
|
---|
| 215 | const { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require('../internal/constants')
|
---|
| 216 |
|
---|
| 217 | const isNullSet = c => c.value === '<0.0.0-0'
|
---|
| 218 | const isAny = c => c.value === ''
|
---|
| 219 |
|
---|
| 220 | // take a set of comparators and determine whether there
|
---|
| 221 | // exists a version which can satisfy it
|
---|
| 222 | const isSatisfiable = (comparators, options) => {
|
---|
| 223 | let result = true
|
---|
| 224 | const remainingComparators = comparators.slice()
|
---|
| 225 | let testComparator = remainingComparators.pop()
|
---|
| 226 |
|
---|
| 227 | while (result && remainingComparators.length) {
|
---|
| 228 | result = remainingComparators.every((otherComparator) => {
|
---|
| 229 | return testComparator.intersects(otherComparator, options)
|
---|
| 230 | })
|
---|
| 231 |
|
---|
| 232 | testComparator = remainingComparators.pop()
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 | return result
|
---|
| 236 | }
|
---|
| 237 |
|
---|
| 238 | // comprised of xranges, tildes, stars, and gtlt's at this point.
|
---|
| 239 | // already replaced the hyphen ranges
|
---|
| 240 | // turn into a set of JUST comparators.
|
---|
| 241 | const parseComparator = (comp, options) => {
|
---|
| 242 | debug('comp', comp, options)
|
---|
| 243 | comp = replaceCarets(comp, options)
|
---|
| 244 | debug('caret', comp)
|
---|
| 245 | comp = replaceTildes(comp, options)
|
---|
| 246 | debug('tildes', comp)
|
---|
| 247 | comp = replaceXRanges(comp, options)
|
---|
| 248 | debug('xrange', comp)
|
---|
| 249 | comp = replaceStars(comp, options)
|
---|
| 250 | debug('stars', comp)
|
---|
| 251 | return comp
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | const isX = id => !id || id.toLowerCase() === 'x' || id === '*'
|
---|
| 255 |
|
---|
| 256 | // ~, ~> --> * (any, kinda silly)
|
---|
| 257 | // ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0
|
---|
| 258 | // ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0
|
---|
| 259 | // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0
|
---|
| 260 | // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0
|
---|
| 261 | // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0
|
---|
| 262 | // ~0.0.1 --> >=0.0.1 <0.1.0-0
|
---|
| 263 | const replaceTildes = (comp, options) => {
|
---|
| 264 | return comp
|
---|
| 265 | .trim()
|
---|
| 266 | .split(/\s+/)
|
---|
| 267 | .map((c) => replaceTilde(c, options))
|
---|
| 268 | .join(' ')
|
---|
| 269 | }
|
---|
| 270 |
|
---|
| 271 | const replaceTilde = (comp, options) => {
|
---|
| 272 | const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]
|
---|
| 273 | return comp.replace(r, (_, M, m, p, pr) => {
|
---|
| 274 | debug('tilde', comp, _, M, m, p, pr)
|
---|
| 275 | let ret
|
---|
| 276 |
|
---|
| 277 | if (isX(M)) {
|
---|
| 278 | ret = ''
|
---|
| 279 | } else if (isX(m)) {
|
---|
| 280 | ret = `>=${M}.0.0 <${+M + 1}.0.0-0`
|
---|
| 281 | } else if (isX(p)) {
|
---|
| 282 | // ~1.2 == >=1.2.0 <1.3.0-0
|
---|
| 283 | ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`
|
---|
| 284 | } else if (pr) {
|
---|
| 285 | debug('replaceTilde pr', pr)
|
---|
| 286 | ret = `>=${M}.${m}.${p}-${pr
|
---|
| 287 | } <${M}.${+m + 1}.0-0`
|
---|
| 288 | } else {
|
---|
| 289 | // ~1.2.3 == >=1.2.3 <1.3.0-0
|
---|
| 290 | ret = `>=${M}.${m}.${p
|
---|
| 291 | } <${M}.${+m + 1}.0-0`
|
---|
| 292 | }
|
---|
| 293 |
|
---|
| 294 | debug('tilde return', ret)
|
---|
| 295 | return ret
|
---|
| 296 | })
|
---|
| 297 | }
|
---|
| 298 |
|
---|
| 299 | // ^ --> * (any, kinda silly)
|
---|
| 300 | // ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0
|
---|
| 301 | // ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0
|
---|
| 302 | // ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0
|
---|
| 303 | // ^1.2.3 --> >=1.2.3 <2.0.0-0
|
---|
| 304 | // ^1.2.0 --> >=1.2.0 <2.0.0-0
|
---|
| 305 | // ^0.0.1 --> >=0.0.1 <0.0.2-0
|
---|
| 306 | // ^0.1.0 --> >=0.1.0 <0.2.0-0
|
---|
| 307 | const replaceCarets = (comp, options) => {
|
---|
| 308 | return comp
|
---|
| 309 | .trim()
|
---|
| 310 | .split(/\s+/)
|
---|
| 311 | .map((c) => replaceCaret(c, options))
|
---|
| 312 | .join(' ')
|
---|
| 313 | }
|
---|
| 314 |
|
---|
| 315 | const replaceCaret = (comp, options) => {
|
---|
| 316 | debug('caret', comp, options)
|
---|
| 317 | const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]
|
---|
| 318 | const z = options.includePrerelease ? '-0' : ''
|
---|
| 319 | return comp.replace(r, (_, M, m, p, pr) => {
|
---|
| 320 | debug('caret', comp, _, M, m, p, pr)
|
---|
| 321 | let ret
|
---|
| 322 |
|
---|
| 323 | if (isX(M)) {
|
---|
| 324 | ret = ''
|
---|
| 325 | } else if (isX(m)) {
|
---|
| 326 | ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`
|
---|
| 327 | } else if (isX(p)) {
|
---|
| 328 | if (M === '0') {
|
---|
| 329 | ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`
|
---|
| 330 | } else {
|
---|
| 331 | ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`
|
---|
| 332 | }
|
---|
| 333 | } else if (pr) {
|
---|
| 334 | debug('replaceCaret pr', pr)
|
---|
| 335 | if (M === '0') {
|
---|
| 336 | if (m === '0') {
|
---|
| 337 | ret = `>=${M}.${m}.${p}-${pr
|
---|
| 338 | } <${M}.${m}.${+p + 1}-0`
|
---|
| 339 | } else {
|
---|
| 340 | ret = `>=${M}.${m}.${p}-${pr
|
---|
| 341 | } <${M}.${+m + 1}.0-0`
|
---|
| 342 | }
|
---|
| 343 | } else {
|
---|
| 344 | ret = `>=${M}.${m}.${p}-${pr
|
---|
| 345 | } <${+M + 1}.0.0-0`
|
---|
| 346 | }
|
---|
| 347 | } else {
|
---|
| 348 | debug('no pr')
|
---|
| 349 | if (M === '0') {
|
---|
| 350 | if (m === '0') {
|
---|
| 351 | ret = `>=${M}.${m}.${p
|
---|
| 352 | }${z} <${M}.${m}.${+p + 1}-0`
|
---|
| 353 | } else {
|
---|
| 354 | ret = `>=${M}.${m}.${p
|
---|
| 355 | }${z} <${M}.${+m + 1}.0-0`
|
---|
| 356 | }
|
---|
| 357 | } else {
|
---|
| 358 | ret = `>=${M}.${m}.${p
|
---|
| 359 | } <${+M + 1}.0.0-0`
|
---|
| 360 | }
|
---|
| 361 | }
|
---|
| 362 |
|
---|
| 363 | debug('caret return', ret)
|
---|
| 364 | return ret
|
---|
| 365 | })
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 | const replaceXRanges = (comp, options) => {
|
---|
| 369 | debug('replaceXRanges', comp, options)
|
---|
| 370 | return comp
|
---|
| 371 | .split(/\s+/)
|
---|
| 372 | .map((c) => replaceXRange(c, options))
|
---|
| 373 | .join(' ')
|
---|
| 374 | }
|
---|
| 375 |
|
---|
| 376 | const replaceXRange = (comp, options) => {
|
---|
| 377 | comp = comp.trim()
|
---|
| 378 | const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]
|
---|
| 379 | return comp.replace(r, (ret, gtlt, M, m, p, pr) => {
|
---|
| 380 | debug('xRange', comp, ret, gtlt, M, m, p, pr)
|
---|
| 381 | const xM = isX(M)
|
---|
| 382 | const xm = xM || isX(m)
|
---|
| 383 | const xp = xm || isX(p)
|
---|
| 384 | const anyX = xp
|
---|
| 385 |
|
---|
| 386 | if (gtlt === '=' && anyX) {
|
---|
| 387 | gtlt = ''
|
---|
| 388 | }
|
---|
| 389 |
|
---|
| 390 | // if we're including prereleases in the match, then we need
|
---|
| 391 | // to fix this to -0, the lowest possible prerelease value
|
---|
| 392 | pr = options.includePrerelease ? '-0' : ''
|
---|
| 393 |
|
---|
| 394 | if (xM) {
|
---|
| 395 | if (gtlt === '>' || gtlt === '<') {
|
---|
| 396 | // nothing is allowed
|
---|
| 397 | ret = '<0.0.0-0'
|
---|
| 398 | } else {
|
---|
| 399 | // nothing is forbidden
|
---|
| 400 | ret = '*'
|
---|
| 401 | }
|
---|
| 402 | } else if (gtlt && anyX) {
|
---|
| 403 | // we know patch is an x, because we have any x at all.
|
---|
| 404 | // replace X with 0
|
---|
| 405 | if (xm) {
|
---|
| 406 | m = 0
|
---|
| 407 | }
|
---|
| 408 | p = 0
|
---|
| 409 |
|
---|
| 410 | if (gtlt === '>') {
|
---|
| 411 | // >1 => >=2.0.0
|
---|
| 412 | // >1.2 => >=1.3.0
|
---|
| 413 | gtlt = '>='
|
---|
| 414 | if (xm) {
|
---|
| 415 | M = +M + 1
|
---|
| 416 | m = 0
|
---|
| 417 | p = 0
|
---|
| 418 | } else {
|
---|
| 419 | m = +m + 1
|
---|
| 420 | p = 0
|
---|
| 421 | }
|
---|
| 422 | } else if (gtlt === '<=') {
|
---|
| 423 | // <=0.7.x is actually <0.8.0, since any 0.7.x should
|
---|
| 424 | // pass. Similarly, <=7.x is actually <8.0.0, etc.
|
---|
| 425 | gtlt = '<'
|
---|
| 426 | if (xm) {
|
---|
| 427 | M = +M + 1
|
---|
| 428 | } else {
|
---|
| 429 | m = +m + 1
|
---|
| 430 | }
|
---|
| 431 | }
|
---|
| 432 |
|
---|
| 433 | if (gtlt === '<') {
|
---|
| 434 | pr = '-0'
|
---|
| 435 | }
|
---|
| 436 |
|
---|
| 437 | ret = `${gtlt + M}.${m}.${p}${pr}`
|
---|
| 438 | } else if (xm) {
|
---|
| 439 | ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`
|
---|
| 440 | } else if (xp) {
|
---|
| 441 | ret = `>=${M}.${m}.0${pr
|
---|
| 442 | } <${M}.${+m + 1}.0-0`
|
---|
| 443 | }
|
---|
| 444 |
|
---|
| 445 | debug('xRange return', ret)
|
---|
| 446 |
|
---|
| 447 | return ret
|
---|
| 448 | })
|
---|
| 449 | }
|
---|
| 450 |
|
---|
| 451 | // Because * is AND-ed with everything else in the comparator,
|
---|
| 452 | // and '' means "any version", just remove the *s entirely.
|
---|
| 453 | const replaceStars = (comp, options) => {
|
---|
| 454 | debug('replaceStars', comp, options)
|
---|
| 455 | // Looseness is ignored here. star is always as loose as it gets!
|
---|
| 456 | return comp
|
---|
| 457 | .trim()
|
---|
| 458 | .replace(re[t.STAR], '')
|
---|
| 459 | }
|
---|
| 460 |
|
---|
| 461 | const replaceGTE0 = (comp, options) => {
|
---|
| 462 | debug('replaceGTE0', comp, options)
|
---|
| 463 | return comp
|
---|
| 464 | .trim()
|
---|
| 465 | .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '')
|
---|
| 466 | }
|
---|
| 467 |
|
---|
| 468 | // This function is passed to string.replace(re[t.HYPHENRANGE])
|
---|
| 469 | // M, m, patch, prerelease, build
|
---|
| 470 | // 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
|
---|
| 471 | // 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do
|
---|
| 472 | // 1.2 - 3.4 => >=1.2.0 <3.5.0-0
|
---|
| 473 | const hyphenReplace = incPr => ($0,
|
---|
| 474 | from, fM, fm, fp, fpr, fb,
|
---|
| 475 | to, tM, tm, tp, tpr, tb) => {
|
---|
| 476 | if (isX(fM)) {
|
---|
| 477 | from = ''
|
---|
| 478 | } else if (isX(fm)) {
|
---|
| 479 | from = `>=${fM}.0.0${incPr ? '-0' : ''}`
|
---|
| 480 | } else if (isX(fp)) {
|
---|
| 481 | from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}`
|
---|
| 482 | } else if (fpr) {
|
---|
| 483 | from = `>=${from}`
|
---|
| 484 | } else {
|
---|
| 485 | from = `>=${from}${incPr ? '-0' : ''}`
|
---|
| 486 | }
|
---|
| 487 |
|
---|
| 488 | if (isX(tM)) {
|
---|
| 489 | to = ''
|
---|
| 490 | } else if (isX(tm)) {
|
---|
| 491 | to = `<${+tM + 1}.0.0-0`
|
---|
| 492 | } else if (isX(tp)) {
|
---|
| 493 | to = `<${tM}.${+tm + 1}.0-0`
|
---|
| 494 | } else if (tpr) {
|
---|
| 495 | to = `<=${tM}.${tm}.${tp}-${tpr}`
|
---|
| 496 | } else if (incPr) {
|
---|
| 497 | to = `<${tM}.${tm}.${+tp + 1}-0`
|
---|
| 498 | } else {
|
---|
| 499 | to = `<=${to}`
|
---|
| 500 | }
|
---|
| 501 |
|
---|
| 502 | return `${from} ${to}`.trim()
|
---|
| 503 | }
|
---|
| 504 |
|
---|
| 505 | const testSet = (set, version, options) => {
|
---|
| 506 | for (let i = 0; i < set.length; i++) {
|
---|
| 507 | if (!set[i].test(version)) {
|
---|
| 508 | return false
|
---|
| 509 | }
|
---|
| 510 | }
|
---|
| 511 |
|
---|
| 512 | if (version.prerelease.length && !options.includePrerelease) {
|
---|
| 513 | // Find the set of versions that are allowed to have prereleases
|
---|
| 514 | // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
|
---|
| 515 | // That should allow `1.2.3-pr.2` to pass.
|
---|
| 516 | // However, `1.2.4-alpha.notready` should NOT be allowed,
|
---|
| 517 | // even though it's within the range set by the comparators.
|
---|
| 518 | for (let i = 0; i < set.length; i++) {
|
---|
| 519 | debug(set[i].semver)
|
---|
| 520 | if (set[i].semver === Comparator.ANY) {
|
---|
| 521 | continue
|
---|
| 522 | }
|
---|
| 523 |
|
---|
| 524 | if (set[i].semver.prerelease.length > 0) {
|
---|
| 525 | const allowed = set[i].semver
|
---|
| 526 | if (allowed.major === version.major &&
|
---|
| 527 | allowed.minor === version.minor &&
|
---|
| 528 | allowed.patch === version.patch) {
|
---|
| 529 | return true
|
---|
| 530 | }
|
---|
| 531 | }
|
---|
| 532 | }
|
---|
| 533 |
|
---|
| 534 | // Version has a -pre, but it's not one of the ones we like.
|
---|
| 535 | return false
|
---|
| 536 | }
|
---|
| 537 |
|
---|
| 538 | return true
|
---|
| 539 | }
|
---|