Skip to content

Commit

Permalink
fix: properly escape dots in GTE0 regexes (#432)
Browse files Browse the repository at this point in the history
Previously the dots were not properly escaped causing them to match any
character. This caused ranges like `>=09090` to evaulate to `*` after
they were incorrectly matched by the `GTE0` regex. This only happened in
strict mode since in loose mode the leading 0 is allowed and parsed into
`>=9090.0.0` before the `GTE0` check. After this fix, this range now
will throw an error. This also affected prerelease versions in both
strict and loose mode.
  • Loading branch information
lukekarrys committed Mar 25, 2022
1 parent 9ab7b71 commit 11494f1
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 13 deletions.
19 changes: 12 additions & 7 deletions classes/range.js
Expand Up @@ -94,7 +94,7 @@ class Range {
debug('hyphen replace', range)
// `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
debug('comparator trim', range, re[t.COMPARATORTRIM])
debug('comparator trim', range)

// `~ 1.2.3` => `~1.2.3`
range = range.replace(re[t.TILDETRIM], tildeTrimReplace)
Expand All @@ -108,24 +108,29 @@ class Range {
// At this point, the range is completely trimmed and
// ready to be split into comparators.

const compRe = loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
const rangeList = range
let rangeList = range
.split(' ')
.map(comp => parseComparator(comp, this.options))
.join(' ')
.split(/\s+/)
// >=0.0.0 is equivalent to *
.map(comp => replaceGTE0(comp, this.options))

if (loose) {
// in loose mode, throw out any that are not valid comparators
.filter(this.options.loose ? comp => !!comp.match(compRe) : () => true)
.map(comp => new Comparator(comp, this.options))
rangeList = rangeList.filter(comp => {
debug('loose invalid filter', comp, this.options)
return !!comp.match(re[t.COMPARATORLOOSE])
})
}
debug('range list', rangeList)

// if any comparators are the null set, then replace with JUST null set
// if more than one comparator, remove any * comparators
// also, don't include the same comparator more than once
const l = rangeList.length
const rangeMap = new Map()
for (const comp of rangeList) {
const comparators = rangeList.map(comp => new Comparator(comp, this.options))
for (const comp of comparators) {
if (isNullSet(comp))
return [comp]
rangeMap.set(comp.value, comp)
Expand Down
6 changes: 3 additions & 3 deletions internal/re.js
Expand Up @@ -10,7 +10,7 @@ let R = 0

const createToken = (name, value, isGlobal) => {
const index = R++
debug(index, value)
debug(name, index, value)
t[name] = index
src[index] = value
re[index] = new RegExp(value, isGlobal ? 'g' : undefined)
Expand Down Expand Up @@ -178,5 +178,5 @@ createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` +
// Star ranges basically just allow anything at all.
createToken('STAR', '(<|>)?=?\\s*\\*')
// >=0.0.0 is like a star
createToken('GTE0', '^\\s*>=\\s*0\.0\.0\\s*$')
createToken('GTE0PRE', '^\\s*>=\\s*0\.0\.0-0\\s*$')
createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$')
createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$')
4 changes: 2 additions & 2 deletions test/classes/range.js
Expand Up @@ -17,9 +17,9 @@ test('range tests', t => {

test('range parsing', t => {
t.plan(rangeParse.length)
rangeParse.forEach(([range, expect, options]) => t.test(`${range} ${expect}`, t => {
rangeParse.forEach(([range, expect, options]) => t.test(`${range} ${expect} ${JSON.stringify(options)}`, t => {
if (expect === null)
t.throws(() => new Range(range), TypeError, `invalid range: ${range}`)
t.throws(() => new Range(range, options), TypeError, `invalid range: ${range} ${JSON.stringify(options)}`)
else {
t.equal(new Range(range, options).range || '*', expect,
`${range} => ${expect}`)
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/range-parse.js
Expand Up @@ -89,4 +89,8 @@ module.exports = [
['<X', '<0.0.0-0'],
['<x <* || >* 2.x', '<0.0.0-0'],
['>x 2.x || * || <x', '*'],
['>=09090', null],
['>=09090', '>=9090.0.0', true],
['>=09090-0', null, { includePrerelease: true }],
['>=09090-0', null, { loose: true, includePrerelease: true }],
]
2 changes: 1 addition & 1 deletion test/ranges/valid.js
Expand Up @@ -8,5 +8,5 @@ test('valid range test', (t) => {
t.plan(rangeParse.length)
rangeParse.forEach(([pre, wanted, options]) =>
t.equal(validRange(pre, options), wanted,
`validRange(${pre}) === ${wanted}`))
`validRange(${pre}) === ${wanted} ${JSON.stringify(options)}`))
})

0 comments on commit 11494f1

Please sign in to comment.