Skip to content

Commit 5ada948

Browse files
committed
fix(shrinkwrap-extractor): Handle dependencies hoisted to the workspace root for packages other than the target
1 parent e4f22b4 commit 5ada948

1 file changed

Lines changed: 46 additions & 9 deletions

File tree

internal/shrinkwrap-extractor/lib/convertPackageLockToShrinkwrap.js

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,12 @@ export default async function convertPackageLockToShrinkwrap(workspaceRootDir, t
6060

6161
// Using the keys, extract relevant package-entries from package-lock.json
6262
const extractedPackages = Object.create(null);
63+
const resolvedConflicts = new Set();
6364
for (let [packageLoc, node] of relevantPackageLocations) {
65+
if (resolvedConflicts.has(packageLoc)) {
66+
// This package location was already moved due to a conflict
67+
continue;
68+
}
6469
let pkg = packageLockJson.packages[packageLoc];
6570
if (pkg.link) {
6671
pkg = packageLockJson.packages[pkg.resolved];
@@ -72,15 +77,47 @@ export default async function convertPackageLockToShrinkwrap(workspaceRootDir, t
7277
throw new Error(`Duplicate root package entry for "${targetPackageName}"`);
7378
}
7479
} else {
75-
packageLoc = normalizePackageLocation(packageLoc, node, targetPackageName, tree.packageName);
76-
}
77-
if (packageLoc !== "" && !pkg.resolved) {
78-
// For all but the root package, ensure that "resolved" and "integrity" fields are present
79-
// These are always missing for locally linked packages, but sometimes also for others (e.g. if installed
80-
// from local cache)
81-
const {resolved, integrity} = await fetchPackageMetadata(node.packageName, node.version, workspaceRootDir);
82-
pkg.resolved = resolved;
83-
pkg.integrity = integrity;
80+
if (!pkg.resolved) {
81+
// For all but the root package, ensure that "resolved" and "integrity" fields are present
82+
// These are always missing for locally linked packages, but sometimes also for others
83+
// (e.g. if installed from local cache)
84+
const {resolved, integrity} = await fetchPackageMetadata(
85+
node.packageName, node.version, workspaceRootDir);
86+
pkg.resolved = resolved;
87+
pkg.integrity = integrity;
88+
}
89+
// Align package locations with new target
90+
const newPackageLoc = normalizePackageLocation(packageLoc, node, targetPackageName, tree.packageName);
91+
// Detect conflicts with dependencies hoisted to root level for packages other than the target
92+
const existingPackageAtNewLocation = relevantPackageLocations.get(newPackageLoc);
93+
if (newPackageLoc !== packageLoc && existingPackageAtNewLocation) {
94+
if (pkg.version !== existingPackageAtNewLocation.version) {
95+
console.log(
96+
`Hoisting conflict: Package "${node.packageName}" (from "${packageLoc}") already exists at ` +
97+
`new location ${newPackageLoc} in version ${existingPackageAtNewLocation.version}`);
98+
resolvedConflicts.add(newPackageLoc);
99+
const conflictPkg = packageLockJson.packages[newPackageLoc];
100+
if (!conflictPkg.resolved) {
101+
// For all but the root package, ensure that "resolved" and "integrity" fields are present
102+
// These are always missing for locally linked packages, but sometimes also for others
103+
// (e.g. if installed from local cache)
104+
const {resolved, integrity} = await fetchPackageMetadata(
105+
existingPackageAtNewLocation.packageName, existingPackageAtNewLocation.version,
106+
workspaceRootDir);
107+
conflictPkg.resolved = resolved;
108+
conflictPkg.integrity = integrity;
109+
}
110+
// Move existing package to a package-specific subdirectories to avoid conflict
111+
for (const edge of existingPackageAtNewLocation.edgesIn) {
112+
const parentPackage = edge.from.top.packageName;
113+
console.log(`Moving conflicting package "${node.packageName}" under ` +
114+
`"node_modules/${parentPackage}/node_modules/"`);
115+
const subPath = `node_modules/${parentPackage}/node_modules/${node.packageName}`;
116+
extractedPackages[subPath] = structuredClone(conflictPkg);
117+
}
118+
}
119+
}
120+
packageLoc = newPackageLoc;
84121
}
85122
extractedPackages[packageLoc] = pkg;
86123
}

0 commit comments

Comments
 (0)