mirror of
https://github.com/denoland/std.git
synced 2024-11-22 04:59:05 +00:00
refactor(semver): use capturing groups in parseComparator()
(#4026)
This commit is contained in:
parent
9a0a21d604
commit
27c3c0257d
@ -119,7 +119,7 @@ const FULL_PLAIN = `v?${MAIN_VERSION}${PRERELEASE}?${BUILD}?`;
|
||||
|
||||
export const FULL_REGEXP = new RegExp(`^${FULL_PLAIN}$`);
|
||||
|
||||
const COMPARATOR = "((?:<|>)?=?)";
|
||||
const COMPARATOR = "(?:<|>)?=?";
|
||||
|
||||
// Something like "2.*" or "1.2.x".
|
||||
// Note that "x.x" is a valid xRange identifier, meaning "any version"
|
||||
@ -130,7 +130,7 @@ export const XRANGE_PLAIN =
|
||||
`[v=\\s]*(?<major>${XRANGE_IDENTIFIER})(?:\\.(?<minor>${XRANGE_IDENTIFIER})(?:\\.(?<patch>${XRANGE_IDENTIFIER})(?:${PRERELEASE})?${BUILD}?)?)?`;
|
||||
|
||||
export const XRANGE_REGEXP = new RegExp(
|
||||
`^${COMPARATOR}\\s*${XRANGE_PLAIN}$`,
|
||||
`^(?<operator>${COMPARATOR})\\s*${XRANGE_PLAIN}$`,
|
||||
);
|
||||
|
||||
// Tilde ranges.
|
||||
@ -143,7 +143,7 @@ export const CARET_REGEXP = new RegExp(`^(?<operator>\\^)${XRANGE_PLAIN}$`);
|
||||
|
||||
// A simple gt/lt/eq thing, or just "" to indicate "any version"
|
||||
export const COMPARATOR_REGEXP = new RegExp(
|
||||
`^${COMPARATOR}\\s*(${FULL_PLAIN})$|^$`,
|
||||
`^(?<operator>${COMPARATOR})\\s*(${FULL_PLAIN})$|^$`,
|
||||
);
|
||||
|
||||
// Star ranges basically just allow anything at all.
|
||||
@ -209,3 +209,30 @@ export const operators = [
|
||||
export function isOperator(value: unknown): value is Operator {
|
||||
return operators.includes(value as Operator);
|
||||
}
|
||||
|
||||
const NUMERIC_IDENTIFIER_REGEXP = new RegExp(`^(${NUMERIC_IDENTIFIER})$`);
|
||||
export function parsePrerelease(prerelease: string) {
|
||||
return prerelease
|
||||
.split(".")
|
||||
.filter((id) => id)
|
||||
.map((id: string) => {
|
||||
const num = parseInt(id);
|
||||
if (id.match(NUMERIC_IDENTIFIER_REGEXP) && isValidNumber(num)) {
|
||||
return num;
|
||||
} else {
|
||||
return id;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function parseBuild(buildmetadata: string) {
|
||||
return buildmetadata.split(".").filter((m) => m) ?? [];
|
||||
}
|
||||
|
||||
export function parseNumber(input: string, errorMessage: string) {
|
||||
const number = Number(input);
|
||||
if (number > Number.MAX_SAFE_INTEGER || number < 0) {
|
||||
throw new TypeError(errorMessage);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { SemVer } from "./types.ts";
|
||||
import { isValidNumber } from "./_shared.ts";
|
||||
import { parseBuild, parseNumber, parsePrerelease } from "./_shared.ts";
|
||||
import { isSemVer } from "./is_semver.ts";
|
||||
import { FULL_REGEXP, MAX_LENGTH } from "./_shared.ts";
|
||||
|
||||
@ -40,38 +40,15 @@ export function parse(version: string | SemVer): SemVer {
|
||||
const groups = version.match(FULL_REGEXP)?.groups;
|
||||
if (!groups) throw new TypeError(`Invalid Version: ${version}`);
|
||||
|
||||
// these are actually numbers
|
||||
const major = parseInt(groups.major);
|
||||
const minor = parseInt(groups.minor);
|
||||
const patch = parseInt(groups.patch);
|
||||
const major = parseNumber(groups.major, "Invalid major version");
|
||||
const minor = parseNumber(groups.minor, "Invalid minor version");
|
||||
const patch = parseNumber(groups.patch, "Invalid patch version");
|
||||
|
||||
if (major > Number.MAX_SAFE_INTEGER || major < 0) {
|
||||
throw new TypeError("Invalid major version");
|
||||
}
|
||||
const prerelease = groups.prerelease
|
||||
? parsePrerelease(groups.prerelease)
|
||||
: [];
|
||||
const build = groups.buildmetadata ? parseBuild(groups.buildmetadata) : [];
|
||||
|
||||
if (minor > Number.MAX_SAFE_INTEGER || minor < 0) {
|
||||
throw new TypeError("Invalid minor version");
|
||||
}
|
||||
|
||||
if (patch > Number.MAX_SAFE_INTEGER || patch < 0) {
|
||||
throw new TypeError("Invalid patch version");
|
||||
}
|
||||
|
||||
// number-ify any prerelease numeric ids
|
||||
const numericIdentifier = new RegExp(`^(0|[1-9]\\d*)$`);
|
||||
const prerelease = (groups.prerelease ?? "")
|
||||
.split(".")
|
||||
.filter((id) => id)
|
||||
.map((id: string) => {
|
||||
const num = parseInt(id);
|
||||
if (id.match(numericIdentifier) && isValidNumber(num)) {
|
||||
return num;
|
||||
} else {
|
||||
return id;
|
||||
}
|
||||
});
|
||||
|
||||
const build = groups.buildmetadata?.split(".")?.filter((m) => m) ?? [];
|
||||
return {
|
||||
major,
|
||||
minor,
|
||||
|
@ -1,26 +1,54 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { parse } from "./parse.ts";
|
||||
import type { Operator, SemVerComparator } from "./types.ts";
|
||||
import { COMPARATOR_REGEXP } from "./_shared.ts";
|
||||
import {
|
||||
COMPARATOR_REGEXP,
|
||||
parseBuild,
|
||||
parseNumber,
|
||||
parsePrerelease,
|
||||
} from "./_shared.ts";
|
||||
import { comparatorMin } from "./comparator_min.ts";
|
||||
import { comparatorMax } from "./comparator_max.ts";
|
||||
import { ANY, NONE } from "./constants.ts";
|
||||
|
||||
type REGEXP_GROUPS = {
|
||||
operator: Operator;
|
||||
major: string;
|
||||
minor: string;
|
||||
patch: string;
|
||||
prerelease: string;
|
||||
buildmetadata: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses a comparator string into a valid SemVerComparator.
|
||||
* @param comparator
|
||||
* @returns A valid SemVerComparator
|
||||
*/
|
||||
export function parseComparator(comparator: string): SemVerComparator {
|
||||
const m = comparator.match(COMPARATOR_REGEXP);
|
||||
const match = comparator.match(COMPARATOR_REGEXP);
|
||||
const groups = match?.groups;
|
||||
|
||||
if (!m) {
|
||||
return NONE;
|
||||
}
|
||||
if (!groups) return NONE;
|
||||
|
||||
const {
|
||||
operator = "",
|
||||
|
||||
prerelease,
|
||||
buildmetadata,
|
||||
} = groups as REGEXP_GROUPS;
|
||||
|
||||
const semver = groups.major
|
||||
? {
|
||||
major: parseNumber(groups.major, "Invalid major version"),
|
||||
minor: parseNumber(groups.minor, "Invalid minor version"),
|
||||
patch: parseNumber(groups.patch, "Invalid patch version"),
|
||||
prerelease: prerelease ? parsePrerelease(prerelease) : [],
|
||||
build: buildmetadata ? parseBuild(buildmetadata) : [],
|
||||
}
|
||||
: ANY;
|
||||
|
||||
const operator = (m[1] ?? "") as Operator;
|
||||
const semver = m[2] ? parse(m[2]) : ANY;
|
||||
const min = comparatorMin(semver, operator);
|
||||
const max = comparatorMax(semver, operator);
|
||||
|
||||
return { operator, semver, min, max };
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user