From 255ab28395ceeeed6cf85194f0a8a5f095574fb3 Mon Sep 17 00:00:00 2001 From: pataar Date: Sun, 13 Nov 2022 14:08:06 +0100 Subject: [PATCH 1/9] fix(volta): make sure volta uses the same yarn package overwrite --- lib/modules/manager/npm/extract/index.ts | 948 ++++++++++++----------- 1 file changed, 477 insertions(+), 471 deletions(-) diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index f436af566d2616..bee4f9ac0eff2a 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -1,509 +1,515 @@ -import is from '@sindresorhus/is'; -import validateNpmPackageName from 'validate-npm-package-name'; -import { GlobalConfig } from '../../../../config/global'; -import { CONFIG_VALIDATION } from '../../../../constants/error-messages'; -import { logger } from '../../../../logger'; -import { getSiblingFileName, readLocalFile } from '../../../../util/fs'; -import { newlineRegex, regEx } from '../../../../util/regex'; -import { GithubTagsDatasource } from '../../../datasource/github-tags'; -import { NpmDatasource } from '../../../datasource/npm'; -import * as nodeVersioning from '../../../versioning/node'; -import { isValid, isVersion } from '../../../versioning/npm'; +import is from "@sindresorhus/is"; +import validateNpmPackageName from "validate-npm-package-name"; +import { GlobalConfig } from "../../../../config/global"; +import { CONFIG_VALIDATION } from "../../../../constants/error-messages"; +import { logger } from "../../../../logger"; +import { getSiblingFileName, readLocalFile } from "../../../../util/fs"; +import { newlineRegex, regEx } from "../../../../util/regex"; +import { GithubTagsDatasource } from "../../../datasource/github-tags"; +import { NpmDatasource } from "../../../datasource/npm"; +import * as nodeVersioning from "../../../versioning/node"; +import { isValid, isVersion } from "../../../versioning/npm"; import type { - ExtractConfig, - NpmLockFiles, - PackageDependency, - PackageFile, -} from '../../types'; -import type { NpmManagerData } from '../types'; -import { getLockedVersions } from './locked-versions'; -import { detectMonorepos } from './monorepo'; -import type { NpmPackage, NpmPackageDependency } from './types'; -import { isZeroInstall } from './yarn'; + ExtractConfig, + NpmLockFiles, + PackageDependency, + PackageFile, +} from "../../types"; +import type { NpmManagerData } from "../types"; +import { getLockedVersions } from "./locked-versions"; +import { detectMonorepos } from "./monorepo"; +import type { NpmPackage, NpmPackageDependency } from "./types"; +import { isZeroInstall } from "./yarn"; function parseDepName(depType: string, key: string): string { - if (depType !== 'resolutions') { - return key; - } + if (depType !== "resolutions") { + return key; + } - const [, depName] = regEx(/((?:@[^/]+\/)?[^/@]+)$/).exec(key) ?? []; - return depName; + const [, depName] = regEx(/((?:@[^/]+\/)?[^/@]+)$/).exec(key) ?? []; + return depName; } const RE_REPOSITORY_GITHUB_SSH_FORMAT = regEx( - /(?:git@)github.com:([^/]+)\/([^/.]+)(?:\.git)?/ + /(?:git@)github.com:([^/]+)\/([^/.]+)(?:\.git)?/ ); export async function extractPackageFile( - content: string, - fileName: string, - config: ExtractConfig + content: string, + fileName: string, + config: ExtractConfig ): Promise | null> { - logger.trace(`npm.extractPackageFile(${fileName})`); - logger.trace({ content }); - const deps: PackageDependency[] = []; - let packageJson: NpmPackage; - try { - packageJson = JSON.parse(content); - } catch (err) { - logger.debug(`Invalid JSON in ${fileName}`); - return null; - } + logger.trace(`npm.extractPackageFile(${fileName})`); + logger.trace({ content }); + const deps: PackageDependency[] = []; + let packageJson: NpmPackage; + try { + packageJson = JSON.parse(content); + } catch (err) { + logger.debug(`Invalid JSON in ${fileName}`); + return null; + } - if (packageJson._id && packageJson._args && packageJson._from) { - logger.debug('Ignoring vendorised package.json'); - return null; - } - if (fileName !== 'package.json' && packageJson.renovate) { - const error = new Error(CONFIG_VALIDATION); - error.validationSource = fileName; - error.validationError = - 'Nested package.json must not contain renovate configuration. Please use `packageRules` with `matchPaths` in your main config instead.'; - throw error; - } - const packageJsonName = packageJson.name; - logger.debug( - `npm file ${fileName} has name ${JSON.stringify(packageJsonName)}` - ); - const packageFileVersion = packageJson.version; - let yarnWorkspacesPackages: string[] | undefined; - if (is.array(packageJson.workspaces)) { - yarnWorkspacesPackages = packageJson.workspaces; - } else { - yarnWorkspacesPackages = packageJson.workspaces?.packages; - } + if (packageJson._id && packageJson._args && packageJson._from) { + logger.debug("Ignoring vendorised package.json"); + return null; + } + if (fileName !== "package.json" && packageJson.renovate) { + const error = new Error(CONFIG_VALIDATION); + error.validationSource = fileName; + error.validationError = + "Nested package.json must not contain renovate configuration. Please use `packageRules` with `matchPaths` in your main config instead."; + throw error; + } + const packageJsonName = packageJson.name; + logger.debug( + `npm file ${fileName} has name ${JSON.stringify(packageJsonName)}` + ); + const packageFileVersion = packageJson.version; + let yarnWorkspacesPackages: string[] | undefined; + if (is.array(packageJson.workspaces)) { + yarnWorkspacesPackages = packageJson.workspaces; + } else { + yarnWorkspacesPackages = packageJson.workspaces?.packages; + } - const lockFiles: NpmLockFiles = { - yarnLock: 'yarn.lock', - packageLock: 'package-lock.json', - shrinkwrapJson: 'npm-shrinkwrap.json', - pnpmShrinkwrap: 'pnpm-lock.yaml', - }; + const lockFiles: NpmLockFiles = { + yarnLock: "yarn.lock", + packageLock: "package-lock.json", + shrinkwrapJson: "npm-shrinkwrap.json", + pnpmShrinkwrap: "pnpm-lock.yaml", + }; - for (const [key, val] of Object.entries(lockFiles) as [ - 'yarnLock' | 'packageLock' | 'shrinkwrapJson' | 'pnpmShrinkwrap', - string - ][]) { - const filePath = getSiblingFileName(fileName, val); - if (await readLocalFile(filePath, 'utf8')) { - lockFiles[key] = filePath; - } else { - lockFiles[key] = undefined; - } - } - lockFiles.npmLock = lockFiles.packageLock ?? lockFiles.shrinkwrapJson; - delete lockFiles.packageLock; - delete lockFiles.shrinkwrapJson; + for (const [key, val] of Object.entries(lockFiles) as [ + "yarnLock" | "packageLock" | "shrinkwrapJson" | "pnpmShrinkwrap", + string + ][]) { + const filePath = getSiblingFileName(fileName, val); + if (await readLocalFile(filePath, "utf8")) { + lockFiles[key] = filePath; + } else { + lockFiles[key] = undefined; + } + } + lockFiles.npmLock = lockFiles.packageLock ?? lockFiles.shrinkwrapJson; + delete lockFiles.packageLock; + delete lockFiles.shrinkwrapJson; - let npmrc: string | undefined; - const npmrcFileName = getSiblingFileName(fileName, '.npmrc'); - let repoNpmrc = await readLocalFile(npmrcFileName, 'utf8'); - if (is.string(repoNpmrc)) { - if (is.string(config.npmrc) && !config.npmrcMerge) { - logger.debug( - { npmrcFileName }, - 'Repo .npmrc file is ignored due to config.npmrc with config.npmrcMerge=false' - ); - } else { - npmrc = config.npmrc ?? ''; - if (npmrc.length) { - if (!npmrc.endsWith('\n')) { - npmrc += '\n'; - } - } - if (repoNpmrc?.includes('package-lock')) { - logger.debug('Stripping package-lock setting from .npmrc'); - repoNpmrc = repoNpmrc.replace( - regEx(/(^|\n)package-lock.*?(\n|$)/g), - '\n' - ); - } - if (repoNpmrc.includes('=${') && !GlobalConfig.get('exposeAllEnv')) { - logger.debug( - { npmrcFileName }, - 'Stripping .npmrc file of lines with variables' - ); - repoNpmrc = repoNpmrc - .split(newlineRegex) - .filter((line) => !line.includes('=${')) - .join('\n'); - } - npmrc += repoNpmrc; - } - } + let npmrc: string | undefined; + const npmrcFileName = getSiblingFileName(fileName, ".npmrc"); + let repoNpmrc = await readLocalFile(npmrcFileName, "utf8"); + if (is.string(repoNpmrc)) { + if (is.string(config.npmrc) && !config.npmrcMerge) { + logger.debug( + { npmrcFileName }, + "Repo .npmrc file is ignored due to config.npmrc with config.npmrcMerge=false" + ); + } else { + npmrc = config.npmrc ?? ""; + if (npmrc.length) { + if (!npmrc.endsWith("\n")) { + npmrc += "\n"; + } + } + if (repoNpmrc?.includes("package-lock")) { + logger.debug("Stripping package-lock setting from .npmrc"); + repoNpmrc = repoNpmrc.replace( + regEx(/(^|\n)package-lock.*?(\n|$)/g), + "\n" + ); + } + if (repoNpmrc.includes("=${") && !GlobalConfig.get("exposeAllEnv")) { + logger.debug( + { npmrcFileName }, + "Stripping .npmrc file of lines with variables" + ); + repoNpmrc = repoNpmrc + .split(newlineRegex) + .filter((line) => !line.includes("=${")) + .join("\n"); + } + npmrc += repoNpmrc; + } + } - const yarnrcYmlFileName = getSiblingFileName(fileName, '.yarnrc.yml'); - const yarnZeroInstall = await isZeroInstall(yarnrcYmlFileName); + const yarnrcYmlFileName = getSiblingFileName(fileName, ".yarnrc.yml"); + const yarnZeroInstall = await isZeroInstall(yarnrcYmlFileName); - let lernaJsonFile: string | undefined; - let lernaPackages: string[] | undefined; - let lernaClient: 'yarn' | 'npm' | undefined; - let hasFancyRefs = false; - let lernaJson: - | { - packages: string[]; - npmClient: string; - useWorkspaces?: boolean; - } - | undefined; - try { - lernaJsonFile = getSiblingFileName(fileName, 'lerna.json'); - // TODO #7154 - lernaJson = JSON.parse((await readLocalFile(lernaJsonFile, 'utf8'))!); - } catch (err) /* istanbul ignore next */ { - logger.warn({ err }, 'Could not parse lerna.json'); - } - if (lernaJson && !lernaJson.useWorkspaces) { - lernaPackages = lernaJson.packages; - lernaClient = - lernaJson.npmClient === 'yarn' || lockFiles.yarnLock ? 'yarn' : 'npm'; - } else { - lernaJsonFile = undefined; - } + let lernaJsonFile: string | undefined; + let lernaPackages: string[] | undefined; + let lernaClient: "yarn" | "npm" | undefined; + let hasFancyRefs = false; + let lernaJson: + | { + packages: string[]; + npmClient: string; + useWorkspaces?: boolean; + } + | undefined; + try { + lernaJsonFile = getSiblingFileName(fileName, "lerna.json"); + // TODO #7154 + lernaJson = JSON.parse((await readLocalFile(lernaJsonFile, "utf8"))!); + } catch (err) /* istanbul ignore next */ { + logger.warn({ err }, "Could not parse lerna.json"); + } + if (lernaJson && !lernaJson.useWorkspaces) { + lernaPackages = lernaJson.packages; + lernaClient = + lernaJson.npmClient === "yarn" || lockFiles.yarnLock ? "yarn" : "npm"; + } else { + lernaJsonFile = undefined; + } - const depTypes = { - dependencies: 'dependency', - devDependencies: 'devDependency', - optionalDependencies: 'optionalDependency', - peerDependencies: 'peerDependency', - engines: 'engine', - volta: 'volta', - resolutions: 'resolutions', - packageManager: 'packageManager', - overrides: 'overrides', - }; + const depTypes = { + dependencies: "dependency", + devDependencies: "devDependency", + optionalDependencies: "optionalDependency", + peerDependencies: "peerDependency", + engines: "engine", + volta: "volta", + resolutions: "resolutions", + packageManager: "packageManager", + overrides: "overrides", + }; - const constraints: Record = {}; + const constraints: Record = {}; - function extractDependency( - depType: string, - depName: string, - input: string - ): PackageDependency { - const dep: PackageDependency = {}; - if (!validateNpmPackageName(depName).validForOldPackages) { - dep.skipReason = 'invalid-name'; - return dep; - } - if (typeof input !== 'string') { - dep.skipReason = 'invalid-value'; - return dep; - } - dep.currentValue = input.trim(); - if (depType === 'engines' || depType === 'packageManager') { - if (depName === 'node') { - dep.datasource = GithubTagsDatasource.id; - dep.packageName = 'nodejs/node'; - dep.versioning = nodeVersioning.id; - constraints.node = dep.currentValue; - } else if (depName === 'yarn') { - dep.datasource = NpmDatasource.id; - dep.commitMessageTopic = 'Yarn'; - constraints.yarn = dep.currentValue; - if ( - dep.currentValue.startsWith('2') || - dep.currentValue.startsWith('3') - ) { - dep.packageName = '@yarnpkg/cli'; - } - } else if (depName === 'npm') { - dep.datasource = NpmDatasource.id; - dep.commitMessageTopic = 'npm'; - constraints.npm = dep.currentValue; - } else if (depName === 'pnpm') { - dep.datasource = NpmDatasource.id; - dep.commitMessageTopic = 'pnpm'; - } else if (depName === 'vscode') { - dep.datasource = GithubTagsDatasource.id; - dep.packageName = 'microsoft/vscode'; - constraints.vscode = dep.currentValue; - } else { - dep.skipReason = 'unknown-engines'; - } - if (!isValid(dep.currentValue)) { - dep.skipReason = 'unknown-version'; - } - return dep; - } + function extractDependency( + depType: string, + depName: string, + input: string + ): PackageDependency { + const dep: PackageDependency = {}; + if (!validateNpmPackageName(depName).validForOldPackages) { + dep.skipReason = "invalid-name"; + return dep; + } + if (typeof input !== "string") { + dep.skipReason = "invalid-value"; + return dep; + } + dep.currentValue = input.trim(); + if (depType === "engines" || depType === "packageManager") { + if (depName === "node") { + dep.datasource = GithubTagsDatasource.id; + dep.packageName = "nodejs/node"; + dep.versioning = nodeVersioning.id; + constraints.node = dep.currentValue; + } else if (depName === "yarn") { + dep.datasource = NpmDatasource.id; + dep.commitMessageTopic = "Yarn"; + constraints.yarn = dep.currentValue; + if ( + dep.currentValue.startsWith("2") || + dep.currentValue.startsWith("3") + ) { + dep.packageName = "@yarnpkg/cli"; + } + } else if (depName === "npm") { + dep.datasource = NpmDatasource.id; + dep.commitMessageTopic = "npm"; + constraints.npm = dep.currentValue; + } else if (depName === "pnpm") { + dep.datasource = NpmDatasource.id; + dep.commitMessageTopic = "pnpm"; + } else if (depName === "vscode") { + dep.datasource = GithubTagsDatasource.id; + dep.packageName = "microsoft/vscode"; + constraints.vscode = dep.currentValue; + } else { + dep.skipReason = "unknown-engines"; + } + if (!isValid(dep.currentValue)) { + dep.skipReason = "unknown-version"; + } + return dep; + } - // support for volta - if (depType === 'volta') { - if (depName === 'node') { - dep.datasource = GithubTagsDatasource.id; - dep.packageName = 'nodejs/node'; - dep.versioning = nodeVersioning.id; - } else if (depName === 'yarn') { - dep.datasource = NpmDatasource.id; - dep.commitMessageTopic = 'Yarn'; - } else if (depName === 'npm') { - dep.datasource = NpmDatasource.id; - } else { - dep.skipReason = 'unknown-volta'; - } - if (!isValid(dep.currentValue)) { - dep.skipReason = 'unknown-version'; - } - return dep; - } + // support for volta + if (depType === "volta") { + if (depName === "node") { + dep.datasource = GithubTagsDatasource.id; + dep.packageName = "nodejs/node"; + dep.versioning = nodeVersioning.id; + } else if (depName === "yarn") { + dep.datasource = NpmDatasource.id; + dep.commitMessageTopic = "Yarn"; + if ( + dep.currentValue.startsWith("2") || + dep.currentValue.startsWith("3") + ) { + dep.packageName = "@yarnpkg/cli"; + } + } else if (depName === "npm") { + dep.datasource = NpmDatasource.id; + } else { + dep.skipReason = "unknown-volta"; + } + if (!isValid(dep.currentValue)) { + dep.skipReason = "unknown-version"; + } + return dep; + } - if (dep.currentValue.startsWith('npm:')) { - dep.npmPackageAlias = true; - hasFancyRefs = true; - const valSplit = dep.currentValue.replace('npm:', '').split('@'); - if (valSplit.length === 2) { - dep.packageName = valSplit[0]; - dep.currentValue = valSplit[1]; - } else if (valSplit.length === 3) { - dep.packageName = valSplit[0] + '@' + valSplit[1]; - dep.currentValue = valSplit[2]; - } else { - logger.debug('Invalid npm package alias: ' + dep.currentValue); - } - } - if (dep.currentValue.startsWith('file:')) { - dep.skipReason = 'file'; - hasFancyRefs = true; - return dep; - } - if (isValid(dep.currentValue)) { - dep.datasource = NpmDatasource.id; - if (dep.currentValue === '') { - dep.skipReason = 'empty'; - } - return dep; - } - const hashSplit = dep.currentValue.split('#'); - if (hashSplit.length !== 2) { - dep.skipReason = 'unknown-version'; - return dep; - } - const [depNamePart, depRefPart] = hashSplit; + if (dep.currentValue.startsWith("npm:")) { + dep.npmPackageAlias = true; + hasFancyRefs = true; + const valSplit = dep.currentValue.replace("npm:", "").split("@"); + if (valSplit.length === 2) { + dep.packageName = valSplit[0]; + dep.currentValue = valSplit[1]; + } else if (valSplit.length === 3) { + dep.packageName = valSplit[0] + "@" + valSplit[1]; + dep.currentValue = valSplit[2]; + } else { + logger.debug("Invalid npm package alias: " + dep.currentValue); + } + } + if (dep.currentValue.startsWith("file:")) { + dep.skipReason = "file"; + hasFancyRefs = true; + return dep; + } + if (isValid(dep.currentValue)) { + dep.datasource = NpmDatasource.id; + if (dep.currentValue === "") { + dep.skipReason = "empty"; + } + return dep; + } + const hashSplit = dep.currentValue.split("#"); + if (hashSplit.length !== 2) { + dep.skipReason = "unknown-version"; + return dep; + } + const [depNamePart, depRefPart] = hashSplit; - let githubOwnerRepo: string; - let githubOwner: string; - let githubRepo: string; - const matchUrlSshFormat = RE_REPOSITORY_GITHUB_SSH_FORMAT.exec(depNamePart); - if (matchUrlSshFormat === null) { - githubOwnerRepo = depNamePart - .replace(regEx(/^github:/), '') - .replace(regEx(/^git\+/), '') - .replace(regEx(/^https:\/\/github\.com\//), '') - .replace(regEx(/\.git$/), ''); - const githubRepoSplit = githubOwnerRepo.split('/'); - if (githubRepoSplit.length !== 2) { - dep.skipReason = 'unknown-version'; - return dep; - } - [githubOwner, githubRepo] = githubRepoSplit; - } else { - githubOwner = matchUrlSshFormat[1]; - githubRepo = matchUrlSshFormat[2]; - githubOwnerRepo = `${githubOwner}/${githubRepo}`; - } - const githubValidRegex = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; // TODO #12872 lookahead - if ( - !githubValidRegex.test(githubOwner) || - !githubValidRegex.test(githubRepo) - ) { - dep.skipReason = 'unknown-version'; - return dep; - } - if (isVersion(depRefPart)) { - dep.currentRawValue = dep.currentValue; - dep.currentValue = depRefPart; - dep.datasource = GithubTagsDatasource.id; - dep.packageName = githubOwnerRepo; - dep.pinDigests = false; - } else if ( - regEx(/^[0-9a-f]{7}$/).test(depRefPart) || - regEx(/^[0-9a-f]{40}$/).test(depRefPart) - ) { - dep.currentRawValue = dep.currentValue; - dep.currentValue = null; - dep.currentDigest = depRefPart; - dep.datasource = GithubTagsDatasource.id; - dep.packageName = githubOwnerRepo; - } else { - dep.skipReason = 'unversioned-reference'; - return dep; - } - dep.sourceUrl = `https://github.com/${githubOwnerRepo}`; - dep.gitRef = true; - return dep; - } + let githubOwnerRepo: string; + let githubOwner: string; + let githubRepo: string; + const matchUrlSshFormat = RE_REPOSITORY_GITHUB_SSH_FORMAT.exec(depNamePart); + if (matchUrlSshFormat === null) { + githubOwnerRepo = depNamePart + .replace(regEx(/^github:/), "") + .replace(regEx(/^git\+/), "") + .replace(regEx(/^https:\/\/github\.com\//), "") + .replace(regEx(/\.git$/), ""); + const githubRepoSplit = githubOwnerRepo.split("/"); + if (githubRepoSplit.length !== 2) { + dep.skipReason = "unknown-version"; + return dep; + } + [githubOwner, githubRepo] = githubRepoSplit; + } else { + githubOwner = matchUrlSshFormat[1]; + githubRepo = matchUrlSshFormat[2]; + githubOwnerRepo = `${githubOwner}/${githubRepo}`; + } + const githubValidRegex = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; // TODO #12872 lookahead + if ( + !githubValidRegex.test(githubOwner) || + !githubValidRegex.test(githubRepo) + ) { + dep.skipReason = "unknown-version"; + return dep; + } + if (isVersion(depRefPart)) { + dep.currentRawValue = dep.currentValue; + dep.currentValue = depRefPart; + dep.datasource = GithubTagsDatasource.id; + dep.packageName = githubOwnerRepo; + dep.pinDigests = false; + } else if ( + regEx(/^[0-9a-f]{7}$/).test(depRefPart) || + regEx(/^[0-9a-f]{40}$/).test(depRefPart) + ) { + dep.currentRawValue = dep.currentValue; + dep.currentValue = null; + dep.currentDigest = depRefPart; + dep.datasource = GithubTagsDatasource.id; + dep.packageName = githubOwnerRepo; + } else { + dep.skipReason = "unversioned-reference"; + return dep; + } + dep.sourceUrl = `https://github.com/${githubOwnerRepo}`; + dep.gitRef = true; + return dep; + } - /** - * Used when there is a json object as a value in overrides block. - * @param parents - * @param child - * @returns PackageDependency array - */ - function extractOverrideDepsRec( - parents: string[], - child: NpmManagerData - ): PackageDependency[] { - const deps: PackageDependency[] = []; - if (!child || is.emptyObject(child)) { - return deps; - } - for (const [overrideName, versionValue] of Object.entries(child)) { - if (is.string(versionValue)) { - // special handling for "." override depenency name - // "." means the constraint is applied to the parent dep - const currDepName = - overrideName === '.' ? parents[parents.length - 1] : overrideName; - const dep: PackageDependency = { - depName: currDepName, - depType: 'overrides', - managerData: { parents: parents.slice() }, // set parents for dependency - }; - setNodeCommitTopic(dep); - deps.push({ - ...dep, - ...extractDependency('overrides', currDepName, versionValue), - }); - } else { - // versionValue is an object, run recursively. - parents.push(overrideName); - const depsOfObject = extractOverrideDepsRec(parents, versionValue); - deps.push(...depsOfObject); - } - } - parents.pop(); - return deps; - } + /** + * Used when there is a json object as a value in overrides block. + * @param parents + * @param child + * @returns PackageDependency array + */ + function extractOverrideDepsRec( + parents: string[], + child: NpmManagerData + ): PackageDependency[] { + const deps: PackageDependency[] = []; + if (!child || is.emptyObject(child)) { + return deps; + } + for (const [overrideName, versionValue] of Object.entries(child)) { + if (is.string(versionValue)) { + // special handling for "." override depenency name + // "." means the constraint is applied to the parent dep + const currDepName = + overrideName === "." ? parents[parents.length - 1] : overrideName; + const dep: PackageDependency = { + depName: currDepName, + depType: "overrides", + managerData: { parents: parents.slice() }, // set parents for dependency + }; + setNodeCommitTopic(dep); + deps.push({ + ...dep, + ...extractDependency("overrides", currDepName, versionValue), + }); + } else { + // versionValue is an object, run recursively. + parents.push(overrideName); + const depsOfObject = extractOverrideDepsRec(parents, versionValue); + deps.push(...depsOfObject); + } + } + parents.pop(); + return deps; + } - for (const depType of Object.keys(depTypes) as (keyof typeof depTypes)[]) { - let dependencies = packageJson[depType]; - if (dependencies) { - try { - if (depType === 'packageManager') { - const match = regEx('^(?.+)@(?.+)$').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 #7154 - deps.push( - ...extractOverrideDepsRec( - [depName], - val as unknown as NpmManagerData - ) - ); - } else { - // TODO: fix type #7154 - dep = { ...dep, ...extractDependency(depType, depName, val!) }; - setNodeCommitTopic(dep); - dep.prettyDepType = depTypes[depType]; - deps.push(dep); - } - } - } catch (err) /* istanbul ignore next */ { - logger.debug({ fileName, depType, err }, 'Error parsing package.json'); - return null; - } - } - } - if (deps.length === 0) { - logger.debug('Package file has no deps'); - if ( - !( - packageJsonName || - packageFileVersion || - npmrc || - lernaJsonFile || - yarnWorkspacesPackages - ) - ) { - logger.debug('Skipping file'); - return null; - } - } - let skipInstalls = config.skipInstalls; - if (skipInstalls === null) { - if ((hasFancyRefs && lockFiles.npmLock) || yarnZeroInstall) { - // https://github.com/npm/cli/issues/1432 - // Explanation: - // - npm install --package-lock-only is buggy for transitive deps in file: and npm: references - // - So we set skipInstalls to false if file: or npm: refs are found *and* the user hasn't explicitly set the value already - // - Also, do not skip install if Yarn zero-install is used - logger.debug('Automatically setting skipInstalls to false'); - skipInstalls = false; - } else { - skipInstalls = true; - } - } + for (const depType of Object.keys(depTypes) as (keyof typeof depTypes)[]) { + let dependencies = packageJson[depType]; + if (dependencies) { + try { + if (depType === "packageManager") { + const match = regEx("^(?.+)@(?.+)$").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 #7154 + deps.push( + ...extractOverrideDepsRec( + [depName], + val as unknown as NpmManagerData + ) + ); + } else { + // TODO: fix type #7154 + dep = { ...dep, ...extractDependency(depType, depName, val!) }; + setNodeCommitTopic(dep); + dep.prettyDepType = depTypes[depType]; + deps.push(dep); + } + } + } catch (err) /* istanbul ignore next */ { + logger.debug({ fileName, depType, err }, "Error parsing package.json"); + return null; + } + } + } + if (deps.length === 0) { + logger.debug("Package file has no deps"); + if ( + !( + packageJsonName || + packageFileVersion || + npmrc || + lernaJsonFile || + yarnWorkspacesPackages + ) + ) { + logger.debug("Skipping file"); + return null; + } + } + let skipInstalls = config.skipInstalls; + if (skipInstalls === null) { + if ((hasFancyRefs && lockFiles.npmLock) || yarnZeroInstall) { + // https://github.com/npm/cli/issues/1432 + // Explanation: + // - npm install --package-lock-only is buggy for transitive deps in file: and npm: references + // - So we set skipInstalls to false if file: or npm: refs are found *and* the user hasn't explicitly set the value already + // - Also, do not skip install if Yarn zero-install is used + logger.debug("Automatically setting skipInstalls to false"); + skipInstalls = false; + } else { + skipInstalls = true; + } + } - return { - deps, - packageJsonName, - packageFileVersion, - npmrc, - ...lockFiles, - managerData: { - lernaJsonFile, - yarnZeroInstall, - hasPackageManager: is.nonEmptyStringAndNotWhitespace( - packageJson.packageManager - ), - }, - lernaClient, - lernaPackages, - skipInstalls, - yarnWorkspacesPackages, - constraints, - }; + return { + deps, + packageJsonName, + packageFileVersion, + npmrc, + ...lockFiles, + managerData: { + lernaJsonFile, + yarnZeroInstall, + hasPackageManager: is.nonEmptyStringAndNotWhitespace( + packageJson.packageManager + ), + }, + lernaClient, + lernaPackages, + skipInstalls, + yarnWorkspacesPackages, + constraints, + }; } export async function postExtract(packageFiles: PackageFile[]): Promise { - await detectMonorepos(packageFiles); - await getLockedVersions(packageFiles); + await detectMonorepos(packageFiles); + await getLockedVersions(packageFiles); } export async function extractAllPackageFiles( - config: ExtractConfig, - packageFiles: string[] + config: ExtractConfig, + packageFiles: string[] ): Promise { - const npmFiles: PackageFile[] = []; - for (const packageFile of packageFiles) { - const content = await readLocalFile(packageFile, 'utf8'); - // istanbul ignore else - if (content) { - const deps = await extractPackageFile(content, packageFile, config); - if (deps) { - npmFiles.push({ - packageFile, - ...deps, - }); - } - } else { - logger.debug(`No content found in ${packageFile}`); - } - } + const npmFiles: PackageFile[] = []; + for (const packageFile of packageFiles) { + const content = await readLocalFile(packageFile, "utf8"); + // istanbul ignore else + if (content) { + const deps = await extractPackageFile(content, packageFile, config); + if (deps) { + npmFiles.push({ + packageFile, + ...deps, + }); + } + } else { + logger.debug(`No content found in ${packageFile}`); + } + } - await postExtract(npmFiles); - return npmFiles; + await postExtract(npmFiles); + return npmFiles; } function setNodeCommitTopic(dep: NpmManagerData): void { - // This is a special case for Node.js to group it together with other managers - if (dep.depName === 'node') { - dep.commitMessageTopic = 'Node.js'; - } + // This is a special case for Node.js to group it together with other managers + if (dep.depName === "node") { + dep.commitMessageTopic = "Node.js"; + } } From 3403a67dedee53cfa4df2f32ca61fb1ead334b86 Mon Sep 17 00:00:00 2001 From: Pataar Date: Sun, 13 Nov 2022 20:00:08 +0100 Subject: [PATCH 2/9] style: reformat --- lib/modules/manager/npm/extract/index.ts | 954 +++++++++++------------ 1 file changed, 477 insertions(+), 477 deletions(-) diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index bee4f9ac0eff2a..a53f9da21cff8f 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -1,515 +1,515 @@ -import is from "@sindresorhus/is"; -import validateNpmPackageName from "validate-npm-package-name"; -import { GlobalConfig } from "../../../../config/global"; -import { CONFIG_VALIDATION } from "../../../../constants/error-messages"; -import { logger } from "../../../../logger"; -import { getSiblingFileName, readLocalFile } from "../../../../util/fs"; -import { newlineRegex, regEx } from "../../../../util/regex"; -import { GithubTagsDatasource } from "../../../datasource/github-tags"; -import { NpmDatasource } from "../../../datasource/npm"; -import * as nodeVersioning from "../../../versioning/node"; -import { isValid, isVersion } from "../../../versioning/npm"; +import is from '@sindresorhus/is'; +import validateNpmPackageName from 'validate-npm-package-name'; +import { GlobalConfig } from '../../../../config/global'; +import { CONFIG_VALIDATION } from '../../../../constants/error-messages'; +import { logger } from '../../../../logger'; +import { getSiblingFileName, readLocalFile } from '../../../../util/fs'; +import { newlineRegex, regEx } from '../../../../util/regex'; +import { GithubTagsDatasource } from '../../../datasource/github-tags'; +import { NpmDatasource } from '../../../datasource/npm'; +import * as nodeVersioning from '../../../versioning/node'; +import { isValid, isVersion } from '../../../versioning/npm'; import type { - ExtractConfig, - NpmLockFiles, - PackageDependency, - PackageFile, -} from "../../types"; -import type { NpmManagerData } from "../types"; -import { getLockedVersions } from "./locked-versions"; -import { detectMonorepos } from "./monorepo"; -import type { NpmPackage, NpmPackageDependency } from "./types"; -import { isZeroInstall } from "./yarn"; + ExtractConfig, + NpmLockFiles, + PackageDependency, + PackageFile, +} from '../../types'; +import type { NpmManagerData } from '../types'; +import { getLockedVersions } from './locked-versions'; +import { detectMonorepos } from './monorepo'; +import type { NpmPackage, NpmPackageDependency } from './types'; +import { isZeroInstall } from './yarn'; function parseDepName(depType: string, key: string): string { - if (depType !== "resolutions") { - return key; - } + if (depType !== 'resolutions') { + return key; + } - const [, depName] = regEx(/((?:@[^/]+\/)?[^/@]+)$/).exec(key) ?? []; - return depName; + const [, depName] = regEx(/((?:@[^/]+\/)?[^/@]+)$/).exec(key) ?? []; + return depName; } const RE_REPOSITORY_GITHUB_SSH_FORMAT = regEx( - /(?:git@)github.com:([^/]+)\/([^/.]+)(?:\.git)?/ + /(?:git@)github.com:([^/]+)\/([^/.]+)(?:\.git)?/ ); export async function extractPackageFile( - content: string, - fileName: string, - config: ExtractConfig + content: string, + fileName: string, + config: ExtractConfig ): Promise | null> { - logger.trace(`npm.extractPackageFile(${fileName})`); - logger.trace({ content }); - const deps: PackageDependency[] = []; - let packageJson: NpmPackage; - try { - packageJson = JSON.parse(content); - } catch (err) { - logger.debug(`Invalid JSON in ${fileName}`); - return null; - } + logger.trace(`npm.extractPackageFile(${fileName})`); + logger.trace({ content }); + const deps: PackageDependency[] = []; + let packageJson: NpmPackage; + try { + packageJson = JSON.parse(content); + } catch (err) { + logger.debug(`Invalid JSON in ${fileName}`); + return null; + } - if (packageJson._id && packageJson._args && packageJson._from) { - logger.debug("Ignoring vendorised package.json"); - return null; - } - if (fileName !== "package.json" && packageJson.renovate) { - const error = new Error(CONFIG_VALIDATION); - error.validationSource = fileName; - error.validationError = - "Nested package.json must not contain renovate configuration. Please use `packageRules` with `matchPaths` in your main config instead."; - throw error; - } - const packageJsonName = packageJson.name; - logger.debug( - `npm file ${fileName} has name ${JSON.stringify(packageJsonName)}` - ); - const packageFileVersion = packageJson.version; - let yarnWorkspacesPackages: string[] | undefined; - if (is.array(packageJson.workspaces)) { - yarnWorkspacesPackages = packageJson.workspaces; - } else { - yarnWorkspacesPackages = packageJson.workspaces?.packages; - } + if (packageJson._id && packageJson._args && packageJson._from) { + logger.debug('Ignoring vendorised package.json'); + return null; + } + if (fileName !== 'package.json' && packageJson.renovate) { + const error = new Error(CONFIG_VALIDATION); + error.validationSource = fileName; + error.validationError = + 'Nested package.json must not contain renovate configuration. Please use `packageRules` with `matchPaths` in your main config instead.'; + throw error; + } + const packageJsonName = packageJson.name; + logger.debug( + `npm file ${fileName} has name ${JSON.stringify(packageJsonName)}` + ); + const packageFileVersion = packageJson.version; + let yarnWorkspacesPackages: string[] | undefined; + if (is.array(packageJson.workspaces)) { + yarnWorkspacesPackages = packageJson.workspaces; + } else { + yarnWorkspacesPackages = packageJson.workspaces?.packages; + } - const lockFiles: NpmLockFiles = { - yarnLock: "yarn.lock", - packageLock: "package-lock.json", - shrinkwrapJson: "npm-shrinkwrap.json", - pnpmShrinkwrap: "pnpm-lock.yaml", - }; + const lockFiles: NpmLockFiles = { + yarnLock: 'yarn.lock', + packageLock: 'package-lock.json', + shrinkwrapJson: 'npm-shrinkwrap.json', + pnpmShrinkwrap: 'pnpm-lock.yaml', + }; - for (const [key, val] of Object.entries(lockFiles) as [ - "yarnLock" | "packageLock" | "shrinkwrapJson" | "pnpmShrinkwrap", - string - ][]) { - const filePath = getSiblingFileName(fileName, val); - if (await readLocalFile(filePath, "utf8")) { - lockFiles[key] = filePath; - } else { - lockFiles[key] = undefined; - } - } - lockFiles.npmLock = lockFiles.packageLock ?? lockFiles.shrinkwrapJson; - delete lockFiles.packageLock; - delete lockFiles.shrinkwrapJson; + for (const [key, val] of Object.entries(lockFiles) as [ + 'yarnLock' | 'packageLock' | 'shrinkwrapJson' | 'pnpmShrinkwrap', + string + ][]) { + const filePath = getSiblingFileName(fileName, val); + if (await readLocalFile(filePath, 'utf8')) { + lockFiles[key] = filePath; + } else { + lockFiles[key] = undefined; + } + } + lockFiles.npmLock = lockFiles.packageLock ?? lockFiles.shrinkwrapJson; + delete lockFiles.packageLock; + delete lockFiles.shrinkwrapJson; - let npmrc: string | undefined; - const npmrcFileName = getSiblingFileName(fileName, ".npmrc"); - let repoNpmrc = await readLocalFile(npmrcFileName, "utf8"); - if (is.string(repoNpmrc)) { - if (is.string(config.npmrc) && !config.npmrcMerge) { - logger.debug( - { npmrcFileName }, - "Repo .npmrc file is ignored due to config.npmrc with config.npmrcMerge=false" - ); - } else { - npmrc = config.npmrc ?? ""; - if (npmrc.length) { - if (!npmrc.endsWith("\n")) { - npmrc += "\n"; - } - } - if (repoNpmrc?.includes("package-lock")) { - logger.debug("Stripping package-lock setting from .npmrc"); - repoNpmrc = repoNpmrc.replace( - regEx(/(^|\n)package-lock.*?(\n|$)/g), - "\n" - ); - } - if (repoNpmrc.includes("=${") && !GlobalConfig.get("exposeAllEnv")) { - logger.debug( - { npmrcFileName }, - "Stripping .npmrc file of lines with variables" - ); - repoNpmrc = repoNpmrc - .split(newlineRegex) - .filter((line) => !line.includes("=${")) - .join("\n"); - } - npmrc += repoNpmrc; - } - } + let npmrc: string | undefined; + const npmrcFileName = getSiblingFileName(fileName, '.npmrc'); + let repoNpmrc = await readLocalFile(npmrcFileName, 'utf8'); + if (is.string(repoNpmrc)) { + if (is.string(config.npmrc) && !config.npmrcMerge) { + logger.debug( + { npmrcFileName }, + 'Repo .npmrc file is ignored due to config.npmrc with config.npmrcMerge=false' + ); + } else { + npmrc = config.npmrc ?? ''; + if (npmrc.length) { + if (!npmrc.endsWith('\n')) { + npmrc += '\n'; + } + } + if (repoNpmrc?.includes('package-lock')) { + logger.debug('Stripping package-lock setting from .npmrc'); + repoNpmrc = repoNpmrc.replace( + regEx(/(^|\n)package-lock.*?(\n|$)/g), + '\n' + ); + } + if (repoNpmrc.includes('=${') && !GlobalConfig.get('exposeAllEnv')) { + logger.debug( + { npmrcFileName }, + 'Stripping .npmrc file of lines with variables' + ); + repoNpmrc = repoNpmrc + .split(newlineRegex) + .filter((line) => !line.includes('=${')) + .join('\n'); + } + npmrc += repoNpmrc; + } + } - const yarnrcYmlFileName = getSiblingFileName(fileName, ".yarnrc.yml"); - const yarnZeroInstall = await isZeroInstall(yarnrcYmlFileName); + const yarnrcYmlFileName = getSiblingFileName(fileName, '.yarnrc.yml'); + const yarnZeroInstall = await isZeroInstall(yarnrcYmlFileName); - let lernaJsonFile: string | undefined; - let lernaPackages: string[] | undefined; - let lernaClient: "yarn" | "npm" | undefined; - let hasFancyRefs = false; - let lernaJson: - | { - packages: string[]; - npmClient: string; - useWorkspaces?: boolean; - } - | undefined; - try { - lernaJsonFile = getSiblingFileName(fileName, "lerna.json"); - // TODO #7154 - lernaJson = JSON.parse((await readLocalFile(lernaJsonFile, "utf8"))!); - } catch (err) /* istanbul ignore next */ { - logger.warn({ err }, "Could not parse lerna.json"); - } - if (lernaJson && !lernaJson.useWorkspaces) { - lernaPackages = lernaJson.packages; - lernaClient = - lernaJson.npmClient === "yarn" || lockFiles.yarnLock ? "yarn" : "npm"; - } else { - lernaJsonFile = undefined; - } + let lernaJsonFile: string | undefined; + let lernaPackages: string[] | undefined; + let lernaClient: 'yarn' | 'npm' | undefined; + let hasFancyRefs = false; + let lernaJson: + | { + packages: string[]; + npmClient: string; + useWorkspaces?: boolean; + } + | undefined; + try { + lernaJsonFile = getSiblingFileName(fileName, 'lerna.json'); + // TODO #7154 + lernaJson = JSON.parse((await readLocalFile(lernaJsonFile, 'utf8'))!); + } catch (err) /* istanbul ignore next */ { + logger.warn({ err }, 'Could not parse lerna.json'); + } + if (lernaJson && !lernaJson.useWorkspaces) { + lernaPackages = lernaJson.packages; + lernaClient = + lernaJson.npmClient === 'yarn' || lockFiles.yarnLock ? 'yarn' : 'npm'; + } else { + lernaJsonFile = undefined; + } - const depTypes = { - dependencies: "dependency", - devDependencies: "devDependency", - optionalDependencies: "optionalDependency", - peerDependencies: "peerDependency", - engines: "engine", - volta: "volta", - resolutions: "resolutions", - packageManager: "packageManager", - overrides: "overrides", - }; + const depTypes = { + dependencies: 'dependency', + devDependencies: 'devDependency', + optionalDependencies: 'optionalDependency', + peerDependencies: 'peerDependency', + engines: 'engine', + volta: 'volta', + resolutions: 'resolutions', + packageManager: 'packageManager', + overrides: 'overrides', + }; - const constraints: Record = {}; + const constraints: Record = {}; - function extractDependency( - depType: string, - depName: string, - input: string - ): PackageDependency { - const dep: PackageDependency = {}; - if (!validateNpmPackageName(depName).validForOldPackages) { - dep.skipReason = "invalid-name"; - return dep; - } - if (typeof input !== "string") { - dep.skipReason = "invalid-value"; - return dep; - } - dep.currentValue = input.trim(); - if (depType === "engines" || depType === "packageManager") { - if (depName === "node") { - dep.datasource = GithubTagsDatasource.id; - dep.packageName = "nodejs/node"; - dep.versioning = nodeVersioning.id; - constraints.node = dep.currentValue; - } else if (depName === "yarn") { - dep.datasource = NpmDatasource.id; - dep.commitMessageTopic = "Yarn"; - constraints.yarn = dep.currentValue; - if ( - dep.currentValue.startsWith("2") || - dep.currentValue.startsWith("3") - ) { - dep.packageName = "@yarnpkg/cli"; - } - } else if (depName === "npm") { - dep.datasource = NpmDatasource.id; - dep.commitMessageTopic = "npm"; - constraints.npm = dep.currentValue; - } else if (depName === "pnpm") { - dep.datasource = NpmDatasource.id; - dep.commitMessageTopic = "pnpm"; - } else if (depName === "vscode") { - dep.datasource = GithubTagsDatasource.id; - dep.packageName = "microsoft/vscode"; - constraints.vscode = dep.currentValue; - } else { - dep.skipReason = "unknown-engines"; - } - if (!isValid(dep.currentValue)) { - dep.skipReason = "unknown-version"; - } - return dep; - } + function extractDependency( + depType: string, + depName: string, + input: string + ): PackageDependency { + const dep: PackageDependency = {}; + if (!validateNpmPackageName(depName).validForOldPackages) { + dep.skipReason = 'invalid-name'; + return dep; + } + if (typeof input !== 'string') { + dep.skipReason = 'invalid-value'; + return dep; + } + dep.currentValue = input.trim(); + if (depType === 'engines' || depType === 'packageManager') { + if (depName === 'node') { + dep.datasource = GithubTagsDatasource.id; + dep.packageName = 'nodejs/node'; + dep.versioning = nodeVersioning.id; + constraints.node = dep.currentValue; + } else if (depName === 'yarn') { + dep.datasource = NpmDatasource.id; + dep.commitMessageTopic = 'Yarn'; + constraints.yarn = dep.currentValue; + if ( + dep.currentValue.startsWith('2') || + dep.currentValue.startsWith('3') + ) { + dep.packageName = '@yarnpkg/cli'; + } + } else if (depName === 'npm') { + dep.datasource = NpmDatasource.id; + dep.commitMessageTopic = 'npm'; + constraints.npm = dep.currentValue; + } else if (depName === 'pnpm') { + dep.datasource = NpmDatasource.id; + dep.commitMessageTopic = 'pnpm'; + } else if (depName === 'vscode') { + dep.datasource = GithubTagsDatasource.id; + dep.packageName = 'microsoft/vscode'; + constraints.vscode = dep.currentValue; + } else { + dep.skipReason = 'unknown-engines'; + } + if (!isValid(dep.currentValue)) { + dep.skipReason = 'unknown-version'; + } + return dep; + } - // support for volta - if (depType === "volta") { - if (depName === "node") { - dep.datasource = GithubTagsDatasource.id; - dep.packageName = "nodejs/node"; - dep.versioning = nodeVersioning.id; - } else if (depName === "yarn") { - dep.datasource = NpmDatasource.id; - dep.commitMessageTopic = "Yarn"; - if ( - dep.currentValue.startsWith("2") || - dep.currentValue.startsWith("3") - ) { - dep.packageName = "@yarnpkg/cli"; - } - } else if (depName === "npm") { - dep.datasource = NpmDatasource.id; - } else { - dep.skipReason = "unknown-volta"; - } - if (!isValid(dep.currentValue)) { - dep.skipReason = "unknown-version"; - } - return dep; - } + // support for volta + if (depType === 'volta') { + if (depName === 'node') { + dep.datasource = GithubTagsDatasource.id; + dep.packageName = 'nodejs/node'; + dep.versioning = nodeVersioning.id; + } else if (depName === 'yarn') { + dep.datasource = NpmDatasource.id; + dep.commitMessageTopic = 'Yarn'; + if ( + dep.currentValue.startsWith('2') || + dep.currentValue.startsWith('3') + ) { + dep.packageName = '@yarnpkg/cli'; + } + } else if (depName === 'npm') { + dep.datasource = NpmDatasource.id; + } else { + dep.skipReason = 'unknown-volta'; + } + if (!isValid(dep.currentValue)) { + dep.skipReason = 'unknown-version'; + } + return dep; + } - if (dep.currentValue.startsWith("npm:")) { - dep.npmPackageAlias = true; - hasFancyRefs = true; - const valSplit = dep.currentValue.replace("npm:", "").split("@"); - if (valSplit.length === 2) { - dep.packageName = valSplit[0]; - dep.currentValue = valSplit[1]; - } else if (valSplit.length === 3) { - dep.packageName = valSplit[0] + "@" + valSplit[1]; - dep.currentValue = valSplit[2]; - } else { - logger.debug("Invalid npm package alias: " + dep.currentValue); - } - } - if (dep.currentValue.startsWith("file:")) { - dep.skipReason = "file"; - hasFancyRefs = true; - return dep; - } - if (isValid(dep.currentValue)) { - dep.datasource = NpmDatasource.id; - if (dep.currentValue === "") { - dep.skipReason = "empty"; - } - return dep; - } - const hashSplit = dep.currentValue.split("#"); - if (hashSplit.length !== 2) { - dep.skipReason = "unknown-version"; - return dep; - } - const [depNamePart, depRefPart] = hashSplit; + if (dep.currentValue.startsWith('npm:')) { + dep.npmPackageAlias = true; + hasFancyRefs = true; + const valSplit = dep.currentValue.replace('npm:', '').split('@'); + if (valSplit.length === 2) { + dep.packageName = valSplit[0]; + dep.currentValue = valSplit[1]; + } else if (valSplit.length === 3) { + dep.packageName = valSplit[0] + '@' + valSplit[1]; + dep.currentValue = valSplit[2]; + } else { + logger.debug('Invalid npm package alias: ' + dep.currentValue); + } + } + if (dep.currentValue.startsWith('file:')) { + dep.skipReason = 'file'; + hasFancyRefs = true; + return dep; + } + if (isValid(dep.currentValue)) { + dep.datasource = NpmDatasource.id; + if (dep.currentValue === '') { + dep.skipReason = 'empty'; + } + return dep; + } + const hashSplit = dep.currentValue.split('#'); + if (hashSplit.length !== 2) { + dep.skipReason = 'unknown-version'; + return dep; + } + const [depNamePart, depRefPart] = hashSplit; - let githubOwnerRepo: string; - let githubOwner: string; - let githubRepo: string; - const matchUrlSshFormat = RE_REPOSITORY_GITHUB_SSH_FORMAT.exec(depNamePart); - if (matchUrlSshFormat === null) { - githubOwnerRepo = depNamePart - .replace(regEx(/^github:/), "") - .replace(regEx(/^git\+/), "") - .replace(regEx(/^https:\/\/github\.com\//), "") - .replace(regEx(/\.git$/), ""); - const githubRepoSplit = githubOwnerRepo.split("/"); - if (githubRepoSplit.length !== 2) { - dep.skipReason = "unknown-version"; - return dep; - } - [githubOwner, githubRepo] = githubRepoSplit; - } else { - githubOwner = matchUrlSshFormat[1]; - githubRepo = matchUrlSshFormat[2]; - githubOwnerRepo = `${githubOwner}/${githubRepo}`; - } - const githubValidRegex = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; // TODO #12872 lookahead - if ( - !githubValidRegex.test(githubOwner) || - !githubValidRegex.test(githubRepo) - ) { - dep.skipReason = "unknown-version"; - return dep; - } - if (isVersion(depRefPart)) { - dep.currentRawValue = dep.currentValue; - dep.currentValue = depRefPart; - dep.datasource = GithubTagsDatasource.id; - dep.packageName = githubOwnerRepo; - dep.pinDigests = false; - } else if ( - regEx(/^[0-9a-f]{7}$/).test(depRefPart) || - regEx(/^[0-9a-f]{40}$/).test(depRefPart) - ) { - dep.currentRawValue = dep.currentValue; - dep.currentValue = null; - dep.currentDigest = depRefPart; - dep.datasource = GithubTagsDatasource.id; - dep.packageName = githubOwnerRepo; - } else { - dep.skipReason = "unversioned-reference"; - return dep; - } - dep.sourceUrl = `https://github.com/${githubOwnerRepo}`; - dep.gitRef = true; - return dep; - } + let githubOwnerRepo: string; + let githubOwner: string; + let githubRepo: string; + const matchUrlSshFormat = RE_REPOSITORY_GITHUB_SSH_FORMAT.exec(depNamePart); + if (matchUrlSshFormat === null) { + githubOwnerRepo = depNamePart + .replace(regEx(/^github:/), '') + .replace(regEx(/^git\+/), '') + .replace(regEx(/^https:\/\/github\.com\//), '') + .replace(regEx(/\.git$/), ''); + const githubRepoSplit = githubOwnerRepo.split('/'); + if (githubRepoSplit.length !== 2) { + dep.skipReason = 'unknown-version'; + return dep; + } + [githubOwner, githubRepo] = githubRepoSplit; + } else { + githubOwner = matchUrlSshFormat[1]; + githubRepo = matchUrlSshFormat[2]; + githubOwnerRepo = `${githubOwner}/${githubRepo}`; + } + const githubValidRegex = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; // TODO #12872 lookahead + if ( + !githubValidRegex.test(githubOwner) || + !githubValidRegex.test(githubRepo) + ) { + dep.skipReason = 'unknown-version'; + return dep; + } + if (isVersion(depRefPart)) { + dep.currentRawValue = dep.currentValue; + dep.currentValue = depRefPart; + dep.datasource = GithubTagsDatasource.id; + dep.packageName = githubOwnerRepo; + dep.pinDigests = false; + } else if ( + regEx(/^[0-9a-f]{7}$/).test(depRefPart) || + regEx(/^[0-9a-f]{40}$/).test(depRefPart) + ) { + dep.currentRawValue = dep.currentValue; + dep.currentValue = null; + dep.currentDigest = depRefPart; + dep.datasource = GithubTagsDatasource.id; + dep.packageName = githubOwnerRepo; + } else { + dep.skipReason = 'unversioned-reference'; + return dep; + } + dep.sourceUrl = `https://github.com/${githubOwnerRepo}`; + dep.gitRef = true; + return dep; + } - /** - * Used when there is a json object as a value in overrides block. - * @param parents - * @param child - * @returns PackageDependency array - */ - function extractOverrideDepsRec( - parents: string[], - child: NpmManagerData - ): PackageDependency[] { - const deps: PackageDependency[] = []; - if (!child || is.emptyObject(child)) { - return deps; - } - for (const [overrideName, versionValue] of Object.entries(child)) { - if (is.string(versionValue)) { - // special handling for "." override depenency name - // "." means the constraint is applied to the parent dep - const currDepName = - overrideName === "." ? parents[parents.length - 1] : overrideName; - const dep: PackageDependency = { - depName: currDepName, - depType: "overrides", - managerData: { parents: parents.slice() }, // set parents for dependency - }; - setNodeCommitTopic(dep); - deps.push({ - ...dep, - ...extractDependency("overrides", currDepName, versionValue), - }); - } else { - // versionValue is an object, run recursively. - parents.push(overrideName); - const depsOfObject = extractOverrideDepsRec(parents, versionValue); - deps.push(...depsOfObject); - } - } - parents.pop(); - return deps; - } + /** + * Used when there is a json object as a value in overrides block. + * @param parents + * @param child + * @returns PackageDependency array + */ + function extractOverrideDepsRec( + parents: string[], + child: NpmManagerData + ): PackageDependency[] { + const deps: PackageDependency[] = []; + if (!child || is.emptyObject(child)) { + return deps; + } + for (const [overrideName, versionValue] of Object.entries(child)) { + if (is.string(versionValue)) { + // special handling for "." override depenency name + // "." means the constraint is applied to the parent dep + const currDepName = + overrideName === '.' ? parents[parents.length - 1] : overrideName; + const dep: PackageDependency = { + depName: currDepName, + depType: 'overrides', + managerData: { parents: parents.slice() }, // set parents for dependency + }; + setNodeCommitTopic(dep); + deps.push({ + ...dep, + ...extractDependency('overrides', currDepName, versionValue), + }); + } else { + // versionValue is an object, run recursively. + parents.push(overrideName); + const depsOfObject = extractOverrideDepsRec(parents, versionValue); + deps.push(...depsOfObject); + } + } + parents.pop(); + return deps; + } - for (const depType of Object.keys(depTypes) as (keyof typeof depTypes)[]) { - let dependencies = packageJson[depType]; - if (dependencies) { - try { - if (depType === "packageManager") { - const match = regEx("^(?.+)@(?.+)$").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 #7154 - deps.push( - ...extractOverrideDepsRec( - [depName], - val as unknown as NpmManagerData - ) - ); - } else { - // TODO: fix type #7154 - dep = { ...dep, ...extractDependency(depType, depName, val!) }; - setNodeCommitTopic(dep); - dep.prettyDepType = depTypes[depType]; - deps.push(dep); - } - } - } catch (err) /* istanbul ignore next */ { - logger.debug({ fileName, depType, err }, "Error parsing package.json"); - return null; - } - } - } - if (deps.length === 0) { - logger.debug("Package file has no deps"); - if ( - !( - packageJsonName || - packageFileVersion || - npmrc || - lernaJsonFile || - yarnWorkspacesPackages - ) - ) { - logger.debug("Skipping file"); - return null; - } - } - let skipInstalls = config.skipInstalls; - if (skipInstalls === null) { - if ((hasFancyRefs && lockFiles.npmLock) || yarnZeroInstall) { - // https://github.com/npm/cli/issues/1432 - // Explanation: - // - npm install --package-lock-only is buggy for transitive deps in file: and npm: references - // - So we set skipInstalls to false if file: or npm: refs are found *and* the user hasn't explicitly set the value already - // - Also, do not skip install if Yarn zero-install is used - logger.debug("Automatically setting skipInstalls to false"); - skipInstalls = false; - } else { - skipInstalls = true; - } - } + for (const depType of Object.keys(depTypes) as (keyof typeof depTypes)[]) { + let dependencies = packageJson[depType]; + if (dependencies) { + try { + if (depType === 'packageManager') { + const match = regEx('^(?.+)@(?.+)$').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 #7154 + deps.push( + ...extractOverrideDepsRec( + [depName], + val as unknown as NpmManagerData + ) + ); + } else { + // TODO: fix type #7154 + dep = { ...dep, ...extractDependency(depType, depName, val!) }; + setNodeCommitTopic(dep); + dep.prettyDepType = depTypes[depType]; + deps.push(dep); + } + } + } catch (err) /* istanbul ignore next */ { + logger.debug({ fileName, depType, err }, 'Error parsing package.json'); + return null; + } + } + } + if (deps.length === 0) { + logger.debug('Package file has no deps'); + if ( + !( + packageJsonName || + packageFileVersion || + npmrc || + lernaJsonFile || + yarnWorkspacesPackages + ) + ) { + logger.debug('Skipping file'); + return null; + } + } + let skipInstalls = config.skipInstalls; + if (skipInstalls === null) { + if ((hasFancyRefs && lockFiles.npmLock) || yarnZeroInstall) { + // https://github.com/npm/cli/issues/1432 + // Explanation: + // - npm install --package-lock-only is buggy for transitive deps in file: and npm: references + // - So we set skipInstalls to false if file: or npm: refs are found *and* the user hasn't explicitly set the value already + // - Also, do not skip install if Yarn zero-install is used + logger.debug('Automatically setting skipInstalls to false'); + skipInstalls = false; + } else { + skipInstalls = true; + } + } - return { - deps, - packageJsonName, - packageFileVersion, - npmrc, - ...lockFiles, - managerData: { - lernaJsonFile, - yarnZeroInstall, - hasPackageManager: is.nonEmptyStringAndNotWhitespace( - packageJson.packageManager - ), - }, - lernaClient, - lernaPackages, - skipInstalls, - yarnWorkspacesPackages, - constraints, - }; + return { + deps, + packageJsonName, + packageFileVersion, + npmrc, + ...lockFiles, + managerData: { + lernaJsonFile, + yarnZeroInstall, + hasPackageManager: is.nonEmptyStringAndNotWhitespace( + packageJson.packageManager + ), + }, + lernaClient, + lernaPackages, + skipInstalls, + yarnWorkspacesPackages, + constraints, + }; } export async function postExtract(packageFiles: PackageFile[]): Promise { - await detectMonorepos(packageFiles); - await getLockedVersions(packageFiles); + await detectMonorepos(packageFiles); + await getLockedVersions(packageFiles); } export async function extractAllPackageFiles( - config: ExtractConfig, - packageFiles: string[] + config: ExtractConfig, + packageFiles: string[] ): Promise { - const npmFiles: PackageFile[] = []; - for (const packageFile of packageFiles) { - const content = await readLocalFile(packageFile, "utf8"); - // istanbul ignore else - if (content) { - const deps = await extractPackageFile(content, packageFile, config); - if (deps) { - npmFiles.push({ - packageFile, - ...deps, - }); - } - } else { - logger.debug(`No content found in ${packageFile}`); - } - } + const npmFiles: PackageFile[] = []; + for (const packageFile of packageFiles) { + const content = await readLocalFile(packageFile, 'utf8'); + // istanbul ignore else + if (content) { + const deps = await extractPackageFile(content, packageFile, config); + if (deps) { + npmFiles.push({ + packageFile, + ...deps, + }); + } + } else { + logger.debug(`No content found in ${packageFile}`); + } + } - await postExtract(npmFiles); - return npmFiles; + await postExtract(npmFiles); + return npmFiles; } function setNodeCommitTopic(dep: NpmManagerData): void { - // This is a special case for Node.js to group it together with other managers - if (dep.depName === "node") { - dep.commitMessageTopic = "Node.js"; - } + // This is a special case for Node.js to group it together with other managers + if (dep.depName === 'node') { + dep.commitMessageTopic = 'Node.js'; + } } From 41d4dffdeff1ff5f869ea44e68ee64a47f556cc9 Mon Sep 17 00:00:00 2001 From: pataar Date: Sun, 13 Nov 2022 20:35:52 +0100 Subject: [PATCH 3/9] test: fix tests --- .../extract/__snapshots__/index.spec.ts.snap | 54 +++++++++++++++++++ lib/modules/manager/npm/extract/index.spec.ts | 42 +++++++++++++++ lib/modules/manager/npm/extract/index.ts | 10 ++-- 3 files changed, 102 insertions(+), 4 deletions(-) diff --git a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap index 9962ebc67ae658..ed9cedb0e3581e 100644 --- a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap +++ b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap @@ -480,6 +480,60 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta } `; +exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta yarn higher than 1 1`] = ` +{ + "constraints": { + "node": "16.0.0", + }, + "deps": [ + { + "commitMessageTopic": "Node.js", + "currentValue": "16.0.0", + "datasource": "github-tags", + "depName": "node", + "depType": "engines", + "packageName": "nodejs/node", + "prettyDepType": "engine", + "versioning": "node", + }, + { + "commitMessageTopic": "Node.js", + "currentValue": "16.0.0", + "datasource": "github-tags", + "depName": "node", + "depType": "volta", + "packageName": "nodejs/node", + "prettyDepType": "volta", + "versioning": "node", + }, + { + "commitMessageTopic": "Yarn", + "currentValue": "3.2.4", + "datasource": "npm", + "depName": "yarn", + "depType": "volta", + "packageName": "@yarnpkg/cli", + "prettyDepType": "volta", + }, + ], + "lernaClient": undefined, + "lernaPackages": undefined, + "managerData": { + "hasPackageManager": false, + "lernaJsonFile": undefined, + "yarnZeroInstall": false, + }, + "npmLock": undefined, + "npmrc": undefined, + "packageFileVersion": undefined, + "packageJsonName": undefined, + "pnpmShrinkwrap": undefined, + "skipInstalls": true, + "yarnLock": undefined, + "yarnWorkspacesPackages": undefined, +} +`; + exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta yarn unknown-version 1`] = ` { "constraints": { diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts index bf5095ee46b317..70fea48badf66d 100644 --- a/lib/modules/manager/npm/extract/index.spec.ts +++ b/lib/modules/manager/npm/extract/index.spec.ts @@ -483,6 +483,48 @@ describe('modules/manager/npm/extract/index', () => { }); }); + it('extracts volta yarn higher than 1', async () => { + const pJson = { + main: 'index.js', + engines: { + node: '16.0.0', + }, + volta: { + node: '16.0.0', + yarn: '3.2.4', + }, + }; + const pJsonStr = JSON.stringify(pJson); + const res = await npmExtract.extractPackageFile( + pJsonStr, + 'package.json', + defaultConfig + ); + expect(res).toMatchSnapshot({ + deps: [ + {}, + { + commitMessageTopic: 'Node.js', + currentValue: '16.0.0', + datasource: 'github-tags', + depName: 'node', + depType: 'volta', + packageName: 'nodejs/node', + prettyDepType: 'volta', + versioning: 'node', + }, + { + commitMessageTopic: 'Yarn', + currentValue: '3.2.4', + datasource: 'npm', + depName: 'yarn', + depType: 'volta', + prettyDepType: 'volta', + }, + ], + }); + }); + it('extracts non-npmjs', async () => { const pJson = { dependencies: { diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index a53f9da21cff8f..8f35afe9ddcf30 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -1,3 +1,4 @@ +import { major } from '@renovatebot/ruby-semver'; import is from '@sindresorhus/is'; import validateNpmPackageName from 'validate-npm-package-name'; import { GlobalConfig } from '../../../../config/global'; @@ -20,6 +21,7 @@ import { getLockedVersions } from './locked-versions'; import { detectMonorepos } from './monorepo'; import type { NpmPackage, NpmPackageDependency } from './types'; import { isZeroInstall } from './yarn'; +import semver from 'semver'; function parseDepName(depType: string, key: string): string { if (depType !== 'resolutions') { @@ -201,8 +203,8 @@ export async function extractPackageFile( dep.commitMessageTopic = 'Yarn'; constraints.yarn = dep.currentValue; if ( - dep.currentValue.startsWith('2') || - dep.currentValue.startsWith('3') + semver.valid(dep.currentValue) && + semver.major(dep.currentValue) > 1 ) { dep.packageName = '@yarnpkg/cli'; } @@ -236,8 +238,8 @@ export async function extractPackageFile( dep.datasource = NpmDatasource.id; dep.commitMessageTopic = 'Yarn'; if ( - dep.currentValue.startsWith('2') || - dep.currentValue.startsWith('3') + semver.valid(dep.currentValue) && + semver.major(dep.currentValue) > 1 ) { dep.packageName = '@yarnpkg/cli'; } From 524c0a9e47d574048b3d893d8f2dbe5d07f1bb3c Mon Sep 17 00:00:00 2001 From: pataar Date: Sun, 13 Nov 2022 20:42:06 +0100 Subject: [PATCH 4/9] fix linter issues --- lib/modules/manager/npm/extract/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index 8f35afe9ddcf30..dda7e93e07c4b4 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -1,5 +1,5 @@ -import { major } from '@renovatebot/ruby-semver'; import is from '@sindresorhus/is'; +import semver from 'semver'; import validateNpmPackageName from 'validate-npm-package-name'; import { GlobalConfig } from '../../../../config/global'; import { CONFIG_VALIDATION } from '../../../../constants/error-messages'; @@ -21,7 +21,6 @@ import { getLockedVersions } from './locked-versions'; import { detectMonorepos } from './monorepo'; import type { NpmPackage, NpmPackageDependency } from './types'; import { isZeroInstall } from './yarn'; -import semver from 'semver'; function parseDepName(depType: string, key: string): string { if (depType !== 'resolutions') { From 4509a4a2bfea8c3295173edc905a9e11fcbb2428 Mon Sep 17 00:00:00 2001 From: pataar Date: Sun, 13 Nov 2022 20:42:38 +0100 Subject: [PATCH 5/9] Update lib/modules/manager/npm/extract/index.spec.ts Co-authored-by: Michael Kriese --- lib/modules/manager/npm/extract/index.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts index 70fea48badf66d..608ebea5d5b296 100644 --- a/lib/modules/manager/npm/extract/index.spec.ts +++ b/lib/modules/manager/npm/extract/index.spec.ts @@ -500,7 +500,7 @@ describe('modules/manager/npm/extract/index', () => { 'package.json', defaultConfig ); - expect(res).toMatchSnapshot({ + expect(res).toMatchObject({ deps: [ {}, { From d35571850307e009f3f031520d2fd6a07a8e8da4 Mon Sep 17 00:00:00 2001 From: pataar Date: Sun, 13 Nov 2022 20:54:52 +0100 Subject: [PATCH 6/9] use different way of versioning --- lib/modules/manager/npm/extract/index.ts | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index dda7e93e07c4b4..1dd37aee894e3f 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -1,5 +1,4 @@ import is from '@sindresorhus/is'; -import semver from 'semver'; import validateNpmPackageName from 'validate-npm-package-name'; import { GlobalConfig } from '../../../../config/global'; import { CONFIG_VALIDATION } from '../../../../constants/error-messages'; @@ -9,7 +8,7 @@ import { newlineRegex, regEx } from '../../../../util/regex'; import { GithubTagsDatasource } from '../../../datasource/github-tags'; import { NpmDatasource } from '../../../datasource/npm'; import * as nodeVersioning from '../../../versioning/node'; -import { isValid, isVersion } from '../../../versioning/npm'; +import { isValid, isVersion, api } from '../../../versioning/npm'; import type { ExtractConfig, NpmLockFiles, @@ -201,10 +200,8 @@ export async function extractPackageFile( dep.datasource = NpmDatasource.id; dep.commitMessageTopic = 'Yarn'; constraints.yarn = dep.currentValue; - if ( - semver.valid(dep.currentValue) && - semver.major(dep.currentValue) > 1 - ) { + const major = api.getMajor(dep.currentValue); + if (isValid(dep.currentValue) && major && major > 1) { dep.packageName = '@yarnpkg/cli'; } } else if (depName === 'npm') { @@ -236,10 +233,8 @@ export async function extractPackageFile( } else if (depName === 'yarn') { dep.datasource = NpmDatasource.id; dep.commitMessageTopic = 'Yarn'; - if ( - semver.valid(dep.currentValue) && - semver.major(dep.currentValue) > 1 - ) { + const major = api.getMajor(dep.currentValue); + if (isValid(dep.currentValue) && major && major > 1) { dep.packageName = '@yarnpkg/cli'; } } else if (depName === 'npm') { From 4f13c017b5f77a66fc57af69bc08b83fae609fdc Mon Sep 17 00:00:00 2001 From: pataar Date: Sun, 13 Nov 2022 21:01:00 +0100 Subject: [PATCH 7/9] test: fix tests --- .../extract/__snapshots__/index.spec.ts.snap | 54 ------------------- lib/modules/manager/npm/extract/index.ts | 12 +++-- 2 files changed, 7 insertions(+), 59 deletions(-) diff --git a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap index ed9cedb0e3581e..9962ebc67ae658 100644 --- a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap +++ b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap @@ -480,60 +480,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta } `; -exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta yarn higher than 1 1`] = ` -{ - "constraints": { - "node": "16.0.0", - }, - "deps": [ - { - "commitMessageTopic": "Node.js", - "currentValue": "16.0.0", - "datasource": "github-tags", - "depName": "node", - "depType": "engines", - "packageName": "nodejs/node", - "prettyDepType": "engine", - "versioning": "node", - }, - { - "commitMessageTopic": "Node.js", - "currentValue": "16.0.0", - "datasource": "github-tags", - "depName": "node", - "depType": "volta", - "packageName": "nodejs/node", - "prettyDepType": "volta", - "versioning": "node", - }, - { - "commitMessageTopic": "Yarn", - "currentValue": "3.2.4", - "datasource": "npm", - "depName": "yarn", - "depType": "volta", - "packageName": "@yarnpkg/cli", - "prettyDepType": "volta", - }, - ], - "lernaClient": undefined, - "lernaPackages": undefined, - "managerData": { - "hasPackageManager": false, - "lernaJsonFile": undefined, - "yarnZeroInstall": false, - }, - "npmLock": undefined, - "npmrc": undefined, - "packageFileVersion": undefined, - "packageJsonName": undefined, - "pnpmShrinkwrap": undefined, - "skipInstalls": true, - "yarnLock": undefined, - "yarnWorkspacesPackages": undefined, -} -`; - exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta yarn unknown-version 1`] = ` { "constraints": { diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index 1dd37aee894e3f..89e3a71bc59db9 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -8,7 +8,7 @@ import { newlineRegex, regEx } from '../../../../util/regex'; import { GithubTagsDatasource } from '../../../datasource/github-tags'; import { NpmDatasource } from '../../../datasource/npm'; import * as nodeVersioning from '../../../versioning/node'; -import { isValid, isVersion, api } from '../../../versioning/npm'; +import { api, isValid, isVersion } from '../../../versioning/npm'; import type { ExtractConfig, NpmLockFiles, @@ -200,8 +200,9 @@ export async function extractPackageFile( dep.datasource = NpmDatasource.id; dep.commitMessageTopic = 'Yarn'; constraints.yarn = dep.currentValue; - const major = api.getMajor(dep.currentValue); - if (isValid(dep.currentValue) && major && major > 1) { + const major = + isVersion(dep.currentValue) && api.getMajor(dep.currentValue); + if (major && major > 1) { dep.packageName = '@yarnpkg/cli'; } } else if (depName === 'npm') { @@ -233,8 +234,9 @@ export async function extractPackageFile( } else if (depName === 'yarn') { dep.datasource = NpmDatasource.id; dep.commitMessageTopic = 'Yarn'; - const major = api.getMajor(dep.currentValue); - if (isValid(dep.currentValue) && major && major > 1) { + const major = + isVersion(dep.currentValue) && api.getMajor(dep.currentValue); + if (major && major > 1) { dep.packageName = '@yarnpkg/cli'; } } else if (depName === 'npm') { From 02072ef0ec39035528d3082dbe1708ec3cb88682 Mon Sep 17 00:00:00 2001 From: pataar Date: Mon, 14 Nov 2022 09:20:36 +0100 Subject: [PATCH 8/9] update test --- lib/modules/manager/npm/extract/index.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts index 608ebea5d5b296..471808cbb2dc78 100644 --- a/lib/modules/manager/npm/extract/index.spec.ts +++ b/lib/modules/manager/npm/extract/index.spec.ts @@ -500,6 +500,8 @@ describe('modules/manager/npm/extract/index', () => { 'package.json', defaultConfig ); + + console.log(res); expect(res).toMatchObject({ deps: [ {}, @@ -520,6 +522,7 @@ describe('modules/manager/npm/extract/index', () => { depName: 'yarn', depType: 'volta', prettyDepType: 'volta', + packageName: '@yarnpkg/cli', }, ], }); From 09eaa02f3bf131b8145f75f91199bc36f999b9ee Mon Sep 17 00:00:00 2001 From: pataar Date: Mon, 14 Nov 2022 13:21:13 +0100 Subject: [PATCH 9/9] remove console log --- lib/modules/manager/npm/extract/index.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts index 471808cbb2dc78..7f90f02c3d3d8b 100644 --- a/lib/modules/manager/npm/extract/index.spec.ts +++ b/lib/modules/manager/npm/extract/index.spec.ts @@ -501,7 +501,6 @@ describe('modules/manager/npm/extract/index', () => { defaultConfig ); - console.log(res); expect(res).toMatchObject({ deps: [ {},