Files
Sebastian Poxhofer c32e2391a0 refactor(linters): add prefer-coerce-object rule (#45493)
Refs #45216

The object counterpart to `prefer-coerce-array`: `x ?? {}` becomes
`coerceObject(x)`. The rule flags a `??` whose default is a bare `{}`
literal, so a populated default or an asserted `({} as Foo)` still
passes; a `x ?? y ?? {}` chain maps onto `coerceObject(x, y)`.

Every hit across `lib/` converted cleanly, so no disable comments were
needed.
2026-08-28 09:27:59 +00:00

118 lines
3.4 KiB
TypeScript

import { isEmptyStringOrWhitespace } from '@sindresorhus/is';
import { migrateDatasource } from '../../../../config/migrations/custom/datasource-migration.ts';
import { logger } from '../../../../logger/index.ts';
import { coerceObject } from '../../../../util/object.ts';
import * as template from '../../../../util/template/index.ts';
import { parseUrl } from '../../../../util/url.ts';
import type { PackageDependency } from '../../types.ts';
import type { ValidMatchFields } from '../types.ts';
import { validMatchFields } from '../utils.ts';
import type {
ExtractionTemplate,
PackageFileInfo,
RegexManagerConfig,
RegexManagerTemplates,
} from './types.ts';
function updateDependency(
dependency: PackageDependency,
field: ValidMatchFields,
value: string,
): void {
switch (field) {
case 'registryUrl': {
// check if URL is valid and pack inside an array
const url = parseUrl(value)?.toString();
if (url) {
dependency.registryUrls = [url];
} else {
logger.warn({ value }, 'Invalid regex manager registryUrl');
}
break;
}
case 'datasource':
dependency.datasource = migrateDatasource(value);
break;
case 'indentation':
dependency.indentation = isEmptyStringOrWhitespace(value) ? value : '';
break;
default:
dependency[field] = value;
break;
}
}
export function createDependency(
extractionTemplate: ExtractionTemplate,
config: RegexManagerConfig,
packageFileInfo: PackageFileInfo,
dep?: PackageDependency,
): PackageDependency | null {
const dependency = coerceObject(dep);
const { groups, replaceString } = extractionTemplate;
const { packageFileName, packageFileDir } = packageFileInfo;
for (const field of validMatchFields) {
const fieldTemplate = `${field}Template` as keyof RegexManagerTemplates;
const tmpl = config[fieldTemplate];
if (tmpl) {
try {
const compiled = template.compile(
tmpl,
{ ...groups, packageFile: packageFileName, packageFileDir },
false,
);
updateDependency(dependency, field, compiled);
} catch {
logger.warn(
{ template: tmpl },
'Error compiling template for custom manager',
);
return null;
}
} else if (groups[field]) {
updateDependency(dependency, field, groups[field]);
}
}
dependency.replaceString = replaceString;
return dependency;
}
export function regexMatchAll(
regex: RegExp,
content: string,
): RegExpMatchArray[] {
const matches: RegExpMatchArray[] = [];
let matchResult: RegExpMatchArray | null;
let iterations = 0;
const maxIterations = 10000;
do {
matchResult = regex.exec(content);
if (matchResult) {
matches.push(matchResult);
}
iterations += 1;
} while (matchResult && iterations < maxIterations);
if (iterations === maxIterations) {
logger.warn('Max iterations reached for matchStrings');
}
return matches;
}
export function mergeGroups(
mergedGroup: Record<string, string>,
secondGroup: Record<string, string>,
): Record<string, string> {
return { ...mergedGroup, ...secondGroup };
}
export function mergeExtractionTemplate(
base: ExtractionTemplate,
addition: ExtractionTemplate,
): ExtractionTemplate {
return {
groups: mergeGroups(base.groups, addition.groups),
replaceString: addition.replaceString ?? base.replaceString,
};
}