mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-01 02:00:10 +00:00
9717259ffc
Enable no-else-return (with allowElseIf: false) and unicorn/no-lonely-if as errors in .oxlintrc.json and fix all 131 pre-existing violations (91 no-else-return, 40 unicorn/no-lonely-if) across 98 files. The no-else-return violations were fixed with the oxlint autofix (iterated to a fixpoint, plus two else-if chains that required --fix-dangerously) followed by Prettier formatting. One comment dropped by the autofix in lib/modules/manager/pub/artifacts.ts was restored manually. The unicorn/no-lonely-if violations were merged by hand, preserving comments and coverage-ignore hints. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
168 lines
5.2 KiB
TypeScript
168 lines
5.2 KiB
TypeScript
import { isString } from '@sindresorhus/is';
|
|
import type { Document } from 'yaml';
|
|
import { CST, isCollection, isPair, isScalar, parseDocument } from 'yaml';
|
|
import { logger } from '../../../../../logger/index.ts';
|
|
import type { UpdateDependencyConfig } from '../../../types.ts';
|
|
import { pnpmWorkspaceOverrides } from '../../dep-types.ts';
|
|
import { PnpmWorkspaceFile } from '../../schema.ts';
|
|
import { getNewGitValue, getNewNpmAliasValue } from './common.ts';
|
|
|
|
export function updatePnpmWorkspaceDependency({
|
|
fileContent,
|
|
upgrade,
|
|
}: UpdateDependencyConfig): string | null {
|
|
const { depType, depName } = upgrade;
|
|
|
|
const catalogName = depType?.split('.').at(-1);
|
|
|
|
// should never happen
|
|
if (!isString(catalogName) && depType !== pnpmWorkspaceOverrides) {
|
|
logger.error(
|
|
'No catalogName or override was found; this is likely an extraction error.',
|
|
);
|
|
return null;
|
|
}
|
|
|
|
let { newValue } = upgrade;
|
|
|
|
newValue = getNewGitValue(upgrade) ?? newValue;
|
|
newValue = getNewNpmAliasValue(newValue, upgrade) ?? newValue;
|
|
|
|
logger.trace(
|
|
`npm.updatePnpmWorkspaceDependency(): ${depType}:${depName} = ${newValue}`,
|
|
);
|
|
|
|
let document: Document;
|
|
let parsedContents: PnpmWorkspaceFile;
|
|
|
|
try {
|
|
// In order to preserve the original formatting as much as possible, we want
|
|
// manipulate the CST directly. Using the AST (the result of parseDocument)
|
|
// does not guarantee that formatting would be the same after
|
|
// stringification. However, the CST is more annoying to query for certain
|
|
// values. Thus, we use both an annotated AST and a JS representation; the
|
|
// former for manipulation, and the latter for querying/validation.
|
|
document = parseDocument(fileContent, { keepSourceTokens: true });
|
|
parsedContents = PnpmWorkspaceFile.parse(fileContent);
|
|
} catch (err) {
|
|
logger.debug({ err }, 'Could not parse pnpm-workspace YAML file.');
|
|
return null;
|
|
}
|
|
|
|
// In pnpm-workspace.yaml, the default catalog can be either `catalog` or
|
|
// `catalog.default`, but not both (pnpm throws outright with a config error).
|
|
// Thus, we must check which entry is being used, to reference it from / set
|
|
// it in the right place.
|
|
const usesImplicitDefaultCatalog = parsedContents.catalog !== undefined;
|
|
const isCatalogUpdate = catalogName && depType !== pnpmWorkspaceOverrides;
|
|
|
|
let oldVersion: string | undefined;
|
|
if (isCatalogUpdate) {
|
|
if (catalogName === 'default' && usesImplicitDefaultCatalog) {
|
|
oldVersion = parsedContents.catalog?.[depName!];
|
|
} else {
|
|
oldVersion = parsedContents.catalogs?.[catalogName]?.[depName!];
|
|
}
|
|
} else {
|
|
oldVersion = parsedContents.overrides?.[depName!];
|
|
}
|
|
|
|
if (oldVersion === newValue) {
|
|
logger.trace('Version is already updated');
|
|
return fileContent;
|
|
}
|
|
|
|
// Update the value
|
|
const path = isCatalogUpdate
|
|
? getDepPath({
|
|
depName: depName!,
|
|
catalogName,
|
|
usesImplicitDefaultCatalog,
|
|
})
|
|
: ['overrides', depName!];
|
|
|
|
const modifiedDocument = changeDependencyIn(document, path, {
|
|
newValue,
|
|
newName: upgrade.newName,
|
|
});
|
|
|
|
if (!modifiedDocument) {
|
|
// Case where we are explicitly unable to substitute the key/value, for
|
|
// example if the value was an alias.
|
|
return null;
|
|
}
|
|
|
|
/* v8 ignore if -- this should not happen in practice, but we must satisfy the types */
|
|
if (!modifiedDocument.contents?.srcToken) {
|
|
return null;
|
|
}
|
|
|
|
return CST.stringify(modifiedDocument.contents.srcToken);
|
|
}
|
|
|
|
/**
|
|
* Change the scalar name and/or value of a collection item in a YAML document,
|
|
* while keeping formatting consistent. Mutates the given document.
|
|
*/
|
|
function changeDependencyIn(
|
|
document: Document,
|
|
path: string[],
|
|
{ newName, newValue }: { newName?: string; newValue?: string },
|
|
): Document | null {
|
|
const parentPath = path.slice(0, -1);
|
|
const relevantItemKey = path.at(-1);
|
|
|
|
const parentNode = document.getIn(parentPath);
|
|
|
|
if (!parentNode || !isCollection(parentNode)) {
|
|
return null;
|
|
}
|
|
|
|
const relevantNode = parentNode.items.find(
|
|
(item) =>
|
|
isPair(item) && isScalar(item.key) && item.key.value === relevantItemKey,
|
|
);
|
|
|
|
if (!relevantNode || !isPair(relevantNode)) {
|
|
return null;
|
|
}
|
|
|
|
if (newName) {
|
|
/* v8 ignore if -- the try..catch block above already throws if a key is an alias */
|
|
if (!CST.isScalar(relevantNode.srcToken?.key)) {
|
|
return null;
|
|
}
|
|
CST.setScalarValue(relevantNode.srcToken.key, newName);
|
|
}
|
|
|
|
// v8 ignore else -- TODO: add test #40625
|
|
if (newValue) {
|
|
// We only support scalar values when substituting. This explicitly avoids
|
|
// substituting aliases, since those can be resolved from a shared location,
|
|
// and replacing either the referrent anchor or the alias would be wrong in
|
|
// the general case. We leave this up to the user, e.g. via a Regex custom
|
|
// manager.
|
|
if (!CST.isScalar(relevantNode.srcToken?.value)) {
|
|
return null;
|
|
}
|
|
CST.setScalarValue(relevantNode.srcToken.value, newValue);
|
|
}
|
|
|
|
return document;
|
|
}
|
|
|
|
function getDepPath({
|
|
catalogName,
|
|
depName,
|
|
usesImplicitDefaultCatalog,
|
|
}: {
|
|
usesImplicitDefaultCatalog: boolean;
|
|
catalogName: string;
|
|
depName: string;
|
|
}): string[] {
|
|
if (catalogName === 'default' && usesImplicitDefaultCatalog) {
|
|
return ['catalog', depName];
|
|
}
|
|
return ['catalogs', catalogName, depName];
|
|
}
|