fix(semver): throw on invalid input in parseRange() (#5567)

* fix(semver): throw on invalid input in `parseRange()`

* fix

* fix

* fix
This commit is contained in:
Asher Gomez 2024-07-30 12:31:20 +10:00 committed by GitHub
parent b064ee1212
commit 3a446538b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 24 additions and 43 deletions

View File

@ -57,14 +57,6 @@ export const ALL: Comparator = {
...ANY,
};
/**
* A comparator which will not span any semantic versions
*/
export const NONE: Comparator = {
operator: "<",
...MIN,
};
export const OPERATORS = [
undefined,
"=",

View File

@ -2,7 +2,7 @@
// This module is browser compatible.
import type { Comparator, Range } from "./types.ts";
import { OPERATORS } from "./_constants.ts";
import { ALL, NONE } from "./_constants.ts";
import { ALL } from "./_constants.ts";
import { isSemVer } from "./is_semver.ts";
function isComparator(value: unknown): value is Comparator {
@ -10,7 +10,7 @@ function isComparator(value: unknown): value is Comparator {
value === null || value === undefined || Array.isArray(value) ||
typeof value !== "object"
) return false;
if (value === NONE || value === ALL) return true;
if (value === ALL) return true;
const { operator } = value as Comparator;
return (
(operator === undefined ||

View File

@ -4,7 +4,6 @@ import { assertEquals } from "@std/assert";
import { parse } from "./parse.ts";
import { parseRange } from "./parse_range.ts";
import { maxSatisfying } from "./max_satisfying.ts";
import { MAX, MIN } from "./_constants.ts";
Deno.test({
name: "maxSatisfying()",
@ -26,8 +25,3 @@ Deno.test({
}
},
});
Deno.test("minSatisfying() handles bad ranges", function () {
const r = parseRange("some frogs and sneks-v2.5.6");
assertEquals(maxSatisfying([MIN, MAX], r), undefined);
});

View File

@ -4,7 +4,6 @@ import { assertEquals } from "@std/assert";
import { parse } from "./parse.ts";
import { parseRange } from "./parse_range.ts";
import { minSatisfying } from "./min_satisfying.ts";
import { MAX, MIN } from "./_constants.ts";
Deno.test("minSatisfying()", async (t) => {
const versions: [string[], string, string][] = [
@ -23,8 +22,3 @@ Deno.test("minSatisfying()", async (t) => {
});
}
});
Deno.test("minSatisfying() handles bad ranges", function () {
const r = parseRange("some frogs and sneks-v2.5.6");
assertEquals(minSatisfying([MIN, MAX], r), undefined);
});

View File

@ -9,7 +9,7 @@ import {
parsePrerelease,
XRANGE,
} from "./_shared.ts";
import { ALL, ANY, NONE } from "./_constants.ts";
import { ALL, ANY } from "./_constants.ts";
import type { Comparator, Operator, Range } from "./types.ts";
type ComparatorRegExpGroup = {
@ -21,11 +21,11 @@ type ComparatorRegExpGroup = {
buildmetadata: string;
};
function parseComparator(comparator: string): Comparator {
function parseComparator(comparator: string): Comparator | null {
const match = comparator.match(COMPARATOR_REGEXP);
const groups = match?.groups;
if (!groups) return NONE;
if (!groups) return null;
const { operator, prerelease, buildmetadata } =
groups as ComparatorRegExpGroup;
@ -349,7 +349,7 @@ function handleEqualOperator(groups: RangeRegExpGroups): Comparator[] {
return [{ operator: undefined, major, minor, patch, prerelease, build }];
}
function parseOperatorRange(string: string): Comparator | Comparator[] {
function parseOperatorRange(string: string): Comparator | Comparator[] | null {
const groups = string.match(OPERATOR_XRANGE_REGEXP)
?.groups as RangeRegExpGroups;
if (!groups) return parseComparator(string);
@ -375,7 +375,7 @@ function parseOperatorRange(string: string): Comparator | Comparator[] {
throw new Error(`'${groups.operator}' is not a valid operator.`);
}
}
function parseOperatorRanges(string: string): Comparator[] {
function parseOperatorRanges(string: string): (Comparator | null)[] {
return string.split(/\s+/).flatMap(parseOperatorRange);
}
@ -404,9 +404,13 @@ function parseOperatorRanges(string: string): Comparator[] {
* @returns A valid SemVer range
*/
export function parseRange(range: string): Range {
return range
const result = range
// remove spaces between operators and versions
.replaceAll(/(?<=<|>|=|~) +/g, "")
.replaceAll(/(?<=<|>|=|~|\^)(\s+)/g, "")
.split(/\s*\|\|\s*/)
.map((string) => parseHyphenRange(string) || parseOperatorRanges(string));
if (result.some((r) => r.includes(null))) {
throw new TypeError(`Invalid range: ${range}`);
}
return result as Range;
}

View File

@ -1,6 +1,6 @@
// Copyright Isaac Z. Schlueter and Contributors. All rights reserved. ISC license.
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "@std/assert";
import { assertEquals, assertThrows } from "@std/assert";
import { parseRange } from "./parse_range.ts";
import type { Range } from "./types.ts";
@ -351,18 +351,6 @@ Deno.test("parseRange() parse ranges of different kinds", () => {
{ operator: "<", major: 0, minor: 0, patch: 2 },
],
]],
["blerg", [
[
{
operator: "<",
major: 0,
minor: 0,
patch: 0,
prerelease: [],
build: [],
},
],
]],
["^1.2.3", [
[
{ operator: ">=", major: 1, minor: 2, patch: 3, prerelease: [] },
@ -585,6 +573,12 @@ Deno.test("parseRanges() parses ranges with tilde", () => {
Deno.test("parseRange() parses ranges with caret", () => {
const ranges: [string, Range][] = [
["^1.2.3", [
[
{ operator: ">=", major: 1, minor: 2, patch: 3, prerelease: [] },
{ operator: "<", major: 2, minor: 0, patch: 0 },
],
]],
["^ 1.2.3", [
[
{ operator: ">=", major: 1, minor: 2, patch: 3, prerelease: [] },
@ -664,3 +658,7 @@ Deno.test("parseRange() parses ranges with caret", () => {
assertEquals(range, expected);
}
});
Deno.test("parseRange() throws on invalid range", () => {
assertThrows(() => parseRange("blerg"), TypeError, "Invalid range: blerg");
});

View File

@ -269,7 +269,6 @@ Deno.test({
["<=1.2.3", "1.2.3-beta"],
// invalid ranges never satisfied!
["blerg", "1.2.3"],
["^1.2.3", "2.0.0-pre"],
["1.0.0 - 2.0.0", "0.0.0"],