Skip to content

Commit 2a56305

Browse files
Merge pull request #293 from snyk/fix/nodejs-transitive-with-a-top-level-alias-but-transitive-is-not
fix: nodejs transitive with a top level alias but transitive it not
2 parents 58e5716 + 9e53a97 commit 2a56305

File tree

5 files changed

+979
-15
lines changed

5 files changed

+979
-15
lines changed

lib/dep-graph-builders/npm-lock-v2/index.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -435,20 +435,9 @@ export const getChildNodeKey = (
435435
// include all ancestors depending on hoisting
436436
const isBundled = ancestry[ancestry.length - 1].inBundle;
437437

438-
// Resolve the real package name in case 'name' is an alias
439-
// This ensures ancestry matching works correctly with alias resolution
440-
let resolvedName = name;
441-
if (candidateKeys.length > 0) {
442-
const firstCandidate = pkgs[candidateKeys[0]];
443-
if (firstCandidate && firstCandidate.name && firstCandidate.name !== name) {
444-
resolvedName = firstCandidate.name;
445-
}
446-
}
447-
448-
const ancestryFromRootOperatingIdx = [
449-
...ancestry.slice(1), // Always start from index 1 (skip only the true root)
450-
{ id: `${name}@${version}`, name: resolvedName, version },
451-
];
438+
// Base ancestry without the current package - we'll add the package with
439+
// the correct resolved name per-candidate during filtering
440+
const baseAncestryFromRoot = ancestry.slice(1);
452441

453442
// Find the bundle owner for the bundle root check below
454443
let bundleOwnerName: string | undefined;
@@ -501,6 +490,18 @@ export const getChildNodeKey = (
501490
return segment;
502491
});
503492

493+
// Resolve the real package name for THIS specific candidate
494+
// This is important when there are aliases - each candidate may resolve to a different real name
495+
const candidatePkg = pkgs[candidate];
496+
const resolvedNameForCandidate =
497+
candidatePkg && candidatePkg.name ? candidatePkg.name : name;
498+
499+
// Build the full ancestry including the current package with its resolved name
500+
const ancestryFromRootOperatingIdx = [
501+
...baseAncestryFromRoot,
502+
{ id: `${name}@${version}`, name: resolvedNameForCandidate, version },
503+
];
504+
504505
// Check the ancestry of the candidate is a subset of
505506
// the current pkg. If it is not then it can't be a
506507
// valid key.
@@ -543,7 +544,7 @@ export const getChildNodeKey = (
543544
return filteredCandidates[0];
544545
}
545546

546-
const ancestryNames = ancestry.map((el) => el.name).concat(resolvedName);
547+
const ancestryNames = ancestry.map((el) => el.name).concat(name);
547548
while (ancestryNames.length > 0) {
548549
const possibleKey = `node_modules/${ancestryNames.join('/node_modules/')}`;
549550

0 commit comments

Comments
 (0)