diff --git a/workspaces/arborist/lib/node.js b/workspaces/arborist/lib/node.js index 13370a50ab475..a0ee56affc6e6 100644 --- a/workspaces/arborist/lib/node.js +++ b/workspaces/arborist/lib/node.js @@ -1505,6 +1505,10 @@ class Node { } [_reloadNamedEdges] (name, rootLoc = this.location) { + if (!this.edgesOut.size && !this.children.size && !this.fsChildren.size) { + return + } + const edge = this.edgesOut.get(name) // if we don't have an edge, do nothing, but keep descending const rootLocResolved = edge && edge.to && diff --git a/workspaces/arborist/test/node.js b/workspaces/arborist/test/node.js index ec474e0b7d75e..cc1fd7b6845fc 100644 --- a/workspaces/arborist/test/node.js +++ b/workspaces/arborist/test/node.js @@ -1332,6 +1332,46 @@ t.test('reparenting keeps children in root inventory', async t => { t.equal(root.inventory.has(fsNested), true) }) +t.test('reloading named edges skips empty leaves without caching their state', t => { + const root = new Node({ path: '/some/path' }) + const leaf = new Node({ parent: root, pkg: { name: 'leaf' } }) + const lookups = [] + const get = leaf.edgesOut.get + leaf.edgesOut.get = function (name) { + lookups.push(name) + return get.call(this, name) + } + + const foo = new Node({ parent: root, pkg: { name: 'foo', version: '1.0.0' } }) + t.same(lookups, [], 'no lookup in an empty leaf during the refresh') + delete leaf.edgesOut.get + + leaf.package = { name: 'leaf', dependencies: { foo: '1' } } + t.equal(leaf.edgesOut.get('foo').to, foo) + foo.parent = null + t.equal(leaf.edgesOut.get('foo').to, null, 'the newly added edge still refreshes') + t.end() +}) + +t.test('reloading traverses dependency-free parents with children', t => { + for (const kind of ['parent', 'fsParent']) { + const root = new Node({ path: '/some/path' }) + const parent = new Node({ parent: root, pkg: { name: 'parent' } }) + const child = new Node({ + [kind]: parent, + path: kind === 'fsParent' ? `${parent.path}/child` : undefined, + pkg: { name: 'child', dependencies: { foo: '1' } }, + }) + t.equal(parent.edgesOut.size, 0) + t.equal(child.edgesOut.get('foo').to, null) + const foo = new Node({ parent: root, pkg: { name: 'foo', version: '1.0.0' } }) + t.equal(child.edgesOut.get('foo').to, foo, `${kind} descendants are refreshed`) + foo.parent = null + t.equal(child.edgesOut.get('foo').to, null, `${kind} descendants track removals`) + } + t.end() +}) + t.test('reloading named edges should refresh edgesIn', t => { // pathological dep nesting scenario: //