fix: auto install of peer dependencies (#4776)

close #4684
This commit is contained in:
Zoltan Kochan
2022-05-22 03:19:40 +03:00
committed by GitHub
parent 35a730a62e
commit 190f0b331f
33 changed files with 221 additions and 110 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/core": minor
"@pnpm/resolve-dependencies": minor
---
New option added for automatically installing missing peer dependencies: `autoInstallPeers`.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/prune-lockfile": patch
---
Don't prune peer deps.

View File

@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-installation": patch
"pnpm": patch
---
When `auto-install-peers` is set to `true`, automatically install missing peer dependencies without writing them to `package.json` as dependencies. This makes pnpm handle peer dependencies the same way as npm v7 [#4776](https://github.com/pnpm/pnpm/pull/4776).

View File

@@ -0,0 +1,5 @@
---
"@pnpm/default-reporter": patch
---
Add hints to the peer dependencies error.

View File

@@ -38,7 +38,7 @@
"@commitlint/prompt-cli": "^16.0.0",
"@pnpm/eslint-config": "workspace:*",
"@pnpm/meta-updater": "0.0.6",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@pnpm/tsconfig": "workspace:*",
"@types/jest": "^27.4.0",
"@types/node": "^14.17.32",
@@ -120,7 +120,9 @@
"@typescript-eslint/eslint-plugin": "^5.6.0",
"@yarnpkg/core": "*"
},
"ignoreMissing": ["@yarnpkg/plugin-patch"]
"ignoreMissing": [
"@yarnpkg/plugin-patch"
]
}
}
}

View File

@@ -74,7 +74,7 @@
"@pnpm/logger": "^4.0.0",
"@pnpm/package-store": "workspace:13.0.5",
"@pnpm/prepare": "workspace:*",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@pnpm/store-path": "workspace:6.0.0",
"@pnpm/test-fixtures": "workspace:*",
"@types/fs-extra": "^9.0.5",

View File

