From e2c4fdad51e0c23a1f4f159aec4e19f6a445372e Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sun, 24 May 2020 01:30:31 +0300 Subject: [PATCH] fix: install on partially up-to-date lockfile --- .changeset/beige-birds-attack.md | 5 +++++ .../src/resolveDependencies.ts | 14 ++++++++++---- packages/supi/test/install/peerDependencies.ts | 16 ++++++++++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 .changeset/beige-birds-attack.md diff --git a/.changeset/beige-birds-attack.md b/.changeset/beige-birds-attack.md new file mode 100644 index 0000000000..33a6e00dc6 --- /dev/null +++ b/.changeset/beige-birds-attack.md @@ -0,0 +1,5 @@ +--- +"@pnpm/resolve-dependencies": patch +--- + +Don't remove resolved peer dependencies from dependencies when lockfile is partially up-to-date. diff --git a/packages/resolve-dependencies/src/resolveDependencies.ts b/packages/resolve-dependencies/src/resolveDependencies.ts index 4da97d1be2..70d3beb91a 100644 --- a/packages/resolve-dependencies/src/resolveDependencies.ts +++ b/packages/resolve-dependencies/src/resolveDependencies.ts @@ -452,16 +452,22 @@ function getInfoFromLockfile ( return null } - const dependencyLockfile = lockfile.packages?.[depPath] + let dependencyLockfile = lockfile.packages?.[depPath] if (dependencyLockfile) { if (dependencyLockfile.peerDependencies && dependencyLockfile.dependencies) { // This is done to guarantee that the dependency will be relinked with the // up-to-date peer dependencies // Covered by test: "peer dependency is grouped with dependency when peer is resolved not from a top dependency" - R.keys(dependencyLockfile.peerDependencies).forEach((peer) => { - delete dependencyLockfile.dependencies![peer] - }) + const dependencies: Record = {} + for (const [depName, ref] of Object.entries(dependencyLockfile.dependencies ?? {})) { + if (dependencyLockfile.peerDependencies[depName]) continue + dependencies[depName] = ref + } + dependencyLockfile = { + ...dependencyLockfile, + dependencies, + } } return { diff --git a/packages/supi/test/install/peerDependencies.ts b/packages/supi/test/install/peerDependencies.ts index 0f0b4f9004..299ab129e4 100644 --- a/packages/supi/test/install/peerDependencies.ts +++ b/packages/supi/test/install/peerDependencies.ts @@ -81,17 +81,29 @@ test('nothing is needlessly removed from node_modules', async (t: tape.Test) => }) test('peer dependency is grouped with dependent when the peer is a top dependency', async (t: tape.Test) => { - prepareEmpty(t) + const project = prepareEmpty(t) const reporter = sinon.spy() - await addDependenciesToPackage({}, ['ajv@4.10.4', 'ajv-keywords@1.5.0'], await testDefaults({ reporter })) + const manifest = await addDependenciesToPackage({}, ['ajv@4.10.4', 'ajv-keywords@1.5.0'], await testDefaults({ reporter })) t.notOk(reporter.calledWithMatch({ message: `localhost+${REGISTRY_MOCK_PORT}/ajv-keywords/1.5.0 requires a peer of ajv@>=4.10.0 but none was installed.`, }), 'no warning is logged about unresolved peer dep') t.ok(await exists(path.resolve(`node_modules/.pnpm/ajv-keywords@1.5.0_ajv@4.10.4/node_modules/ajv-keywords`)), 'dependent is grouped with top peer dep') + + await mutateModules([ + { + buildIndex: 0, + manifest, + mutation: 'install', + rootDir: process.cwd(), + }, + ], await testDefaults({ preferFrozenLockfile: false })) + + const lockfile = await project.readLockfile() + t.ok(lockfile.packages['/ajv-keywords/1.5.0_ajv@4.10.4'].dependencies['ajv'], 'peer dep is still linked after repeat install') }) test('the right peer dependency is used in every workspace package', async (t: tape.Test) => {