mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-25 06:51:11 +00:00
6a1a69c3ef
* feat(versioning): comparator ranges for the regex scheme The regex versioning orders versions by the release array built from its captured groups (major, minor, patch, build, revision) but matches every range by exact equality, so a comparator range in `allowedVersions` (`<=1.2.3` and friends) never resolves against a regex-versioned dependency. Add a scheme-independent comparator parser (`generic-range.ts`) and wire it into the regex scheme's `isValid`/`matches`/`getSatisfyingVersion`/ `minSatisfyingVersion`, evaluating each `<`, `<=`, `>`, `>=`, `=`, `==` term through the scheme's own `_compare`. A pattern that captures a `-ee.N` suffix as an ordered `build` component then resolves `<=X-ee.0` correctly, where npm `semver` cannot: as a prerelease the suffix breaks the range, as build metadata it is ignored, and a four-part release is not valid semver. The parser defers operand validation and comparison to the caller, so it stays independent of npm `semver` (used by the semver family) and consistent with the scheme's own ordering. Dependency values stay exact tags, so `supportsRanges` remains `false`. * test(versioning): cover regex ordering by capture-group name, not position Add a calendar-versioning case (`YYYY.DD.MM`) showing comparison follows the `major`/`minor`/`patch` capture-group names in precedence order, not their left-to-right position: naming the month `minor` and the day `patch` sorts by year, then month, then day even though the day is the middle field. Also reword the readme, which described this as "the same capture-group ordering" and read as positional, to state the major/minor/patch precedence explicitly. * refactor(versioning): declare RangeComparator in types.ts The `renovate/types-location` rule requires an exported type to live in a colocated `types.ts`, so `RangeComparator` is declared there and `generic-range.ts` imports it.
65 lines
2.0 KiB
TypeScript
65 lines
2.0 KiB
TypeScript
import { isNonEmptyString } from '@sindresorhus/is';
|
|
import { regEx } from '../../util/regex.ts';
|
|
import type { RangeComparator } from './types.ts';
|
|
|
|
// Comparator operators, longest first so `<=` is matched ahead of `<`, `>=`
|
|
// ahead of `>`, and `==` ahead of `=`.
|
|
const operators = ['<=', '>=', '==', '<', '>', '='];
|
|
const separator = regEx(/[\s,]+/);
|
|
|
|
/**
|
|
* Parse a comparator range (for example `<=1.2.3`, `>1.0 <2.0`, or `=1.2.3`)
|
|
* into its `{ operator, version }` terms, which are ANDed together. Returns
|
|
* `null` when the input is not a comparator range (such as a bare version), so
|
|
* callers can fall back to treating it as a version.
|
|
*
|
|
* The `isVersion` predicate validates each operand against the caller's own
|
|
* version format and the caller compares with its own ordering, so this parser
|
|
* stays independent of any single versioning scheme (unlike npm `semver`,
|
|
* whose parser also coerces and normalizes the operands).
|
|
*/
|
|
export function parseRange(
|
|
range: string,
|
|
isVersion: (version: string) => boolean,
|
|
): RangeComparator[] | null {
|
|
if (!isNonEmptyString(range)) {
|
|
return null;
|
|
}
|
|
const comparators: RangeComparator[] = [];
|
|
for (const term of range.trim().split(separator)) {
|
|
const operator = operators.find((op) => term.startsWith(op));
|
|
if (!operator) {
|
|
return null;
|
|
}
|
|
const version = term.slice(operator.length);
|
|
if (!isVersion(version)) {
|
|
return null;
|
|
}
|
|
comparators.push({ operator, version });
|
|
}
|
|
return comparators;
|
|
}
|
|
|
|
/**
|
|
* Given the result of comparing a version against a comparator's version
|
|
* (negative when lower, zero when equal, positive when higher), return whether
|
|
* the comparator's operator is satisfied.
|
|
*/
|
|
export function satisfiesComparator(
|
|
comparison: number,
|
|
operator: string,
|
|
): boolean {
|
|
switch (operator) {
|
|
case '<':
|
|
return comparison < 0;
|
|
case '<=':
|
|
return comparison <= 0;
|
|
case '>':
|
|
return comparison > 0;
|
|
case '>=':
|
|
return comparison >= 0;
|
|
default:
|
|
return comparison === 0;
|
|
}
|
|
}
|