mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-26 15:31:53 +00:00
16ef1715e9
* feat(lint): add renovate/prefer-is-helpers and renovate/prefer-is-object rules Flag ad-hoc type checks that have @sindresorhus/is equivalents: - .filter(Boolean) -> .filter(isTruthy) - typeof x === 'string' -> isString(x) - x === null || x === undefined -> isNullOrUndefined(x) (and negation) The typeof x === 'object' shape lives in a separate suggestion-only rule (renovate/prefer-is-object, kept at warn) because isObject()/isPlainObject() are not drop-in equivalents: null, arrays and functions behave differently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: fix renovate/prefer-is-helpers violations Replace ad-hoc type checks with @sindresorhus/is helpers across lib/: - 13x .filter(Boolean) -> .filter(isTruthy) - 36x typeof x ==/!== 'string' -> isString(x) / !isString(x) - 6x x === null || x === undefined -> isNullOrUndefined(x) (and negation) Promote renovate/prefer-is-helpers to error now that the codebase is clean. renovate/prefer-is-object stays at warn: its 15 remaining sites guard parsed YAML/JSON or unknown values where isObject()/isPlainObject() are not provably equivalent (null/array/function semantics). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: enforce renovate/prefer-is-object at error level Resolve the 15 remaining warnings and raise the rule from warn to error: - Migrate 10 sites to isObject() where the guarded value provably cannot be a function (parsed YAML/JSON, typed exec command arguments, or test-controlled fixtures): helm-values, woodpecker, bun, pre-commit managers, exec utils, file package cache, and the github http spec. In the bun manager this also fixes a latent crash where a null `workspaces` value would throw on the `in` operator. - Keep 5 sites as reasoned oxlint-disable comments where excluding functions is load-bearing: the byte-exact fingerprint canonicalizer (2), the circularity walker, the zod result guard, and the generic hasKey helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
114 lines
2.9 KiB
TypeScript
114 lines
2.9 KiB
TypeScript
import { isString } from '@sindresorhus/is';
|
|
import * as semver from 'semver';
|
|
import { regEx } from '../../../util/regex.ts';
|
|
import { coerceString } from '../../../util/string.ts';
|
|
|
|
export function makeVersion(
|
|
version: string,
|
|
options: semver.RangeOptions,
|
|
): string | boolean | null {
|
|
const splitVersion = version.split('.');
|
|
const prerelease = semver.prerelease(version, options);
|
|
|
|
if (prerelease && !options.includePrerelease) {
|
|
if (!Number.isNaN(parseInt(prerelease.toString()[0], 10))) {
|
|
const stringVersion = `${splitVersion[0]}.${splitVersion[1]}.${splitVersion[2]}`;
|
|
return semver.valid(stringVersion, options);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
options.loose &&
|
|
!semver.valid(version, options) &&
|
|
splitVersion.length !== 3
|
|
) {
|
|
return semver.valid(semver.coerce(version, options), options);
|
|
}
|
|
return semver.valid(version, options);
|
|
}
|
|
|
|
export function cleanVersion(version: string): string {
|
|
if (version) {
|
|
return version
|
|
.replace(
|
|
regEx(
|
|
/,|\[|\]|"|include_prerelease=|include_prerelease|loose=|True|False/g,
|
|
),
|
|
'',
|
|
)
|
|
.trim();
|
|
}
|
|
return version;
|
|
}
|
|
|
|
export function getOptions(input: string): {
|
|
loose: boolean;
|
|
includePrerelease: boolean;
|
|
} {
|
|
let includePrerelease = false;
|
|
let loose = true;
|
|
if (input) {
|
|
includePrerelease =
|
|
input.includes('include_prerelease') &&
|
|
!input.includes('include_prerelease=False');
|
|
loose = input.includes('loose=True') || !input.includes('loose=False');
|
|
}
|
|
return { loose, includePrerelease };
|
|
}
|
|
|
|
export function containsOperators(input: string): boolean {
|
|
return regEx('[<=>^~]').test(input);
|
|
}
|
|
|
|
export function matchesWithOptions(
|
|
version: string,
|
|
cleanRange: string,
|
|
options: semver.RangeOptions,
|
|
): boolean {
|
|
let cleanedVersion = version;
|
|
if (
|
|
cleanedVersion &&
|
|
semver.prerelease(cleanedVersion) &&
|
|
options.includePrerelease
|
|
) {
|
|
const coercedVersion = semver.coerce(cleanedVersion)?.raw;
|
|
cleanedVersion = coerceString(coercedVersion);
|
|
}
|
|
return semver.satisfies(cleanedVersion, cleanRange, options);
|
|
}
|
|
|
|
export function findSatisfyingVersion(
|
|
versions: string[],
|
|
range: string,
|
|
compareRt: number,
|
|
): string | null {
|
|
const options = getOptions(range);
|
|
let cur: any = null;
|
|
let curSV: any = null;
|
|
let index = 0;
|
|
let curIndex = -1;
|
|
|
|
for (const v of versions) {
|
|
const versionFromList = makeVersion(v, options);
|
|
if (isString(versionFromList)) {
|
|
const cleanedVersion = cleanVersion(versionFromList);
|
|
const options = getOptions(range);
|
|
const cleanRange = cleanVersion(range);
|
|
if (
|
|
matchesWithOptions(cleanedVersion, cleanRange, options) &&
|
|
(!cur || semver.compare(curSV, versionFromList, options) === compareRt)
|
|
) {
|
|
cur = versionFromList;
|
|
curIndex = index;
|
|
curSV = new semver.SemVer(cur, options);
|
|
}
|
|
}
|
|
index += 1;
|
|
}
|
|
if (curIndex >= 0) {
|
|
return versions[curIndex];
|
|
}
|
|
return null;
|
|
}
|