From 6dae62e636cdddbdd4e99653c2809fe38dfbe9f5 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 13 Apr 2026 08:17:38 +0100 Subject: [PATCH] fix(arborist): remove inert optional extraneous shared deps A shared dependency of two or more umet optional dependencies, where no other package in the tree also depends on that shared package, does not need to be installed. This removes packages currently marked as extraneous from trees where some platform-specific packages share a dependency. --- workspaces/arborist/lib/optional-set.js | 2 +- workspaces/arborist/test/optional-set.js | 41 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/workspaces/arborist/lib/optional-set.js b/workspaces/arborist/lib/optional-set.js index 021a0ef72aa17..891961fe2cd95 100644 --- a/workspaces/arborist/lib/optional-set.js +++ b/workspaces/arborist/lib/optional-set.js @@ -26,7 +26,7 @@ const optionalSet = node => { // now that we've hit the boundary, gather the rest of the nodes in // the optional section that don't have dependents outside the set. - return gatherDepSet(set, edge => !set.has(edge.to)) + return gatherDepSet(set, edge => !set.has(edge.to) && !edge.from?.inert) } module.exports = optionalSet diff --git a/workspaces/arborist/test/optional-set.js b/workspaces/arborist/test/optional-set.js index cf40bd382af1c..27719254eae06 100644 --- a/workspaces/arborist/test/optional-set.js +++ b/workspaces/arborist/test/optional-set.js @@ -89,3 +89,44 @@ t.equal(setM.has(nodeN), true, 'set m includes n') const setB = optionalSet(nodeB) t.equal(setB.size, 1, 'gathering from b is only b') t.equal(setB.has(nodeB), true, 'set b includes b') + +// tree (OPT opt-p, OPT opt-q) +// +-- OPT opt-p (PROD shared-dep) +// +-- OPT opt-q (PROD shared-dep) +// +-- shared-dep () +const sharedTree = new Node({ + path: '/path/to/shared-tree', + pkg: { + optionalDependencies: { + 'opt-p': '', + 'opt-q': '', + }, + }, + children: [ + { pkg: { name: 'opt-p', version: '1.0.0', dependencies: { 'shared-dep': '' } } }, + { pkg: { name: 'opt-q', version: '1.0.0', dependencies: { 'shared-dep': '' } } }, + { pkg: { name: 'shared-dep', version: '1.0.0' } }, + ], +}) + +calcDepFlags(sharedTree) + +const nodeOptP = sharedTree.children.get('opt-p') +const nodeOptQ = sharedTree.children.get('opt-q') +const nodeSharedDep = sharedTree.children.get('shared-dep') + +// Simulate opt-p failing platform check and being marked inert first +const setOptP = optionalSet(nodeOptP) +// shared-dep is excluded because opt-q (not yet inert) also depends on it +t.equal(setOptP.has(nodeOptP), true, 'set opt-p includes opt-p') +t.equal(setOptP.has(nodeSharedDep), false, 'set opt-p excludes shared-dep (opt-q is not inert)') +for (const n of setOptP) { + n.inert = true +} + +// Simulate opt-q failing platform check second (opt-p is already inert) +const setOptQ = optionalSet(nodeOptQ) +// shared-dep now has no active external dependents and is included +t.equal(setOptQ.has(nodeOptQ), true, 'set opt-q includes opt-q') +t.equal(setOptQ.has(nodeSharedDep), true, 'set opt-q includes shared-dep (opt-p is inert)') +t.equal(setOptQ.size, 2, 'set opt-q has two nodes: opt-q and shared-dep')