Files
npm-node-semver/test/fixtures/range-parse.js
T
dualfroz 2124e4b155 fix: reject loose ranges that collapse to match everything
In loose mode the comparators that fail to parse are filtered out of a
comparator list, and whatever is left becomes the range. When the only
survivor is the any comparator, a typo such as `* (4.1.x  4.1.2)` drops
`(4.1.x` and `4.1.2)` and collapses to the leftover `*`, so the range
silently satisfies every version instead of being rejected. Without
`loose` the same input throws `Invalid comparator: (4.1.x`.

Treat that comparator list as invalid instead, the same way a list with
no valid comparator at all is already treated: the list is dropped, so
other `||` branches still stand on their own and a range left with no
valid branch throws `Invalid SemVer Range`.

Junk sitting next to a comparator that does parse is still tolerated, so
`>=1.2.3 &&&` still yields `>=1.2.3` and `== 1.0.0` still yields
`1.0.0`.

Fixes #387
2026-09-04 22:16:53 +02:00

160 lines
6.7 KiB
JavaScript

'use strict'
// [range, canonical result, options]
// null result means it's not a valid range
// '*' is the return value from functions.validRange(), but
// new Range().range will be '' in those cases
const { MAX_SAFE_INTEGER } = require('../../internal/constants')
module.exports = [
['1.0.0 - 2.0.0', '>=1.0.0 <=2.0.0'],
['1.0.0 - 2.0.0', '>=1.0.0-0 <2.0.1-0', { includePrerelease: true }],
['1 - 2', '>=1.0.0 <3.0.0-0'],
['1 - 2', '>=1.0.0-0 <3.0.0-0', { includePrerelease: true }],
['1.0 - 2.0', '>=1.0.0 <2.1.0-0'],
['1.0 - 2.0', '>=1.0.0-0 <2.1.0-0', { includePrerelease: true }],
['1.0.0', '1.0.0', { loose: false }],
['>=*', '*'],
['', '*'],
['*', '*'],
['>=1.0.0', '>=1.0.0'],
['>1.0.0', '>1.0.0'],
['<=2.0.0', '<=2.0.0'],
['1', '>=1.0.0 <2.0.0-0'],
['<2.0.0', '<2.0.0'],
['>= 1.0.0', '>=1.0.0'],
['>= 1.0.0', '>=1.0.0'],
['>= 1.0.0', '>=1.0.0'],
['> 1.0.0', '>1.0.0'],
['> 1.0.0', '>1.0.0'],
['<= 2.0.0', '<=2.0.0'],
['<= 2.0.0', '<=2.0.0'],
['<= 2.0.0', '<=2.0.0'],
['< 2.0.0', '<2.0.0'],
['<\t2.0.0', '<2.0.0'],
['>=0.1.97', '>=0.1.97'],
['0.1.20 || 1.2.4', '0.1.20||1.2.4'],
['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1'],
['||', '*'],
['2.x.x', '>=2.0.0 <3.0.0-0'],
['1.2.x', '>=1.2.0 <1.3.0-0'],
['1.2.x || 2.x', '>=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0'],
['1.x.5', null],
['1.*.5', null],
['1.x.5 || 2.x', null],
['x.1', null],
['x.1.2', null],
['x.x.1', null],
['x', '*'],
['2.*.*', '>=2.0.0 <3.0.0-0'],
['1.2.*', '>=1.2.0 <1.3.0-0'],
['1.2.* || 2.*', '>=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0'],
['2', '>=2.0.0 <3.0.0-0'],
['2.3', '>=2.3.0 <2.4.0-0'],
['~2.4', '>=2.4.0 <2.5.0-0'],
['~>3.2.1', '>=3.2.1 <3.3.0-0'],
['~1', '>=1.0.0 <2.0.0-0'],
['~>1', '>=1.0.0 <2.0.0-0'],
['~> 1', '>=1.0.0 <2.0.0-0'],
['~1.0', '>=1.0.0 <1.1.0-0'],
['~ 1.0', '>=1.0.0 <1.1.0-0'],
// tilde with includePrerelease must lower-bound at -0 just like the
// equivalent x-range (e.g. ~1.2 is documented as the same as 1.2.x),
// so that prereleases such as 1.2.0-rc match. See #512.
['~1', '>=1.0.0-0 <2.0.0-0', { includePrerelease: true }],
['~1.x', '>=1.0.0-0 <2.0.0-0', { includePrerelease: true }],
['~1.2', '>=1.2.0-0 <1.3.0-0', { includePrerelease: true }],
['~1.2.x', '>=1.2.0-0 <1.3.0-0', { includePrerelease: true }],
['~0.0', '<0.1.0-0', { includePrerelease: true }],
// a fully-specified tilde keeps its exact lower bound (matches caret),
// and an explicit prerelease is preserved as-is
['~1.2.3', '>=1.2.3 <1.3.0-0', { includePrerelease: true }],
['~1.2.3-beta.4', '>=1.2.3-beta.4 <1.3.0-0', { includePrerelease: true }],
['^0', '<1.0.0-0'],
['^ 1', '>=1.0.0 <2.0.0-0'],
['^0.1', '>=0.1.0 <0.2.0-0'],
['^1.0', '>=1.0.0 <2.0.0-0'],
['^1.2', '>=1.2.0 <2.0.0-0'],
['^0.0.1', '>=0.0.1 <0.0.2-0'],
['^0.0.1-beta', '>=0.0.1-beta <0.0.2-0'],
['^0.1.2', '>=0.1.2 <0.2.0-0'],
['^1.2.3', '>=1.2.3 <2.0.0-0'],
['^1.2.3-beta.4', '>=1.2.3-beta.4 <2.0.0-0'],
['<1', '<1.0.0-0'],
['< 1', '<1.0.0-0'],
['>=1', '>=1.0.0'],
['>= 1', '>=1.0.0'],
['<1.2', '<1.2.0-0'],
['< 1.2', '<1.2.0-0'],
['>01.02.03', '>1.2.3', true],
['>01.02.03', null],
['~1.2.3beta', '>=1.2.3-beta <1.3.0-0', { loose: true }],
['~1.2.3beta', null],
['^ 1.2 ^ 1', '>=1.2.0 <2.0.0-0 >=1.0.0'],
['1.2 - 3.4.5', '>=1.2.0 <=3.4.5'],
['1.2.3 - 3.4', '>=1.2.3 <3.5.0-0'],
['1.2 - 3.4', '>=1.2.0 <3.5.0-0'],
['>1', '>=2.0.0'],
['>1.2', '>=1.3.0'],
['>X', '<0.0.0-0'],
['<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 }],
[`^${MAX_SAFE_INTEGER}.0.0`, null],
[`=${MAX_SAFE_INTEGER}.0.0`, `${MAX_SAFE_INTEGER}.0.0`],
[`^${MAX_SAFE_INTEGER - 1}.0.0`, `>=${MAX_SAFE_INTEGER - 1}.0.0 <${MAX_SAFE_INTEGER}.0.0-0`],
// x-ranges with build metadata
['1.x.x+build >2.x+build', '>=1.0.0 <2.0.0-0 >=3.0.0', null],
['>=1.x+build <2.x.x+build', '>=1.0.0 <2.0.0-0', null],
['1.x.x+build || 2.x.x+build', '>=1.0.0 <2.0.0-0||>=2.0.0 <3.0.0-0', null],
['1.x+build.123', '>=1.0.0 <2.0.0-0', null],
['1.x.x+meta-data', '>=1.0.0 <2.0.0-0', null],
['1.x.x+build.123 >2.x.x+meta-data', '>=1.0.0 <2.0.0-0 >=3.0.0', null],
['1.x.x+build <2.x.x+meta', '>=1.0.0 <2.0.0-0', null],
['>1.x+build <=2.x.x+meta', '>=2.0.0 <3.0.0-0', null],
[' 1.x.x+build >2.x.x+build ', '>=1.0.0 <2.0.0-0 >=3.0.0', null],
['^1.x+build', '>=1.0.0 <2.0.0-0', null],
['^1.x.x+build', '>=1.0.0 <2.0.0-0', null],
['^1.2.x+build', '>=1.2.0 <2.0.0-0', null],
['^1.x+meta-data', '>=1.0.0 <2.0.0-0', null],
['^1.x.x+build.123', '>=1.0.0 <2.0.0-0', null],
['~1.x+build', '>=1.0.0 <2.0.0-0', null],
['~1.x.x+build', '>=1.0.0 <2.0.0-0', null],
['~1.2.x+build', '>=1.2.0 <1.3.0-0', null],
['~1.x+meta-data', '>=1.0.0 <2.0.0-0', null],
['~1.x.x+build.123', '>=1.0.0 <2.0.0-0', null],
['^1.x.x+build || ~2.x.x+meta', '>=1.0.0 <2.0.0-0||>=2.0.0 <3.0.0-0', null],
['~1.x.x+build >2.x+meta', '>=1.0.0 <2.0.0-0 >=3.0.0', null],
['^1.x+build.123 <2.x.x+meta-data', '>=1.0.0 <2.0.0-0', null],
// // x-ranges with prerelease and build
['1.x.x-alpha+build', '>=1.0.0 <2.0.0-0', null],
['>1.x.x-alpha+build', '>=2.0.0', null],
['>=1.x.x-alpha+build <2.x.x+build', '>=1.0.0 <2.0.0-0', null],
['1.x.x-alpha+build || 2.x.x+build', '>=1.0.0 <2.0.0-0||>=2.0.0 <3.0.0-0', null],
// long build metadata must be stripped, not bled into the version
['4.17.0+' + 'a'.repeat(250) + '3', '4.17.0', { loose: true }],
['4.17.0+' + 'a'.repeat(251), '4.17.0', { loose: true }],
['v1.0+' + 'a'.repeat(249) + 'x6', '>=1.0.0 <1.1.0-0', null],
['1.2.3+' + 'a'.repeat(251) + ' - 2.0.0', '>=1.2.3 <=2.0.0', null],
['1.2.3+' + 'a'.repeat(251) + ' - 2.0.0', '>=1.2.3 <=2.0.0', { loose: true }],
['> 1.2.3+' + 'a'.repeat(251), '>1.2.3', null],
['>= 1.2.3+' + 'a'.repeat(251), '>=1.2.3', { loose: true }],
['~1.2.3+' + 'a'.repeat(251), '>=1.2.3 <1.3.0-0', null],
['^1.2.3+' + 'a'.repeat(251), '>=1.2.3 <2.0.0-0', null],
['1.2.3+sha512.' + 'a'.repeat(251), '1.2.3', { loose: true }],
['1.2.3+sha256.' + 'a'.repeat(200) + '.' + 'b'.repeat(200), '1.2.3', { loose: true }],
['1.2.3+' + 'a'.repeat(251) + ' || 2.0.0+' + 'b'.repeat(251),
'1.2.3||2.0.0', { loose: true }],
// dropping unparseable comparators must not leave a match-everything range
['* (4.1.x 4.1.2)', null],
['* (4.1.x 4.1.2)', null, { loose: true }],
['* (foo)', null, { loose: true }],
// but loose mode still tolerates junk next to a real comparator, and still
// tolerates a `||` branch that is invalid as a whole
['>=1.2.3 &&&', '>=1.2.3', { loose: true }],
['1.2.3 || (foo)', '1.2.3', { loose: true }],
]