@@ -16,6 +16,7 @@ import pnpmPkgJson from '../pnpmPkgJson'
import { ReporterFunction } from '../types'
export interface StrictInstallOptions {
autoInstallPeers: boolean
forceSharedLockfile: boolean
frozenLockfile: boolean
frozenLockfileIfExists: boolean
@@ -107,6 +108,7 @@ const defaults = async (opts: InstallOptions) => {
version: pnpmPkgJson.version,
}
return {
autoInstallPeers: false,
childConcurrency: 5,
depth: 0,
enablePnp: false,

View File

@@ -740,6 +740,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
projects,
{
allowBuild: createAllowBuildFunction(opts),
autoInstallPeers: opts.autoInstallPeers,
currentLockfile: ctx.currentLockfile,
defaultUpdateDepth: (opts.update || (opts.updateMatching != null)) ? opts.depth : -1,
dryRun: opts.lockfileOnly,

View File

@@ -0,0 +1,37 @@
import { addDependenciesToPackage } from '@pnpm/core'
import { prepareEmpty } from '@pnpm/prepare'
import { addDistTag } from '@pnpm/registry-mock'
import { testDefaults } from '../utils'
test('auto install non-optional peer dependencies', async () => {
await addDistTag({ package: 'peer-a', version: '1.0.0', distTag: 'latest' })
const project = prepareEmpty()
await addDependenciesToPackage({}, ['abc-optional-peers@1.0.0'], await testDefaults({ autoInstallPeers: true }))
const lockfile = await project.readLockfile()
expect(Object.keys(lockfile.packages)).toStrictEqual([
'/abc-optional-peers/1.0.0_peer-a@1.0.0',
'/peer-a/1.0.0',
])
})
test('auto install the common peer dependency', async () => {
await addDistTag({ package: 'peer-c', version: '1.0.1', distTag: 'latest' })
const project = prepareEmpty()
await addDependenciesToPackage({}, ['wants-peer-c-1', 'wants-peer-c-1.0.0'], await testDefaults({ autoInstallPeers: true }))
const lockfile = await project.readLockfile()
expect(Object.keys(lockfile.packages)).toStrictEqual([
'/peer-c/1.0.0',
'/wants-peer-c-1.0.0/1.0.0_peer-c@1.0.0',
'/wants-peer-c-1/1.0.0_peer-c@1.0.0',
])
})
test('do not auto install when there is no common peer dependency range intersection', async () => {
const project = prepareEmpty()
await addDependenciesToPackage({}, ['wants-peer-c-1', 'wants-peer-c-2'], await testDefaults({ autoInstallPeers: true }))
const lockfile = await project.readLockfile()
expect(Object.keys(lockfile.packages)).toStrictEqual([
'/wants-peer-c-1/1.0.0',
'/wants-peer-c-2/1.0.0',
])
})

View File

@@ -1116,7 +1116,7 @@ test('peer dependency that is resolved by a dev dependency', async () => {
], await testDefaults({ fastUnpack: false, lockfileOnly: true, strictPeerDependencies: false }))
const lockfile = await project.readLockfile()
expect(lockfile.packages['/@types/mongoose/5.7.32'].dev).toBeTruthy()
expect(lockfile.packages['/@types/mongoose/5.7.32'].dev).toBeUndefined()
await mutateModules([
{

View File

@@ -397,8 +397,21 @@ function reportPeerDependencyIssuesError (
err: Error,
msg: { issuesByProjects: PeerDependencyIssuesByProjects }
) {
const hasMissingPeers = getHasMissingPeers(msg.issuesByProjects)
const hints: string[] = []
if (hasMissingPeers) {
hints.push('If you want peer dependencies to be automatically installed, set the "auto-install-peers" setting to "true".')
}
hints.push('If you don\'t want pnpm to fail on peer dependency issues, set the "strict-peer-dependencies" setting to "false".')
return {
title: err.message,
body: renderPeerIssues(msg.issuesByProjects),
body: `${renderPeerIssues(msg.issuesByProjects)}
${hints.map((hint) => `hint: ${hint}`).join('\n')}
`,
}
}
function getHasMissingPeers (issuesByProjects: PeerDependencyIssuesByProjects) {
return Object.values(issuesByProjects)
.some((issues) => Object.values(issues.missing).flat().some(({ optional }) => !optional))
}

View File

@@ -22,7 +22,7 @@
"@pnpm/package-store": "workspace:13.0.5",
"@pnpm/prepare": "workspace:*",
"@pnpm/read-projects-context": "workspace:6.0.3",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@pnpm/store-path": "workspace:6.0.0",
"@pnpm/test-fixtures": "workspace:*",
"@types/fs-extra": "^9.0.5",

View File

@@ -65,7 +65,7 @@
"@pnpm/create-cafs-store": "workspace:1.0.1",
"@pnpm/logger": "^4.0.0",
"@pnpm/package-requester": "workspace:18.0.5",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@pnpm/test-fixtures": "workspace:*",
"@types/normalize-path": "^3.0.0",
"@types/ramda": "0.27.39",

View File

@@ -39,7 +39,7 @@
"@pnpm/modules-yaml": "workspace:10.0.1",
"@pnpm/plugin-commands-installation": "workspace:10.0.6",
"@pnpm/prepare": "workspace:*",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@pnpm/test-fixtures": "workspace:*",
"@types/is-ci": "^3.0.0",
"@types/proxyquire": "^1.3.28",

View File

@@ -20,7 +20,6 @@ import {
import logger from '@pnpm/logger'
import { sequenceGraph } from '@pnpm/sort-packages'
import isSubdir from 'is-subdir'
import isEmpty from 'ramda/src/isEmpty'
import getOptionsFromRootManifest from './getOptionsFromRootManifest'
import getPinnedVersion from './getPinnedVersion'
import getSaveType from './getSaveType'
@@ -233,29 +232,8 @@ when running add/update with the --workspace option')
rootDir: opts.dir,
targetDependenciesField: getSaveType(opts),
}
let [updatedImporter] = await mutateModules([mutatedProject], {
...installOpts,
strictPeerDependencies: opts.autoInstallPeers ? false : installOpts.strictPeerDependencies,
})
const [updatedImporter] = await mutateModules([mutatedProject], installOpts)
if (opts.save !== false) {
if (opts.autoInstallPeers && !isEmpty(updatedImporter.peerDependencyIssues?.intersections ?? {})) {
logger.info({
message: 'Installing missing peer dependencies',
prefix: opts.dir,
})
const dependencySelectors = Object.entries(updatedImporter.peerDependencyIssues!.intersections)
.map(([name, version]: [string, string]) => `${name}@${version}`)
const result = await mutateModules([
{
...mutatedProject,
dependencySelectors,
manifest: updatedImporter.manifest,
peer: false,
targetDependenciesField: 'devDependencies',
},
], installOpts)
updatedImporter = result[0]
}
await writeProjectManifest(updatedImporter.manifest)
}
return

View File

@@ -291,7 +291,7 @@ test('pnpm add - should add prefix when set in .npmrc when a range is not specif
})
test('pnpm add automatically installs missing peer dependencies', async () => {
prepare()
const project = prepare()
await add.handler({
...DEFAULT_OPTIONS,
autoInstallPeers: true,
@@ -299,10 +299,6 @@ test('pnpm add automatically installs missing peer dependencies', async () => {
linkWorkspacePackages: false,
}, ['abc@1.0.0'])
const manifest = (await import(path.resolve('package.json')))
expect(manifest.dependencies['abc']).toBe('1.0.0')
expect(manifest.devDependencies['peer-a']).toBe('^1.0.0')
expect(manifest.devDependencies['peer-b']).toBe('^1.0.0')
expect(manifest.devDependencies['peer-c']).toBe('^1.0.0')
const lockfile = await project.readLockfile()
expect(Object.keys(lockfile.packages).length).toBe(5)
})

View File

@@ -38,7 +38,7 @@
"@pnpm/plugin-commands-installation": "workspace:10.0.6",
"@pnpm/plugin-commands-listing": "workspace:5.0.6",
"@pnpm/prepare": "workspace:*",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@types/ramda": "0.27.39",
"execa": "npm:safe-execa@^0.1.1",
"strip-ansi": "^6.0.0",

View File

@@ -38,7 +38,7 @@
"@pnpm/plugin-commands-installation": "workspace:10.0.6",
"@pnpm/plugin-commands-outdated": "workspace:6.0.6",
"@pnpm/prepare": "workspace:*",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@types/lru-cache": "^5.1.0",
"@types/ramda": "0.27.39",
"@types/wrap-ansi": "^3.0.0",

View File

@@ -39,7 +39,7 @@
"@pnpm/logger": "^4.0.0",
"@pnpm/plugin-commands-publishing": "workspace:5.0.7",
"@pnpm/prepare": "workspace:*",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@types/cross-spawn": "^6.0.2",
"@types/is-ci": "^3.0.0",
"@types/is-windows": "^1.0.0",

View File

@@ -37,7 +37,7 @@
"@pnpm/logger": "^4.0.0",
"@pnpm/plugin-commands-rebuild": "workspace:6.1.5",
"@pnpm/prepare": "workspace:*",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@pnpm/test-fixtures": "workspace:*",
"@types/ramda": "0.27.39",
"@types/semver": "^7.3.4",

View File

@@ -38,7 +38,7 @@
"@pnpm/logger": "^4.0.0",
"@pnpm/plugin-commands-script-runners": "workspace:5.0.7",
"@pnpm/prepare": "workspace:*",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@types/is-windows": "^1.0.0",
"@types/ramda": "0.27.39",
"is-windows": "^1.0.2",

View File

@@ -38,7 +38,7 @@
"@pnpm/logger": "^4.0.0",
"@pnpm/plugin-commands-store": "workspace:5.1.5",
"@pnpm/prepare": "workspace:*",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@types/archy": "0.0.31",
"@types/ramda": "0.27.39",
"@types/ssri": "^7.1.0",

View File

@@ -55,7 +55,7 @@
"@pnpm/prepare": "workspace:*",
"@pnpm/read-package-json": "workspace:6.0.2",
"@pnpm/read-project-manifest": "workspace:3.0.2",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@pnpm/run-npm": "workspace:4.0.1",
"@pnpm/tabtab": "^0.1.2",
"@pnpm/types": "workspace:8.0.1",

View File

@@ -9,7 +9,6 @@ import { PackageManifest } from '@pnpm/types'
import { refToRelative } from 'dependency-path'
import difference from 'ramda/src/difference'
import isEmpty from 'ramda/src/isEmpty'
import omit from 'ramda/src/omit'
import unnest from 'ramda/src/unnest'
export * from '@pnpm/lockfile-types'
@@ -197,7 +196,7 @@ function copyDependencySubGraph (
} else if (depLockfile.dev === undefined && !ctx.notProdOnly.has(depPath)) {
depLockfile.dev = false
}
const newDependencies = resolvedDepsToDepPaths(omit(Object.keys(depLockfile.peerDependencies ?? {}) ?? [], depLockfile.dependencies ?? {}))
const newDependencies = resolvedDepsToDepPaths(depLockfile.dependencies ?? {})
copyDependencySubGraph(ctx, newDependencies, opts)
const newOptionalDependencies = resolvedDepsToDepPaths(depLockfile.optionalDependencies ?? {})
copyDependencySubGraph(ctx, newOptionalDependencies, { dev: opts.dev, optional: true })

View File

@@ -8,7 +8,7 @@ export interface WantedDependency {
injected?: boolean
}
export default function getNonDevWantedDependencies (pkg: DependencyManifest) {
export default function getNonDevWantedDependencies (pkg: Pick<DependencyManifest, 'bundleDependencies' | 'optionalDependencies' | 'dependencies' | 'dependenciesMeta'>) {
const bd = pkg.bundleDependencies ?? pkg.bundleDependencies
const bundledDeps = new Set(Array.isArray(bd) ? bd : [])
const filterDeps = getNotBundledDeps.bind(null, bundledDeps)

View File

@@ -136,7 +136,7 @@ export default async function (
difference(
Object.keys(getAllDependenciesFromManifest(project.manifest)),
resolvedImporter.directDependencies
.filter((dep, index) => project.wantedDependencies[index].isNew === true)
.filter((dep, index) => project.wantedDependencies[index]?.isNew === true)
.map(({ alias }) => alias) || []
),
project.modulesDir

View File

@@ -20,7 +20,7 @@ export function mergePeers (missingPeers: MissingPeerIssuesByPeerName) {
return { conflicts, intersections }
}
function safeIntersect (ranges: string[]): null | string {
export function safeIntersect (ranges: string[]): null | string {
try {
return intersect(...ranges)
} catch {

View File

@@ -42,6 +42,7 @@ import isEmpty from 'ramda/src/isEmpty'
import semver from 'semver'
import encodePkgId from './encodePkgId'
import getNonDevWantedDependencies, { WantedDependency } from './getNonDevWantedDependencies'
import { safeIntersect } from './mergePeers'
import {
createNodeId,
nodeIdContainsSequence,
@@ -116,6 +117,7 @@ export interface ChildrenByParentDepPath {
}
export interface ResolutionContext {
autoInstallPeers: boolean
allowBuild?: (pkgName: string) => boolean
updatedSet: Set<string>
defaultTag: string
@@ -160,6 +162,7 @@ export type PkgAddress = {
version?: string
updated: boolean
rootDir: string
missingPeers: Record<string, string>
} & ({
isLinkedDependency: true
version: string
@@ -203,9 +206,12 @@ export interface ResolvedPackage {
type ParentPkg = Pick<PkgAddress, 'nodeId' | 'installable' | 'depPath' | 'rootDir'>
type ParentPkgAliases = Record<string, true>
interface ResolvedDependenciesOptions {
currentDepth: number
parentPkg: ParentPkg
parentPkgAliases: ParentPkgAliases
// If the package has been updated, the dependencies
// which were used by the previous version are passed
// via this option
@@ -216,35 +222,47 @@ interface ResolvedDependenciesOptions {
workspacePackages?: WorkspacePackages
}
type PostponedResolutionFunction = (preferredVersions: PreferredVersions, parentPkgAliases: ParentPkgAliases) => Promise<void>
export default async function resolveDependencies (
ctx: ResolutionContext,
preferredVersions: PreferredVersions,
wantedDependencies: Array<WantedDependency & { updateDepth?: number }>,
options: ResolvedDependenciesOptions
): Promise<Array<PkgAddress | LinkedDependency>> {
const extendedWantedDeps = getDepsToResolve(wantedDependencies, ctx.wantedLockfile, {
preferredDependencies: options.preferredDependencies,
prefix: ctx.prefix,
proceed: options.proceed || ctx.forceFullResolution,
registries: ctx.registries,
resolvedDependencies: options.resolvedDependencies,
})
const postponedResolutionsQueue = [] as Array<(preferredVersions: PreferredVersions) => Promise<void>>
const pkgAddresses = (
await Promise.all(
extendedWantedDeps.map(async (extendedWantedDep) => resolveDependenciesOfDependency(
postponedResolutionsQueue,
ctx,
preferredVersions,
options,
extendedWantedDep
))
)
)
.filter(Boolean) as PkgAddress[]
let extendedWantedDeps: ExtendedWantedDependency[] = []
const postponedResolutionsQueue: PostponedResolutionFunction[] = []
const pkgAddresses: PkgAddress[] = []
while (true) {
extendedWantedDeps = getDepsToResolve(wantedDependencies, ctx.wantedLockfile, {
preferredDependencies: options.preferredDependencies,
prefix: ctx.prefix,
proceed: options.proceed || ctx.forceFullResolution,
registries: ctx.registries,
resolvedDependencies: options.resolvedDependencies,
})
const newPkgAddresses = (
await Promise.all(
extendedWantedDeps.map(async (extendedWantedDep) => resolveDependenciesOfDependency(
postponedResolutionsQueue,
ctx,
preferredVersions,
options,
extendedWantedDep
))
)
).filter(Boolean) as PkgAddress[]
pkgAddresses.push(...newPkgAddresses)
if (!ctx.autoInstallPeers) break
const allMissingPeers = mergePkgsDeps(newPkgAddresses.map(({ missingPeers }) => missingPeers))
if (!Object.keys(allMissingPeers).length) break
wantedDependencies = getNonDevWantedDependencies({ dependencies: allMissingPeers })
}
const newPreferredVersions = { ...preferredVersions }
const newParentPkgAliases = { ...options.parentPkgAliases }
for (const pkgAddress of pkgAddresses) {
newParentPkgAliases[pkgAddress.alias] = true
if (pkgAddress.updated) {
ctx.updatedSet.add(pkgAddress.alias)
}
@@ -255,11 +273,31 @@ export default async function resolveDependencies (
}
newPreferredVersions[resolvedPackage.name][resolvedPackage.version] = 'version'
}
await Promise.all(postponedResolutionsQueue.map(async (postponedResolution) => postponedResolution(newPreferredVersions)))
await Promise.all(postponedResolutionsQueue.map(async (postponedResolution) => postponedResolution(newPreferredVersions, newParentPkgAliases)))
return pkgAddresses
}
function mergePkgsDeps (pkgsDeps: Array<Record<string, string>>): Record<string, string> {
const groupedRanges: Record<string, string[]> = {}
for (const deps of pkgsDeps) {
for (const [name, range] of Object.entries(deps)) {
if (!groupedRanges[name]) {
groupedRanges[name] = []
}
groupedRanges[name].push(range)
}
}
const mergedPkgDeps = {} as Record<string, string>
for (const [name, ranges] of Object.entries(groupedRanges)) {
const intersection = safeIntersect(ranges)
if (intersection) {
mergedPkgDeps[name] = intersection
}
}
return mergedPkgDeps
}
interface ExtendedWantedDependency {
infoFromLockfile?: InfoFromLockfile
proceed: boolean
@@ -267,7 +305,7 @@ interface ExtendedWantedDependency {
}
async function resolveDependenciesOfDependency (
postponedResolutionsQueue: Array<(preferredVersions: PreferredVersions) => Promise<void>>,
postponedResolutionsQueue: PostponedResolutionFunction[],
ctx: ResolutionContext,
preferredVersions: PreferredVersions,
options: ResolvedDependenciesOptions,
@@ -296,6 +334,7 @@ async function resolveDependenciesOfDependency (
const resolveDependencyOpts: ResolveDependencyOptions = {
currentDepth: options.currentDepth,
parentPkg: options.parentPkg,
parentPkgAliases: options.parentPkgAliases,
preferredVersions,
workspacePackages: options.workspacePackages,
currentPkg: extendedWantedDep.infoFromLockfile ?? undefined,
@@ -320,10 +359,11 @@ async function resolveDependenciesOfDependency (
}
if (!resolveDependencyResult.isNew) return resolveDependencyResult
postponedResolutionsQueue.push(async (preferredVersions) =>
postponedResolutionsQueue.push(async (preferredVersions, parentPkgAliases) =>
resolveChildren(
ctx,
resolveDependencyResult,
parentPkgAliases,
extendedWantedDep.infoFromLockfile?.dependencyLockfile,
options.workspacePackages,
options.currentDepth,
@@ -338,6 +378,7 @@ async function resolveDependenciesOfDependency (
async function resolveChildren (
ctx: ResolutionContext,
parentPkg: PkgAddress,
parentPkgAliases: ParentPkgAliases,
dependencyLockfile: PackageSnapshot | undefined,
workspacePackages: WorkspacePackages | undefined,
parentDepth: number,
@@ -365,6 +406,7 @@ async function resolveChildren (
{
currentDepth: parentDepth + 1,
parentPkg,
parentPkgAliases,
preferredDependencies: currentResolvedDependencies,
// If the package is not linked, we should also gather information about its dependencies.
// After linking the package we'll need to symlink its dependencies.
@@ -562,6 +604,7 @@ interface ResolveDependencyOptions {
dependencyLockfile?: PackageSnapshot
}
parentPkg: ParentPkg
parentPkgAliases: ParentPkgAliases
preferredVersions: PreferredVersions
proceed: boolean
update: boolean
@@ -837,6 +880,7 @@ async function resolveDependency (
normalizedPref: options.currentDepth === 0 ? pkgResponse.body.normalizedPref : undefined,
pkgId: pkgResponse.body.id,
rootDir,
missingPeers: getMissingPeers(pkg, options.parentPkgAliases),
// Next fields are actually only needed when isNew = true
installable,
@@ -846,6 +890,16 @@ async function resolveDependency (
}
}
function getMissingPeers (pkg: PackageManifest, parentPkgAliases: ParentPkgAliases): Record<string, string> {
const missingPeers = {} as Record<string, string>
for (const [peerName, peerVersion] of Object.entries(pkg.peerDependencies ?? {})) {
if (!parentPkgAliases[peerName] && !pkg.peerDependenciesMeta?.[peerName]?.optional) {
missingPeers[peerName] = peerVersion
}
}
return missingPeers
}
function pkgIsLeaf (pkg: PackageManifest) {
return isEmpty(pkg.dependencies ?? {}) &&
isEmpty(pkg.optionalDependencies ?? {}) &&

View File

@@ -52,6 +52,7 @@ export interface ImporterToResolveGeneric<T> extends Importer<T> {
}
export interface ResolveDependenciesOptions {
autoInstallPeers?: boolean
allowBuild?: (pkgName: string) => boolean
currentLockfile: Lockfile
dryRun: boolean
@@ -84,6 +85,7 @@ export default async function<T> (
const wantedToBeSkippedPackageIds = new Set<string>()
const ctx = {
autoInstallPeers: opts.autoInstallPeers === true,
allowBuild: opts.allowBuild,
childrenByParentDepPath: {} as ChildrenByParentDepPath,
currentLockfile: opts.currentLockfile,
@@ -135,6 +137,7 @@ export default async function<T> (
depPath: importer.id,
rootDir: importer.rootDir,
},
parentPkgAliases: {},
proceed,
resolvedDependencies: {
...projectSnapshot.dependencies,

View File

@@ -22,7 +22,7 @@ export default async function updateProjectManifest (
throw new Error('Cannot save because no package.json found')
}
const specsToUpsert = opts.directDependencies
.filter((rdd, index) => importer.wantedDependencies[index]!.updateSpec)
.filter((rdd, index) => importer.wantedDependencies[index]?.updateSpec)
.map((rdd, index) => {
const wantedDep = importer.wantedDependencies[index]!
return resolvedDirectDepToSpecObject({ ...rdd, isNew: wantedDep.isNew, specRaw: wantedDep.raw }, importer, {

72
pnpm-lock.yaml generated
View File

@@ -41,7 +41,7 @@ importers:
'@commitlint/prompt-cli': ^16.0.0
'@pnpm/eslint-config': workspace:*
'@pnpm/meta-updater': 0.0.6
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/tsconfig': workspace:*
'@types/jest': ^27.4.0
'@types/node': ^14.17.32
@@ -72,7 +72,7 @@ importers:
'@commitlint/prompt-cli': 16.2.4
'@pnpm/eslint-config': link:utils/eslint-config
'@pnpm/meta-updater': 0.0.6
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/tsconfig': link:utils/tsconfig
'@types/jest': 27.5.0
'@types/node': 14.18.16
@@ -422,7 +422,7 @@ importers:
'@pnpm/read-modules-dir': workspace:4.0.0
'@pnpm/read-package-json': workspace:6.0.2
'@pnpm/read-project-manifest': workspace:3.0.2
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/remove-bins': workspace:3.0.2
'@pnpm/resolve-dependencies': workspace:27.0.4
'@pnpm/resolver-base': workspace:9.0.1
@@ -527,7 +527,7 @@ importers:
'@pnpm/logger': 4.0.0
'@pnpm/package-store': link:../package-store
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/store-path': link:../store-path
'@pnpm/test-fixtures': link:../../privatePackages/test-fixtures
'@types/fs-extra': 9.0.13
@@ -1113,7 +1113,7 @@ importers:
'@pnpm/read-project-manifest': workspace:3.0.2
'@pnpm/read-projects-context': workspace:6.0.3
'@pnpm/real-hoist': workspace:0.2.3
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/store-controller-types': workspace:13.0.1
'@pnpm/store-path': workspace:6.0.0
'@pnpm/symlink-dependency': workspace:5.0.1
@@ -1174,7 +1174,7 @@ importers:
'@pnpm/package-store': link:../package-store
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/read-projects-context': link:../read-projects-context
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/store-path': link:../store-path
'@pnpm/test-fixtures': link:../../privatePackages/test-fixtures
'@types/fs-extra': 9.0.13
@@ -1867,7 +1867,7 @@ importers:
'@pnpm/package-is-installable': workspace:6.0.3
'@pnpm/package-requester': workspace:18.0.5
'@pnpm/read-package-json': workspace:6.0.2
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/resolver-base': workspace:9.0.1
'@pnpm/store-controller-types': workspace:13.0.1
'@pnpm/test-fixtures': workspace:*
@@ -1918,7 +1918,7 @@ importers:
'@pnpm/create-cafs-store': link:../create-cafs-store
'@pnpm/logger': 4.0.0
'@pnpm/package-requester': 'link:'
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/test-fixtures': link:../../privatePackages/test-fixtures
'@types/normalize-path': 3.0.0
'@types/ramda': 0.27.39
@@ -2190,7 +2190,7 @@ importers:
'@pnpm/pnpmfile': workspace:2.0.2
'@pnpm/prepare': workspace:*
'@pnpm/read-project-manifest': workspace:3.0.2
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/resolver-base': workspace:9.0.1
'@pnpm/semver-diff': ^1.0.2
'@pnpm/sort-packages': workspace:3.0.2
@@ -2287,7 +2287,7 @@ importers:
'@pnpm/modules-yaml': link:../modules-yaml
'@pnpm/plugin-commands-installation': 'link:'
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/test-fixtures': link:../../privatePackages/test-fixtures
'@types/is-ci': 3.0.0
'@types/proxyquire': 1.3.28
@@ -2318,7 +2318,7 @@ importers:
'@pnpm/plugin-commands-installation': workspace:10.0.6
'@pnpm/plugin-commands-listing': workspace:5.0.6
'@pnpm/prepare': workspace:*
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/types': workspace:8.0.1
'@types/ramda': 0.27.39
execa: npm:safe-execa@^0.1.1
@@ -2342,7 +2342,7 @@ importers:
'@pnpm/plugin-commands-installation': link:../plugin-commands-installation
'@pnpm/plugin-commands-listing': 'link:'
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@types/ramda': 0.27.39
execa: /safe-execa/0.1.1
strip-ansi: 6.0.1
@@ -2366,7 +2366,7 @@ importers:
'@pnpm/plugin-commands-installation': workspace:10.0.6
'@pnpm/plugin-commands-outdated': workspace:6.0.6
'@pnpm/prepare': workspace:*
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/semver-diff': ^1.0.2
'@pnpm/store-path': workspace:6.0.0
'@pnpm/types': workspace:8.0.1
@@ -2409,7 +2409,7 @@ importers:
'@pnpm/plugin-commands-installation': link:../plugin-commands-installation
'@pnpm/plugin-commands-outdated': 'link:'
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@types/lru-cache': 5.1.1
'@types/ramda': 0.27.39
'@types/wrap-ansi': 3.0.0
@@ -2429,7 +2429,7 @@ importers:
'@pnpm/pick-registry-for-package': workspace:3.0.1
'@pnpm/plugin-commands-publishing': workspace:5.0.7
'@pnpm/prepare': workspace:*
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/resolver-base': workspace:9.0.1
'@pnpm/run-npm': workspace:4.0.1
'@pnpm/sort-packages': workspace:3.0.2
@@ -2492,7 +2492,7 @@ importers:
'@pnpm/logger': 4.0.0
'@pnpm/plugin-commands-publishing': 'link:'
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@types/cross-spawn': 6.0.2
'@types/is-ci': 3.0.0
'@types/is-windows': 1.0.0
@@ -2530,7 +2530,7 @@ importers:
'@pnpm/normalize-registries': workspace:3.0.1
'@pnpm/plugin-commands-rebuild': workspace:6.1.5
'@pnpm/prepare': workspace:*
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/sort-packages': workspace:3.0.2
'@pnpm/store-connection-manager': workspace:4.1.5
'@pnpm/store-controller-types': workspace:13.0.1
@@ -2589,7 +2589,7 @@ importers:
'@pnpm/logger': 4.0.0
'@pnpm/plugin-commands-rebuild': 'link:'
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/test-fixtures': link:../../privatePackages/test-fixtures
'@types/ramda': 0.27.39
'@types/semver': 7.3.9
@@ -2615,7 +2615,7 @@ importers:
'@pnpm/prepare': workspace:*
'@pnpm/read-package-json': workspace:6.0.2
'@pnpm/read-project-manifest': workspace:3.0.2
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/sort-packages': workspace:3.0.2
'@pnpm/store-path': workspace:6.0.0
'@pnpm/types': workspace:8.0.1
@@ -2658,7 +2658,7 @@ importers:
'@pnpm/logger': 4.0.0
'@pnpm/plugin-commands-script-runners': 'link:'
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@types/is-windows': 1.0.0
'@types/ramda': 0.27.39
is-windows: 1.0.2
@@ -2748,7 +2748,7 @@ importers:
'@pnpm/pick-registry-for-package': workspace:3.0.1
'@pnpm/plugin-commands-store': workspace:5.1.5
'@pnpm/prepare': workspace:*
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/store-connection-manager': workspace:4.1.5
'@pnpm/store-controller-types': workspace:13.0.1
'@pnpm/store-path': workspace:6.0.0
@@ -2795,7 +2795,7 @@ importers:
'@pnpm/logger': 4.0.0
'@pnpm/plugin-commands-store': 'link:'
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@types/archy': 0.0.31
'@types/ramda': 0.27.39
'@types/ssri': 7.1.1
@@ -2843,7 +2843,7 @@ importers:
'@pnpm/prepare': workspace:*
'@pnpm/read-package-json': workspace:6.0.2
'@pnpm/read-project-manifest': workspace:3.0.2
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/run-npm': workspace:4.0.1
'@pnpm/tabtab': ^0.1.2
'@pnpm/types': workspace:8.0.1
@@ -2931,7 +2931,7 @@ importers:
'@pnpm/prepare': link:../../privatePackages/prepare
'@pnpm/read-package-json': link:../read-package-json
'@pnpm/read-project-manifest': link:../read-project-manifest
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/run-npm': link:../run-npm
'@pnpm/tabtab': 0.1.2
'@pnpm/types': link:../types
@@ -3529,7 +3529,7 @@ importers:
'@pnpm/constants': workspace:6.1.0
'@pnpm/lockfile-types': workspace:4.0.1
'@pnpm/modules-yaml': workspace:10.0.1
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/types': workspace:8.0.1
'@types/is-windows': ^1.0.0
'@types/isexe': 2.0.0
@@ -3544,7 +3544,7 @@ importers:
'@pnpm/constants': link:../../packages/constants
'@pnpm/lockfile-types': link:../../packages/lockfile-types
'@pnpm/modules-yaml': link:../../packages/modules-yaml
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
'@pnpm/types': link:../../packages/types
is-windows: 1.0.2
isexe: 2.0.0
@@ -3561,11 +3561,11 @@ importers:
specifiers:
'@pnpm/assert-store': workspace:*
'@pnpm/cafs': workspace:4.0.2
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
path-exists: ^4.0.0
dependencies:
'@pnpm/cafs': link:../../packages/cafs
'@pnpm/registry-mock': 2.16.0
'@pnpm/registry-mock': 2.17.0
path-exists: 4.0.0
devDependencies:
'@pnpm/assert-store': 'link:'
@@ -5134,8 +5134,8 @@ packages:
strip-bom: 4.0.0
dev: true
/@pnpm/registry-mock/2.16.0:
resolution: {integrity: sha512-Ro5tsRBR+qTnYne6B9aQJIzsyIJWhSBfARZMpEBmVVUysivYPWjoIRBNZ3EVbtt67oF6tMXTBGViPvYkwQYeyQ==}
/@pnpm/registry-mock/2.17.0:
resolution: {integrity: sha512-vZuWSJaixugxz0Y39VIEKeyYm69TG3/8qXkgMXjLjRWtE/4EezKKGfiAEhuJasSdvVoYUQWY2Ng0nEkWihTN9w==}
engines: {node: '>=10.13'}
hasBin: true
dependencies:
@@ -5312,7 +5312,7 @@ packages:
/@types/byline/4.2.33:
resolution: {integrity: sha512-LJYez7wrWcJQQDknqZtrZuExMGP0IXmPl1rOOGDqLbu+H7UNNRfKNuSxCBcQMLH1EfjeWidLedC/hCc5dDfBog==}
dependencies:
'@types/node': 17.0.31
'@types/node': 17.0.35
dev: true
/@types/cacheable-request/6.0.2:
@@ -5486,6 +5486,10 @@ packages:
/@types/node/17.0.31:
resolution: {integrity: sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q==}
/@types/node/17.0.35:
resolution: {integrity: sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==}
dev: true
/@types/normalize-package-data/2.4.1:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
dev: true
@@ -9438,7 +9442,7 @@ packages:
source-map: 0.6.1
wordwrap: 1.0.0
optionalDependencies:
uglify-js: 3.15.4
uglify-js: 3.15.5
/har-schema/2.0.0:
resolution: {integrity: sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=}
@@ -14584,8 +14588,8 @@ packages:
engines: {node: '>=4.2.0'}
hasBin: true
/uglify-js/3.15.4:
resolution: {integrity: sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==}
/uglify-js/3.15.5:
resolution: {integrity: sha512-hNM5q5GbBRB5xB+PMqVRcgYe4c8jbyZ1pzZhS6jbq54/4F2gFK869ZheiE5A8/t+W5jtTNpWef/5Q9zk639FNQ==}
engines: {node: '>=0.8.0'}
hasBin: true
requiresBuild: true

View File

@@ -45,7 +45,7 @@
"@pnpm/constants": "workspace:6.1.0",
"@pnpm/lockfile-types": "workspace:4.0.1",
"@pnpm/modules-yaml": "workspace:10.0.1",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"@pnpm/types": "workspace:8.0.1",
"is-windows": "^1.0.2",
"isexe": "2.0.0",

View File

@@ -42,7 +42,7 @@
},
"dependencies": {
"@pnpm/cafs": "workspace:4.0.2",
"@pnpm/registry-mock": "2.16.0",
"@pnpm/registry-mock": "2.17.0",
"path-exists": "^4.0.0"
},
"devDependencies": {