From 6f33d74f310fa27aad30fd00d58d8e4404ef8cb2 Mon Sep 17 00:00:00 2001 From: AmirHossein Sakhravi Date: Mon, 1 Jul 2024 20:47:41 +0330 Subject: [PATCH] fix(arborist): safeguard against null node.target in flag calculation (#7579) If a node represents a symbolic link or a file dep (node.isLink is true), its target is expected to reference another node in the dependency tree. If the linking is not done correctly or is incomplete, node.target might be null. in this PR, a null check is added to ensure node.target is not null or before proceeding, which will prevent causing errors like: `npm error Cannot set properties of null (setting 'peer')` ## References Related to #7065, Fixes #6622, #5007, Closes #6622, #5007 --- workspaces/arborist/lib/calc-dep-flags.js | 15 +++++++++++---- workspaces/arborist/test/calc-dep-flags.js | 13 +++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/workspaces/arborist/lib/calc-dep-flags.js b/workspaces/arborist/lib/calc-dep-flags.js index 45ed9562479af..bcd30d0f493c7 100644 --- a/workspaces/arborist/lib/calc-dep-flags.js +++ b/workspaces/arborist/lib/calc-dep-flags.js @@ -31,6 +31,10 @@ const calcDepFlagsStep = (node) => { // for links, map their hierarchy appropriately if (node.isLink) { + // node.target can be null, we check to ensure it's not null before proceeding + if (node.target == null) { + return node + } node.target.dev = node.dev node.target.optional = node.optional node.target.devOptional = node.devOptional @@ -97,15 +101,18 @@ const unsetFlag = (node, flag) => { tree: node, visit: node => { node.extraneous = node[flag] = false - if (node.isLink) { + if (node.isLink && node.target) { node.target.extraneous = node.target[flag] = false } }, getChildren: node => { const children = [] - for (const edge of node.target.edgesOut.values()) { - if (edge.to && edge.to[flag] && - (flag !== 'peer' && edge.type === 'peer' || edge.type === 'prod') + const targetNode = node.isLink && node.target ? node.target : node + for (const edge of targetNode.edgesOut.values()) { + if ( + edge.to && + edge.to[flag] && + ((flag !== 'peer' && edge.type === 'peer') || edge.type === 'prod') ) { children.push(edge.to) } diff --git a/workspaces/arborist/test/calc-dep-flags.js b/workspaces/arborist/test/calc-dep-flags.js index bba64fc5dd0dc..ff7f320ded29d 100644 --- a/workspaces/arborist/test/calc-dep-flags.js +++ b/workspaces/arborist/test/calc-dep-flags.js @@ -264,3 +264,16 @@ t.test('set parents to not extraneous when visiting', t => { t.equal(bazLink.devOptional, false, 'bazlink not devOptional') t.end() }) + +t.test('check null target in link', async t => { + const root = new Link({ + path: '/some/path', + realpath: '/some/path', + pkg: { + dependencies: { foo: '' }, + }, + }) + t.doesNotThrow(() => calcDepFlags(root)) + t.doesNotThrow(() => calcDepFlags(root, false)) + t.end() +})