From 789f9bc8259dbe95486b0a8da2d8c23216276bff Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 16 Sep 2020 14:52:45 -0700 Subject: [PATCH] Do not try to re-resolve failed nodes forever Via: https://github.com/targos/npm7-cra#issue-4-npm-i-react17-never-ends --- lib/arborist/build-ideal-tree.js | 4 +++ test/arborist/build-ideal-tree.js | 44 ++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/lib/arborist/build-ideal-tree.js b/lib/arborist/build-ideal-tree.js index fc19195a1..f061a6d0d 100644 --- a/lib/arborist/build-ideal-tree.js +++ b/lib/arborist/build-ideal-tree.js @@ -758,11 +758,15 @@ This is a one-time fix-up, please be patient... // the nodes into the ideal tree, and then prune. So, fetching those // possibly-bundled meta-deps at this point doesn't cause any worse // problems than a few unnecessary packument fetches. + + // also skip over any nodes in the tree that failed to load, since those + // will crash the install later on anyway. const bd = node.isRoot ? null : node.package.bundleDependencies const bundled = new Set(bd || []) return [...node.edgesOut.values()] .filter(edge => !bundled.has(edge.name) && + !(edge.to && this[_loadFailures].has(edge.to)) && !(edge.to && edge.to.inShrinkwrap) && (!edge.valid || !edge.to || this[_updateNames].includes(edge.name) || this[_isVulnerable](edge.to) || diff --git a/test/arborist/build-ideal-tree.js b/test/arborist/build-ideal-tree.js index bb5015137..5bf0cb9fc 100644 --- a/test/arborist/build-ideal-tree.js +++ b/test/arborist/build-ideal-tree.js @@ -1364,11 +1364,12 @@ t.test('pathologically nested dependency cycle', t => t.resolveMatchSnapshot(printIdeal( resolve(fixtures, 'pathological-dep-nesting-cycle')))) -t.test('resolve files from cwd in global mode, Arb path in local mode', t => { +t.test('resolve file deps from cwd', t => { const cwd = process.cwd() t.teardown(() => process.chdir(cwd)) const path = t.testdir({ - global: {} + global: {}, + local: {}, }) const fixturedir = resolve(fixtures, 'root-bundler') process.chdir(fixturedir) @@ -1378,6 +1379,7 @@ t.test('resolve files from cwd in global mode, Arb path in local mode', t => { ...OPT, }) return arb.buildIdealTree({ + path: `${path}/local`, add: ['child-1.2.3.tgz'], global: true, }).then(tree => { @@ -1386,7 +1388,7 @@ t.test('resolve files from cwd in global mode, Arb path in local mode', t => { }) }) -t.only('resolve links in global mode', t => { +t.test('resolve links in global mode', t => { const path = t.testdir({ global: {}, lib: { @@ -1598,3 +1600,39 @@ t.test('push conflicted peer deps deeper in to the tree to solve', async t => { const path = resolve(fixtures, 'testing-peer-dep-conflict-chain/override-dep') t.matchSnapshot(await printIdeal(path)) }) + +t.test('do not continually re-resolve deps that failed to load', async t => { + const path = t.testdir({ + node_modules: { + '@isaacs': { + 'this-does-not-exist-actually': { + 'package.json': JSON.stringify({ + name: '@isaacs/this-does-not-exist-actually', + version: '1.0.0', + }), + }, + 'depends-on-load-failer': { + 'package.json': JSON.stringify({ + name: '@isaacs/depends-on-load-failer', + version: '1.0.0', + dependencies: { + '@isaacs/this-does-not-exist-actually': '1.x', + }, + }), + }, + }, + }, + 'package.json': JSON.stringify({ + name: 'my-project', + version: '1.2.3', + dependencies: { + '@isaacs/depends-on-load-failer': '1.x', + '@isaacs/this-does-not-exist-actually': '1.x', + }, + }), + }) + const arb = new Arborist({...OPT, path }) + t.rejects(() => arb.buildIdealTree({ add: [ + '@isaacs/this-does-not-exist-actually@2.x', + ]}), { code: 'E404' }) +})