From 962214bb43757b0bb9c3fe74e23cfe198ae6486c Mon Sep 17 00:00:00 2001 From: isaacs Date: Tue, 9 Mar 2021 08:59:54 -0800 Subject: [PATCH] Respect link deps when calculating peerDep sets Previously, we were not including link targets in the virtual trees where peer dependency sets are calculated. Additionally, we were still using the path `/virtual-root` for the virtual node, even though this is no longer load-bearing. (And, as of the recent change to the Node printable output, no longer necessary or particularly helpful for debugging.) As a result, a link dependency from the root node like `file:../../foo` would get resolved against `/virtual-root`, resulting in `/foo`, which of course does not match any Node in the virtual tree. The outcome was an ERESOVLVE error where the `current` Node is shown as having no name or version (because it is an unsatisfied Link). The solution is two-part. First, the path of the virtual tree root now matches the path of the Node that it is sourced from. Second, any Link children of the source node have their targets mirrored in the virtual tree, resulting in them being matched appropriately. The result is that a Link dependency can now properly satisfy a peerDependency. Test shows an example of using a Link to a local Node as a workaround for a peerSet that otherwise would not be resolveable. This can of course be abused to get around valid peerDep contracts, but if they user takes it on themselves to use a local fork of a dependency, we should respect that in buildIdealTree as we do elsewhere. Fix: npm/cli#2199 --- lib/arborist/build-ideal-tree.js | 16 +- ...t-arborist-build-ideal-tree.js-TAP.test.js | 415 ++++++++++++++++++ test/arborist/build-ideal-tree.js | 37 ++ .../testing-peer-dep-conflict-chain-vv.json | 92 ++++ ...esting-peer-dep-conflict-chain-vv.min.json | 39 ++ .../vv/1/package.json | 7 + .../vv/2/package.json | 7 + 7 files changed, 612 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/registry-mocks/content/isaacs/testing-peer-dep-conflict-chain-vv.json create mode 100644 test/fixtures/registry-mocks/content/isaacs/testing-peer-dep-conflict-chain-vv.min.json create mode 100644 test/fixtures/testing-peer-dep-conflict-chain/vv/1/package.json create mode 100644 test/fixtures/testing-peer-dep-conflict-chain/vv/2/package.json diff --git a/lib/arborist/build-ideal-tree.js b/lib/arborist/build-ideal-tree.js index 412d6ce8b..f7e5b7e32 100644 --- a/lib/arborist/build-ideal-tree.js +++ b/lib/arborist/build-ideal-tree.js @@ -883,6 +883,8 @@ This is a one-time fix-up, please be patient... // create a virtual root node with the same deps as the node that // is requesting this one, so that we can get all the peer deps in // a context where they're likely to be resolvable. + // Note that the virtual root will also have virtual copies of the + // targets of any child Links, so that they resolve appropriately. const parent = parent_ || this[_virtualRoot](edge.from) const realParent = edge.peer ? edge.from.resolveParent : edge.from @@ -936,11 +938,23 @@ This is a one-time fix-up, please be patient... return this[_virtualRoots].get(node) const vr = new Node({ - path: '/virtual-root', + path: node.realpath, sourceReference: node, legacyPeerDeps: this.legacyPeerDeps, }) + // also need to set up any targets from any link deps, so that + // they are properly reflected in the virtual environment + for (const child of node.children.values()) { + if (child.isLink) { + new Node({ + path: child.realpath, + sourceReference: child.target, + root: vr, + }) + } + } + this[_virtualRoots].set(node, vr) return vr } diff --git a/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js b/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js index 4a4c51ceb..53c287896 100644 --- a/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js +++ b/tap-snapshots/test-arborist-build-ideal-tree.js-TAP.test.js @@ -1182,6 +1182,421 @@ ArboristNode { } ` +exports[`test/arborist/build-ideal-tree.js TAP allow a link dep to satisfy a peer dep > reified link avoids conflict 1`] = ` +ArboristNode { + "children": Map { + "@isaacs/testing-peer-dep-conflict-chain-a" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "spec": "1", + "type": "prod", + }, + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-e", + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-b" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-b", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-b", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-a/-/testing-peer-dep-conflict-chain-a-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-b" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "name": "@isaacs/testing-peer-dep-conflict-chain-b", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-c" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-c", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-c", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-b", + "name": "@isaacs/testing-peer-dep-conflict-chain-b", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-b", + "peer": true, + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-b/-/testing-peer-dep-conflict-chain-b-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-c" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-b", + "name": "@isaacs/testing-peer-dep-conflict-chain-c", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-d" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-d", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-d", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-c", + "name": "@isaacs/testing-peer-dep-conflict-chain-c", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-c", + "peer": true, + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-c/-/testing-peer-dep-conflict-chain-c-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-d" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-c", + "name": "@isaacs/testing-peer-dep-conflict-chain-d", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-e" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-e", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-e", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-d", + "name": "@isaacs/testing-peer-dep-conflict-chain-d", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-d", + "peer": true, + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-d/-/testing-peer-dep-conflict-chain-d-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-e" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-d", + "name": "@isaacs/testing-peer-dep-conflict-chain-e", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-a" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-e", + "name": "@isaacs/testing-peer-dep-conflict-chain-e", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-e", + "peer": true, + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-e/-/testing-peer-dep-conflict-chain-e-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-v" => ArboristLink { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "spec": "file:../v2", + "type": "prod", + }, + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-vv", + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "spec": "2", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-v", + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-v", + "realpath": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/v2", + "resolved": "file:../../../v2", + "target": ArboristNode { + "location": "../v2", + "name": "v2", + "packageName": "@isaacs/testing-peer-dep-conflict-chain-v", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/v2", + "version": "2.0.0", + }, + "version": "2.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-vv" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "spec": "2", + "type": "prod", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-v" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "spec": "2", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-v", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-vv", + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-vv", + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-vv/-/testing-peer-dep-conflict-chain-vv-2.0.0.tgz", + "version": "2.0.0", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-a" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "type": "prod", + }, + "@isaacs/testing-peer-dep-conflict-chain-v" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "spec": "file:../v2", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-v", + "type": "prod", + }, + "@isaacs/testing-peer-dep-conflict-chain-vv" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "spec": "2", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-vv", + "type": "prod", + }, + }, + "location": "", + "name": "main", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main", + "version": "1.0.0", +} +` + +exports[`test/arborist/build-ideal-tree.js TAP allow a link dep to satisfy a peer dep > unmet link avoids conflict 1`] = ` +ArboristNode { + "children": Map { + "@isaacs/testing-peer-dep-conflict-chain-a" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "spec": "1", + "type": "prod", + }, + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-e", + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-b" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-b", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-b", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-a/-/testing-peer-dep-conflict-chain-a-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-b" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "name": "@isaacs/testing-peer-dep-conflict-chain-b", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-c" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-c", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-c", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-b", + "name": "@isaacs/testing-peer-dep-conflict-chain-b", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-b", + "peer": true, + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-b/-/testing-peer-dep-conflict-chain-b-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-c" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-b", + "name": "@isaacs/testing-peer-dep-conflict-chain-c", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-d" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-d", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-d", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-c", + "name": "@isaacs/testing-peer-dep-conflict-chain-c", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-c", + "peer": true, + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-c/-/testing-peer-dep-conflict-chain-c-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-d" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-c", + "name": "@isaacs/testing-peer-dep-conflict-chain-d", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-e" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-e", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-e", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-d", + "name": "@isaacs/testing-peer-dep-conflict-chain-d", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-d", + "peer": true, + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-d/-/testing-peer-dep-conflict-chain-d-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-e" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-d", + "name": "@isaacs/testing-peer-dep-conflict-chain-e", + "spec": "1", + "type": "peer", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-a" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-e", + "name": "@isaacs/testing-peer-dep-conflict-chain-e", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-e", + "peer": true, + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-e/-/testing-peer-dep-conflict-chain-e-1.0.0.tgz", + "version": "1.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-v" => ArboristLink { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "spec": "file:../v2", + "type": "prod", + }, + EdgeIn { + "from": "node_modules/@isaacs/testing-peer-dep-conflict-chain-vv", + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "spec": "2", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-v", + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-v", + "realpath": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/v2", + "resolved": "file:../../../v2", + "target": ArboristNode { + "location": "../v2", + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/v2", + "version": "2.0.0", + }, + "version": "2.0.0", + }, + "@isaacs/testing-peer-dep-conflict-chain-vv" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "spec": "2", + "type": "prod", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-v" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "spec": "2", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-v", + "type": "peer", + }, + }, + "location": "node_modules/@isaacs/testing-peer-dep-conflict-chain-vv", + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main/node_modules/@isaacs/testing-peer-dep-conflict-chain-vv", + "resolved": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-vv/-/testing-peer-dep-conflict-chain-vv-2.0.0.tgz", + "version": "2.0.0", + }, + }, + "edgesOut": Map { + "@isaacs/testing-peer-dep-conflict-chain-a" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-a", + "spec": "1", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-a", + "type": "prod", + }, + "@isaacs/testing-peer-dep-conflict-chain-v" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-v", + "spec": "file:../v2", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-v", + "type": "prod", + }, + "@isaacs/testing-peer-dep-conflict-chain-vv" => EdgeOut { + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "spec": "2", + "to": "node_modules/@isaacs/testing-peer-dep-conflict-chain-vv", + "type": "prod", + }, + }, + "location": "", + "name": "main", + "path": "{CWD}/test/arborist/build-ideal-tree-allow-a-link-dep-to-satisfy-a-peer-dep/main", + "version": "1.0.0", +} +` + exports[`test/arborist/build-ideal-tree.js TAP allow updating when peer outside of explicit update set conflict, but resolves appropriately with --force > succeed if force applied 1`] = ` ArboristNode { "children": Map { diff --git a/test/arborist/build-ideal-tree.js b/test/arborist/build-ideal-tree.js index 54b76ed4c..208fae135 100644 --- a/test/arborist/build-ideal-tree.js +++ b/test/arborist/build-ideal-tree.js @@ -7,6 +7,7 @@ require(fixtures) const registryServer = require('../fixtures/registry-mocks/server.js') const {registry, auditResponse} = registryServer const npa = require('npm-package-arg') +const fs = require('fs') t.test('setup server', { bail: true }, registryServer) @@ -2605,3 +2606,39 @@ t.test('allow ERESOLVE to be forced when not in the source', async t => { t.end() }) + +t.test('allow a link dep to satisfy a peer dep', async t => { + const path = t.testdir({ + v2: { + 'package.json': JSON.stringify({ + name: '@isaacs/testing-peer-dep-conflict-chain-v', + version: '2.0.0', + }), + }, + main: { + 'package.json': JSON.stringify({ + name: 'main', + version: '1.0.0', + dependencies: { + '@isaacs/testing-peer-dep-conflict-chain-v': 'file:../v2', + '@isaacs/testing-peer-dep-conflict-chain-a': '1', + }, + }), + node_modules: { + '@isaacs': {}, // needed for when we create the link + }, + }, + }) + + const add = ['@isaacs/testing-peer-dep-conflict-chain-vv@2'] + + // avoids if the link dep is unmet + t.matchSnapshot(await printIdeal(path + '/main', { add }), 'unmet link avoids conflict') + + // also avoid the conflict if the link is present + const link = resolve(path, 'main/node_modules/@isaacs/testing-peer-dep-conflict-chain-v') + fs.symlinkSync(resolve(path, 'v2'), link, 'junction') + + // avoids if the link dep is unmet + t.matchSnapshot(await printIdeal(path + '/main', { add }), 'reified link avoids conflict') +}) diff --git a/test/fixtures/registry-mocks/content/isaacs/testing-peer-dep-conflict-chain-vv.json b/test/fixtures/registry-mocks/content/isaacs/testing-peer-dep-conflict-chain-vv.json new file mode 100644 index 000000000..3fd43bb19 --- /dev/null +++ b/test/fixtures/registry-mocks/content/isaacs/testing-peer-dep-conflict-chain-vv.json @@ -0,0 +1,92 @@ +{ + "_id": "@isaacs/testing-peer-dep-conflict-chain-vv", + "_rev": "1-efdd1288ff2d87bb801612ad93be34b2", + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "dist-tags": { + "latest": "2.0.0" + }, + "versions": { + "1.0.0": { + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "version": "1.0.0", + "peerDependencies": { + "@isaacs/testing-peer-dep-conflict-chain-v": "1" + }, + "_id": "@isaacs/testing-peer-dep-conflict-chain-vv@1.0.0", + "_nodeVersion": "15.3.0", + "_npmVersion": "7.6.0", + "dist": { + "integrity": "sha512-8CbQaqnv9GsTN+Kz6iWPLYLV7hOVQIDTpeZdDM3FXs7WW03uDI7S3rlFRdkc0ansSPMpnZb2SYTHbKn/W56G3g==", + "shasum": "6e7d8c0d29e215e2a74656483c4bdeb05b91174d", + "tarball": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-vv/-/testing-peer-dep-conflict-chain-vv-1.0.0.tgz", + "fileCount": 1, + "unpackedSize": 163, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgR8kHCRA9TVsSAnZWagAAIjAP/jw+div6Cal6j9QvCdPX\n1anNxvxYW2/ykeZpN0atcNaAYsnDaAIC7vmCeNOk6RJfIin7ASOefKQ0MhZY\nxjRPTn/9MoeuQgsqXbtjEzy0+ubn7FuX5PjayhDUtkp+dWN4gkEY99Y9Fi+k\nlq+XxtkAhuFj4+soT3tTLeXQDX6SPuiq8DgIF2owzejvXo4aR0AL+EJ3dBKD\nvAFXZb46Yty3Qgg7uu6sw4CKxSlMvdVr4ubfJ8libLFoLKhelvwjOs6cT3GP\n/JUsuYOjf2sfW8mMjUyG7kK7vO7PteQQp6wURJIgJWpAfHOgIS3uAC8xrfde\nPGNJXkECPJ7P3ixDEsjRAsecPKalsmojiSuXzVhmlFZNG4n81VMXGG7X6Irl\n3ZUAnMqBRma8DqD/gI+D32wrw3kM/ZvHK4aybVitjw2uSYKR7KXbnnN1zkDp\nPUuSP+2/FRQS0LTRU9xfhnb5Fcmap6jDrn4KpVkx6VbvwDaSigxh5zO+mpOi\nx29gc6q8niWuUdUUFYjyR75hl1wIJHyk5d40xW+1oIaCY8K1aE2cFbtXyOwo\nk4cO36c0hjQzFb6p25DHVfqz7TzS/tHdh5H6XpdSZcp3XI9xF50RSj8TSmxY\nyIobDniIeHQc+wlOiWSQZIlbvuTLiZb22RuqOktIlZd3/f2NMoCc9fzkFqK3\nriTZ\r\n=LyXS\r\n-----END PGP SIGNATURE-----\r\n" + }, + "_npmUser": { + "name": "isaacs", + "email": "i@izs.me" + }, + "directories": {}, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/testing-peer-dep-conflict-chain-vv_1.0.0_1615317254590_0.5802183600068374" + }, + "_hasShrinkwrap": false + }, + "2.0.0": { + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "version": "2.0.0", + "peerDependencies": { + "@isaacs/testing-peer-dep-conflict-chain-v": "2" + }, + "_id": "@isaacs/testing-peer-dep-conflict-chain-vv@2.0.0", + "_nodeVersion": "15.3.0", + "_npmVersion": "7.6.0", + "dist": { + "integrity": "sha512-GKxX5OHPD+i0EmjO03QnUSKxXQr6QzFVAza0fkEEUyg2/ju07BuhzhkpbxsEByFaiiQhIfsx2kmcSHtXY5hwTg==", + "shasum": "27f9622c7253589a5575e60c29fbb2380f14c54f", + "tarball": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-vv/-/testing-peer-dep-conflict-chain-vv-2.0.0.tgz", + "fileCount": 1, + "unpackedSize": 163, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgR8kNCRA9TVsSAnZWagAA97QP/i2ccR4jX9imu4EL0m+2\nD7OINfojL59pXHsCUgB25pD8OBnt4oN77RTjQQ8t930Z+PFOf7gsLA9ApJDd\nNIisf89786ymKDleuh6BR09AazyzSkM5oiEYvnNnAf6KvIctHJ5kPAq8VOyO\nIDjL40TSisuL0Om8h6NXaOdzR+TdyRP61hjPdse8VOpNwkui4gzTjiSX+WJg\nJ9xBnCS0wBkKVXoi4pCebtATUmLGGhOMv0pq0mY+bHdRa7n4r8J81v74nlyw\ndzWL6/J6b/ncUyX9Jy4ilDvnfH1I8h6U28xqzAHAYzpu0BzeTfnhJo9m+M8Y\nmNDIkXDWPeOP+pJqSocGUhYzFdBIY5EgNOcdUcD3AamocnxaOZ8Sm2ywLuBi\nv4mTj2QA0BD0WzVaJmqhQDuo6oTmP4jftg0MXz195Ncnz0xFgUdz3JDdqUas\nhTNRyw+M/h/sGgxhISELPN3fyeRiidB6whkrZZBmy5dSJQhByP2t+4JtbTL0\npNOTfQvofFeZicXBCcxAxICrKisQNua9htN8qh4lZGT3CejNWJjwB0YekwZc\nfDstNcpDOiSf0CWpWeoBHs5/n0VovZDCiRu1EigGyKjwgClF8QCpE5e+H0br\nXRpwHYLinSBtR4wdDCvAOJbvoFuKSn4jxV3FC9ajl+pOzcis4Vm/I4fsqW1O\nplqA\r\n=cfvi\r\n-----END PGP SIGNATURE-----\r\n" + }, + "_npmUser": { + "name": "isaacs", + "email": "i@izs.me" + }, + "directories": {}, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/testing-peer-dep-conflict-chain-vv_2.0.0_1615317261274_0.7280452006330511" + }, + "_hasShrinkwrap": false + } + }, + "time": { + "created": "2021-03-09T19:14:14.528Z", + "1.0.0": "2021-03-09T19:14:14.695Z", + "modified": "2021-03-09T19:14:23.579Z", + "2.0.0": "2021-03-09T19:14:21.403Z" + }, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "readme": "ERROR: No README data found!", + "readmeFilename": "" +} diff --git a/test/fixtures/registry-mocks/content/isaacs/testing-peer-dep-conflict-chain-vv.min.json b/test/fixtures/registry-mocks/content/isaacs/testing-peer-dep-conflict-chain-vv.min.json new file mode 100644 index 000000000..ac763f946 --- /dev/null +++ b/test/fixtures/registry-mocks/content/isaacs/testing-peer-dep-conflict-chain-vv.min.json @@ -0,0 +1,39 @@ +{ + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "dist-tags": { + "latest": "2.0.0" + }, + "versions": { + "1.0.0": { + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "version": "1.0.0", + "peerDependencies": { + "@isaacs/testing-peer-dep-conflict-chain-v": "1" + }, + "dist": { + "integrity": "sha512-8CbQaqnv9GsTN+Kz6iWPLYLV7hOVQIDTpeZdDM3FXs7WW03uDI7S3rlFRdkc0ansSPMpnZb2SYTHbKn/W56G3g==", + "shasum": "6e7d8c0d29e215e2a74656483c4bdeb05b91174d", + "tarball": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-vv/-/testing-peer-dep-conflict-chain-vv-1.0.0.tgz", + "fileCount": 1, + "unpackedSize": 163, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgR8kHCRA9TVsSAnZWagAAIjAP/jw+div6Cal6j9QvCdPX\n1anNxvxYW2/ykeZpN0atcNaAYsnDaAIC7vmCeNOk6RJfIin7ASOefKQ0MhZY\nxjRPTn/9MoeuQgsqXbtjEzy0+ubn7FuX5PjayhDUtkp+dWN4gkEY99Y9Fi+k\nlq+XxtkAhuFj4+soT3tTLeXQDX6SPuiq8DgIF2owzejvXo4aR0AL+EJ3dBKD\nvAFXZb46Yty3Qgg7uu6sw4CKxSlMvdVr4ubfJ8libLFoLKhelvwjOs6cT3GP\n/JUsuYOjf2sfW8mMjUyG7kK7vO7PteQQp6wURJIgJWpAfHOgIS3uAC8xrfde\nPGNJXkECPJ7P3ixDEsjRAsecPKalsmojiSuXzVhmlFZNG4n81VMXGG7X6Irl\n3ZUAnMqBRma8DqD/gI+D32wrw3kM/ZvHK4aybVitjw2uSYKR7KXbnnN1zkDp\nPUuSP+2/FRQS0LTRU9xfhnb5Fcmap6jDrn4KpVkx6VbvwDaSigxh5zO+mpOi\nx29gc6q8niWuUdUUFYjyR75hl1wIJHyk5d40xW+1oIaCY8K1aE2cFbtXyOwo\nk4cO36c0hjQzFb6p25DHVfqz7TzS/tHdh5H6XpdSZcp3XI9xF50RSj8TSmxY\nyIobDniIeHQc+wlOiWSQZIlbvuTLiZb22RuqOktIlZd3/f2NMoCc9fzkFqK3\nriTZ\r\n=LyXS\r\n-----END PGP SIGNATURE-----\r\n" + } + }, + "2.0.0": { + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "version": "2.0.0", + "peerDependencies": { + "@isaacs/testing-peer-dep-conflict-chain-v": "2" + }, + "dist": { + "integrity": "sha512-GKxX5OHPD+i0EmjO03QnUSKxXQr6QzFVAza0fkEEUyg2/ju07BuhzhkpbxsEByFaiiQhIfsx2kmcSHtXY5hwTg==", + "shasum": "27f9622c7253589a5575e60c29fbb2380f14c54f", + "tarball": "https://registry.npmjs.org/@isaacs/testing-peer-dep-conflict-chain-vv/-/testing-peer-dep-conflict-chain-vv-2.0.0.tgz", + "fileCount": 1, + "unpackedSize": 163, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgR8kNCRA9TVsSAnZWagAA97QP/i2ccR4jX9imu4EL0m+2\nD7OINfojL59pXHsCUgB25pD8OBnt4oN77RTjQQ8t930Z+PFOf7gsLA9ApJDd\nNIisf89786ymKDleuh6BR09AazyzSkM5oiEYvnNnAf6KvIctHJ5kPAq8VOyO\nIDjL40TSisuL0Om8h6NXaOdzR+TdyRP61hjPdse8VOpNwkui4gzTjiSX+WJg\nJ9xBnCS0wBkKVXoi4pCebtATUmLGGhOMv0pq0mY+bHdRa7n4r8J81v74nlyw\ndzWL6/J6b/ncUyX9Jy4ilDvnfH1I8h6U28xqzAHAYzpu0BzeTfnhJo9m+M8Y\nmNDIkXDWPeOP+pJqSocGUhYzFdBIY5EgNOcdUcD3AamocnxaOZ8Sm2ywLuBi\nv4mTj2QA0BD0WzVaJmqhQDuo6oTmP4jftg0MXz195Ncnz0xFgUdz3JDdqUas\nhTNRyw+M/h/sGgxhISELPN3fyeRiidB6whkrZZBmy5dSJQhByP2t+4JtbTL0\npNOTfQvofFeZicXBCcxAxICrKisQNua9htN8qh4lZGT3CejNWJjwB0YekwZc\nfDstNcpDOiSf0CWpWeoBHs5/n0VovZDCiRu1EigGyKjwgClF8QCpE5e+H0br\nXRpwHYLinSBtR4wdDCvAOJbvoFuKSn4jxV3FC9ajl+pOzcis4Vm/I4fsqW1O\nplqA\r\n=cfvi\r\n-----END PGP SIGNATURE-----\r\n" + } + } + }, + "modified": "2021-03-09T19:14:23.579Z" +} diff --git a/test/fixtures/testing-peer-dep-conflict-chain/vv/1/package.json b/test/fixtures/testing-peer-dep-conflict-chain/vv/1/package.json new file mode 100644 index 000000000..abd15d5d5 --- /dev/null +++ b/test/fixtures/testing-peer-dep-conflict-chain/vv/1/package.json @@ -0,0 +1,7 @@ +{ + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "version": "1.0.0", + "peerDependencies": { + "@isaacs/testing-peer-dep-conflict-chain-v": "1" + } +} diff --git a/test/fixtures/testing-peer-dep-conflict-chain/vv/2/package.json b/test/fixtures/testing-peer-dep-conflict-chain/vv/2/package.json new file mode 100644 index 000000000..225c968b7 --- /dev/null +++ b/test/fixtures/testing-peer-dep-conflict-chain/vv/2/package.json @@ -0,0 +1,7 @@ +{ + "name": "@isaacs/testing-peer-dep-conflict-chain-vv", + "version": "2.0.0", + "peerDependencies": { + "@isaacs/testing-peer-dep-conflict-chain-v": "2" + } +}