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