improve parseRange, add test cases

- parse "NaN" as string part
- allow more whitespaces in hyphen
This commit is contained in:
Ivan Kopeykin 2022-02-01 10:54:38 +03:00
parent 1ab1d0104c
commit 3b55455b26
2 changed files with 20 additions and 16 deletions

View File

@ -89,7 +89,9 @@ exports.versionLt = versionLt;
*/ */
exports.parseRange = str => { exports.parseRange = str => {
const splitAndConvert = str => { const splitAndConvert = str => {
return str.split(".").map(item => (`${+item}` === item ? +item : item)); return str
.split(".")
.map(item => (item !== "NaN" && `${+item}` === item ? +item : item));
}; };
// see https://docs.npmjs.com/misc/semver#range-grammar for grammar // see https://docs.npmjs.com/misc/semver#range-grammar for grammar
const parsePartial = str => { const parsePartial = str => {
@ -131,13 +133,15 @@ exports.parseRange = str => {
return [-range[0] - 1, ...range.slice(1)]; return [-range[0] - 1, ...range.slice(1)];
}; };
const parseSimple = str => { const parseSimple = str => {
// simple ::= primitive | partial | tilde | caret // simple ::= primitive | partial | tilde | caret
// primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial // primitive ::= ( '<' | '>' | '>=' | '<=' | '=' | '!' ) ( ' ' ) * partial
// tilde ::= '~' partial // tilde ::= '~' ( ' ' ) * partial
// caret ::= '^' partial // caret ::= '^' ( ' ' ) * partial
const match = /^(\^|~|<=|<|>=|>|=|v|!)/.exec(str); const match = /^(\^|~|<=|<|>=|>|=|v|!)/.exec(str);
const start = match ? match[0] : ""; const start = match ? match[0] : "";
const remainder = parsePartial(str.slice(start.length)); const remainder = parsePartial(
start.length ? str.slice(start.length).trim() : str.trim()
);
switch (start) { switch (start) {
case "^": case "^":
if (remainder.length > 1 && remainder[1] === 0) { if (remainder.length > 1 && remainder[1] === 0) {
@ -190,18 +194,14 @@ exports.parseRange = str => {
// eslint-disable-next-line no-sparse-arrays // eslint-disable-next-line no-sparse-arrays
return [, ...arr, ...items.slice(1).map(() => fn)]; return [, ...arr, ...items.slice(1).map(() => fn)];
}; };
// remove whitespace characters after ^, ~, <=, <, >=, >, =
const trimRangeOperators = str => {
return str.replace(/(\^|~|<=|<|>=|>|=)\s*/g, "$1");
};
const parseRange = str => { const parseRange = str => {
// range ::= hyphen | simple ( ' ' simple ) * | '' // range ::= hyphen | simple ( ' ' ( ' ' ) * simple ) * | ''
// hyphen ::= partial ' - ' partial // hyphen ::= partial ( ' ' ) * ' - ' ( ' ' ) * partial
const items = str.split(" - "); const items = str.split(/\s+-\s+/);
if (items.length === 1) { if (items.length === 1) {
const items = trimRangeOperators(str) const items = str
.trim() .trim()
.split(/\s+/g) .split(/(?<=[-0-9A-Za-z])\s+/g)
.map(parseSimple); .map(parseSimple);
return combine(items, 2); return combine(items, 2);
} }

View File

@ -129,6 +129,8 @@ describe("SemVer", () => {
describe("parseRange", () => { describe("parseRange", () => {
const cases = { const cases = {
"5 || 6 || 7.x.x": ["5.x.x || 6.x || 7"],
"1 - 2": ["1 - 2"],
"=3": [ "=3": [
"3", "3",
"v3", "v3",
@ -145,7 +147,9 @@ describe("SemVer", () => {
"^3.4": ["^3.4.*", "^ 3.4"], "^3.4": ["^3.4.*", "^ 3.4"],
"3.4 - 6.5": [">=3.4 <=6.5", ">= 3.4 <= 6.5"], "3.4 - 6.5": [">=3.4 <=6.5", ">= 3.4 <= 6.5"],
"<=3.4": ["<3.4 || =3.4", "<= 3.4"], "<=3.4": ["<3.4 || =3.4", "<= 3.4"],
">3.4": [">=3.4 !3.4", "> 3.4"] ">3.4": [">=3.4 !3.4", "> 3.4"],
"1.2.3-alpha.x.x": ["1.2.3-alpha", "1.2.3-alpha+build.25"],
"1.2.3-NaN": ["1.2.3-NaN"]
}; };
for (const key of Object.keys(cases)) { for (const key of Object.keys(cases)) {
describe(key, () => { describe(key, () => {