mirror of
https://github.com/renovatebot/renovate.git
synced 2024-12-23 05:58:05 +00:00
147 lines
4.9 KiB
TypeScript
147 lines
4.9 KiB
TypeScript
import is from '@sindresorhus/is';
|
|
import { CONFIG_VALIDATION } from '../../../../../constants/error-messages';
|
|
import { logger } from '../../../../../logger';
|
|
import { regEx } from '../../../../../util/regex';
|
|
import type { PackageDependency, PackageFileContent } from '../../../types';
|
|
import type { NpmManagerData } from '../../types';
|
|
import type { NpmPackage, NpmPackageDependency } from '../types';
|
|
import {
|
|
extractDependency,
|
|
getExtractedConstraints,
|
|
parseDepName,
|
|
} from './dependency';
|
|
import { setNodeCommitTopic } from './node';
|
|
import { extractOverrideDepsRec } from './overrides';
|
|
|
|
export function extractPackageJson(
|
|
packageJson: NpmPackage,
|
|
packageFile: string,
|
|
): PackageFileContent<NpmManagerData> | null {
|
|
logger.trace(`npm.extractPackageJson(${packageFile})`);
|
|
const deps: PackageDependency[] = [];
|
|
|
|
if (packageJson._id && packageJson._args && packageJson._from) {
|
|
logger.debug({ packageFile }, 'Ignoring vendorised package.json');
|
|
return null;
|
|
}
|
|
if (packageFile !== 'package.json' && packageJson.renovate) {
|
|
const error = new Error(CONFIG_VALIDATION);
|
|
error.validationSource = packageFile;
|
|
error.validationError =
|
|
'Nested package.json must not contain Renovate configuration. Please use `packageRules` with `matchFileNames` in your main config instead.';
|
|
throw error;
|
|
}
|
|
const packageJsonName = packageJson.name;
|
|
logger.debug(
|
|
`npm file ${packageFile} has name ${JSON.stringify(packageJsonName)}`,
|
|
);
|
|
const packageFileVersion = packageJson.version;
|
|
|
|
const depTypes = {
|
|
dependencies: 'dependency',
|
|
devDependencies: 'devDependency',
|
|
optionalDependencies: 'optionalDependency',
|
|
peerDependencies: 'peerDependency',
|
|
engines: 'engine',
|
|
volta: 'volta',
|
|
resolutions: 'resolutions',
|
|
packageManager: 'packageManager',
|
|
overrides: 'overrides',
|
|
pnpm: 'pnpm',
|
|
};
|
|
|
|
for (const depType of Object.keys(depTypes) as (keyof typeof depTypes)[]) {
|
|
let dependencies = packageJson[depType];
|
|
if (dependencies) {
|
|
try {
|
|
if (depType === 'packageManager') {
|
|
const match = regEx('^(?<name>.+)@(?<range>.+)$').exec(
|
|
dependencies as string,
|
|
);
|
|
// istanbul ignore next
|
|
if (!match?.groups) {
|
|
break;
|
|
}
|
|
dependencies = { [match.groups.name]: match.groups.range };
|
|
}
|
|
for (const [key, val] of Object.entries(
|
|
dependencies as NpmPackageDependency,
|
|
)) {
|
|
const depName = parseDepName(depType, key);
|
|
let dep: PackageDependency = {
|
|
depType,
|
|
depName,
|
|
};
|
|
if (depName !== key) {
|
|
dep.managerData = { key };
|
|
}
|
|
if (depType === 'overrides' && !is.string(val)) {
|
|
// TODO: fix type #22198
|
|
deps.push(
|
|
...extractOverrideDepsRec(
|
|
[depName],
|
|
val as unknown as NpmManagerData,
|
|
),
|
|
);
|
|
} else if (depType === 'pnpm' && depName === 'overrides') {
|
|
// pnpm overrides
|
|
// https://pnpm.io/package_json#pnpmoverrides
|
|
for (const [overridesKey, overridesVal] of Object.entries(
|
|
val as unknown as NpmPackageDependency,
|
|
)) {
|
|
if (is.string(overridesVal)) {
|
|
// Newer flat syntax: `parent>parent>child`
|
|
const packageName = overridesKey.split('>').pop()!;
|
|
dep = {
|
|
depName: overridesKey,
|
|
packageName,
|
|
depType: 'pnpm.overrides',
|
|
...extractDependency(depName, packageName, overridesVal),
|
|
};
|
|
setNodeCommitTopic(dep);
|
|
// TODO: Is this expected? It's always 'overrides'.
|
|
dep.prettyDepType = depTypes[depName];
|
|
deps.push(dep);
|
|
} else if (is.object(overridesVal)) {
|
|
// Older nested object syntax: `parent: { parent: { child: version } }`
|
|
deps.push(
|
|
...extractOverrideDepsRec(
|
|
[overridesKey],
|
|
overridesVal as unknown as NpmManagerData,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
// TODO: fix type #22198
|
|
dep = { ...dep, ...extractDependency(depType, depName, val!) };
|
|
setNodeCommitTopic(dep);
|
|
dep.prettyDepType = depTypes[depType];
|
|
deps.push(dep);
|
|
}
|
|
}
|
|
} catch (err) /* istanbul ignore next */ {
|
|
logger.debug(
|
|
{ fileName: packageFile, depType, err },
|
|
'Error parsing package.json',
|
|
);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
const extractedConstraints = getExtractedConstraints(deps);
|
|
|
|
return {
|
|
deps,
|
|
extractedConstraints,
|
|
packageFileVersion,
|
|
managerData: {
|
|
packageJsonName,
|
|
hasPackageManager: is.nonEmptyStringAndNotWhitespace(
|
|
packageJson.packageManager,
|
|
),
|
|
},
|
|
};
|
|
}
|