@yarnpkg/nm 3.0.0-rc.7 → 3.0.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/buildNodeModulesTree.d.ts +1 -0
- package/lib/buildNodeModulesTree.js +118 -71
- package/lib/hoist.d.ts +1 -0
- package/lib/hoist.js +71 -21
- package/package.json +5 -5
|
@@ -39,6 +39,7 @@ export interface NodeModulesTreeOptions {
|
|
|
39
39
|
pnpifyFs?: boolean;
|
|
40
40
|
validateExternalSoftLinks?: boolean;
|
|
41
41
|
hoistingLimitsByCwd?: Map<PortablePath, NodeModulesHoistingLimits>;
|
|
42
|
+
selfReferencesByCwd?: Map<PortablePath, Boolean>;
|
|
42
43
|
project?: Project;
|
|
43
44
|
}
|
|
44
45
|
/** Package locator key for usage inside maps */
|
|
@@ -84,88 +84,120 @@ const areRealLocatorsEqual = (a, b) => {
|
|
|
84
84
|
const realB = core_1.structUtils.isVirtualLocator(b) ? core_1.structUtils.devirtualizeLocator(b) : b;
|
|
85
85
|
return core_1.structUtils.areLocatorsEqual(realA, realB);
|
|
86
86
|
};
|
|
87
|
+
const isExternalSoftLink = (pkg, locator, pnp, topPkgPortableLocation) => {
|
|
88
|
+
if (pkg.linkType !== LinkType.SOFT)
|
|
89
|
+
return false;
|
|
90
|
+
const realSoftLinkPath = fslib_1.npath.toPortablePath(pnp.resolveVirtual && locator.reference && locator.reference.startsWith(`virtual:`) ? pnp.resolveVirtual(pkg.packageLocation) : pkg.packageLocation);
|
|
91
|
+
return fslib_1.ppath.contains(topPkgPortableLocation, realSoftLinkPath) === null;
|
|
92
|
+
};
|
|
87
93
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* @param pnp PnP API
|
|
91
|
-
*
|
|
92
|
-
* @returns package tree, packages info and locators
|
|
94
|
+
* Builds a map representing layout of nested workspaces and internal portals on the file system.
|
|
93
95
|
*/
|
|
94
|
-
const
|
|
95
|
-
const pnpRoots = pnp.getDependencyTreeRoots();
|
|
96
|
-
const errors = [];
|
|
97
|
-
let preserveSymlinksRequired = false;
|
|
98
|
-
const hoistingLimits = new Map();
|
|
99
|
-
const workspaceDependenciesMap = new Map();
|
|
96
|
+
const buildWorkspaceMap = (pnp) => {
|
|
100
97
|
const topPkg = pnp.getPackageInformation(pnp.topLevel);
|
|
101
98
|
if (topPkg === null)
|
|
102
99
|
throw new Error(`Assertion failed: Expected the top-level package to have been registered`);
|
|
103
100
|
const topLocator = pnp.findPackageLocator(topPkg.packageLocation);
|
|
104
101
|
if (topLocator === null)
|
|
105
102
|
throw new Error(`Assertion failed: Expected the top-level package to have a physical locator`);
|
|
106
|
-
const topPkgPortableLocation = fslib_1.npath.toPortablePath(topPkg.packageLocation);
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
103
|
+
const topPkgPortableLocation = fslib_1.npath.toPortablePath(topPkg.packageLocation.slice(0, -1));
|
|
104
|
+
const workspaceMap = new Map();
|
|
105
|
+
const workspaceTree = { children: new Map() };
|
|
106
|
+
const pnpRoots = pnp.getDependencyTreeRoots();
|
|
107
|
+
// Workspace and internal portal locations to locators map
|
|
108
|
+
const workspaceLikeLocators = new Map();
|
|
109
|
+
const seen = new Set();
|
|
110
|
+
const visit = (locator, parentLocator) => {
|
|
111
|
+
const locatorKey = stringifyLocator(locator);
|
|
112
|
+
if (seen.has(locatorKey))
|
|
113
|
+
return;
|
|
114
|
+
seen.add(locatorKey);
|
|
115
|
+
const pkg = pnp.getPackageInformation(locator);
|
|
116
|
+
if (pkg) {
|
|
117
|
+
const parentLocatorKey = parentLocator ? stringifyLocator(parentLocator) : ``;
|
|
118
|
+
if (stringifyLocator(locator) !== parentLocatorKey && pkg.linkType === LinkType.SOFT && !isExternalSoftLink(pkg, locator, pnp, topPkgPortableLocation)) {
|
|
119
|
+
const location = getRealPackageLocation(pkg, locator, pnp);
|
|
120
|
+
const prevLocator = workspaceLikeLocators.get(location);
|
|
121
|
+
// Give workspaces a priority over portals and other protocols pointing to the same location
|
|
122
|
+
// The devDependencies are not installed for portals, but installed for workspaces
|
|
123
|
+
if (!prevLocator || locator.reference.startsWith(`workspace:`)) {
|
|
124
|
+
workspaceLikeLocators.set(location, locator);
|
|
119
125
|
}
|
|
120
|
-
node = nextNode;
|
|
121
126
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
let dependencies = workspaceDependenciesMap.get(parentLocatorKey);
|
|
128
|
-
if (!dependencies) {
|
|
129
|
-
dependencies = new Set();
|
|
130
|
-
workspaceDependenciesMap.set(parentLocatorKey, dependencies);
|
|
127
|
+
for (const [name, referencish] of pkg.packageDependencies) {
|
|
128
|
+
if (referencish !== null) {
|
|
129
|
+
if (!pkg.packagePeers.has(name)) {
|
|
130
|
+
visit(pnp.getLocator(name, referencish), locator);
|
|
131
|
+
}
|
|
131
132
|
}
|
|
132
|
-
dependencies.add(node.workspaceLocator);
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
for (const locator of pnpRoots)
|
|
137
|
+
visit(locator, null);
|
|
138
|
+
const cwdSegments = topPkgPortableLocation.split(fslib_1.ppath.sep);
|
|
139
|
+
for (const locator of workspaceLikeLocators.values()) {
|
|
140
|
+
const pkg = pnp.getPackageInformation(locator);
|
|
141
|
+
const location = fslib_1.npath.toPortablePath(pkg.packageLocation.slice(0, -1));
|
|
142
|
+
const segments = location.split(fslib_1.ppath.sep).slice(cwdSegments.length);
|
|
143
|
+
let node = workspaceTree;
|
|
144
|
+
for (const segment of segments) {
|
|
145
|
+
let nextNode = node.children.get(segment);
|
|
146
|
+
if (!nextNode) {
|
|
147
|
+
nextNode = { children: new Map() };
|
|
148
|
+
node.children.set(segment, nextNode);
|
|
136
149
|
}
|
|
137
|
-
|
|
138
|
-
for (const child of workspaceTree.children.values()) {
|
|
139
|
-
addWorkspace(child, workspaceTree.workspaceLocator);
|
|
150
|
+
node = nextNode;
|
|
140
151
|
}
|
|
152
|
+
node.workspaceLocator = locator;
|
|
141
153
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
dependencies.add(locator);
|
|
154
|
+
const addWorkspace = (node, parentWorkspaceLocator) => {
|
|
155
|
+
if (node.workspaceLocator) {
|
|
156
|
+
const parentLocatorKey = stringifyLocator(parentWorkspaceLocator);
|
|
157
|
+
let dependencies = workspaceMap.get(parentLocatorKey);
|
|
158
|
+
if (!dependencies) {
|
|
159
|
+
dependencies = new Set();
|
|
160
|
+
workspaceMap.set(parentLocatorKey, dependencies);
|
|
151
161
|
}
|
|
162
|
+
dependencies.add(node.workspaceLocator);
|
|
152
163
|
}
|
|
153
|
-
|
|
164
|
+
for (const child of node.children.values()) {
|
|
165
|
+
addWorkspace(child, node.workspaceLocator || parentWorkspaceLocator);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
for (const child of workspaceTree.children.values())
|
|
169
|
+
addWorkspace(child, workspaceTree.workspaceLocator);
|
|
170
|
+
return workspaceMap;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Traverses PnP tree and produces input for the `RawHoister`
|
|
174
|
+
*
|
|
175
|
+
* @param pnp PnP API
|
|
176
|
+
*
|
|
177
|
+
* @returns package tree, packages info and locators
|
|
178
|
+
*/
|
|
179
|
+
const buildPackageTree = (pnp, options) => {
|
|
180
|
+
const errors = [];
|
|
181
|
+
let preserveSymlinksRequired = false;
|
|
182
|
+
const hoistingLimits = new Map();
|
|
183
|
+
const workspaceMap = buildWorkspaceMap(pnp);
|
|
184
|
+
const topPkg = pnp.getPackageInformation(pnp.topLevel);
|
|
185
|
+
if (topPkg === null)
|
|
186
|
+
throw new Error(`Assertion failed: Expected the top-level package to have been registered`);
|
|
187
|
+
const topLocator = pnp.findPackageLocator(topPkg.packageLocation);
|
|
188
|
+
if (topLocator === null)
|
|
189
|
+
throw new Error(`Assertion failed: Expected the top-level package to have a physical locator`);
|
|
190
|
+
const topPkgPortableLocation = fslib_1.npath.toPortablePath(topPkg.packageLocation.slice(0, -1));
|
|
154
191
|
const packageTree = {
|
|
155
192
|
name: topLocator.name,
|
|
156
193
|
identName: topLocator.name,
|
|
157
194
|
reference: topLocator.reference,
|
|
158
195
|
peerNames: topPkg.packagePeers,
|
|
159
196
|
dependencies: new Set(),
|
|
197
|
+
isWorkspace: true,
|
|
160
198
|
};
|
|
161
199
|
const nodes = new Map();
|
|
162
200
|
const getNodeKey = (name, locator) => `${stringifyLocator(locator)}:${name}`;
|
|
163
|
-
const isExternalSoftLink = (pkg, locator) => {
|
|
164
|
-
if (pkg.linkType !== LinkType.SOFT || !options.project)
|
|
165
|
-
return false;
|
|
166
|
-
const realSoftLinkPath = fslib_1.npath.toPortablePath(pnp.resolveVirtual && locator.reference && locator.reference.startsWith(`virtual:`) ? pnp.resolveVirtual(pkg.packageLocation) : pkg.packageLocation);
|
|
167
|
-
return fslib_1.ppath.contains(options.project.cwd, realSoftLinkPath) === null;
|
|
168
|
-
};
|
|
169
201
|
const addPackageToTree = (name, pkg, locator, parent, parentPkg, parentDependencies, parentRelativeCwd, isHoistBorder) => {
|
|
170
202
|
var _a, _b;
|
|
171
203
|
const nodeKey = getNodeKey(name, locator);
|
|
@@ -175,18 +207,22 @@ const buildPackageTree = (pnp, options) => {
|
|
|
175
207
|
node = packageTree;
|
|
176
208
|
nodes.set(nodeKey, packageTree);
|
|
177
209
|
}
|
|
210
|
+
const isExternalSoftLinkPackage = isExternalSoftLink(pkg, locator, pnp, topPkgPortableLocation);
|
|
178
211
|
if (!node) {
|
|
212
|
+
const isWorkspace = pkg.linkType === LinkType.SOFT && locator.name.endsWith(WORKSPACE_NAME_SUFFIX);
|
|
179
213
|
node = {
|
|
180
214
|
name,
|
|
181
215
|
identName: locator.name,
|
|
182
216
|
reference: locator.reference,
|
|
183
217
|
dependencies: new Set(),
|
|
184
|
-
|
|
218
|
+
// View peer dependencies as regular dependencies for workspaces
|
|
219
|
+
// (meeting workspace peer dependency constraints is sometimes hard, sometimes impossible for the nm linker)
|
|
220
|
+
peerNames: isWorkspace ? new Set() : pkg.packagePeers,
|
|
221
|
+
isWorkspace,
|
|
185
222
|
};
|
|
186
223
|
nodes.set(nodeKey, node);
|
|
187
224
|
}
|
|
188
225
|
let hoistPriority;
|
|
189
|
-
const isExternalSoftLinkPackage = isExternalSoftLink(pkg, locator);
|
|
190
226
|
if (isExternalSoftLinkPackage)
|
|
191
227
|
// External soft link dependencies have the highest priority - we don't want to install inside them
|
|
192
228
|
hoistPriority = 2;
|
|
@@ -218,15 +254,17 @@ const buildPackageTree = (pnp, options) => {
|
|
|
218
254
|
}
|
|
219
255
|
}
|
|
220
256
|
}
|
|
221
|
-
const locatorKey = stringifyLocator(locator);
|
|
222
|
-
const
|
|
223
|
-
if (
|
|
224
|
-
for (const workspaceLocator of
|
|
257
|
+
const locatorKey = stringifyLocator({ name: locator.name.replace(WORKSPACE_NAME_SUFFIX, ``), reference: locator.reference });
|
|
258
|
+
const innerWorkspaces = workspaceMap.get(locatorKey);
|
|
259
|
+
if (innerWorkspaces) {
|
|
260
|
+
for (const workspaceLocator of innerWorkspaces) {
|
|
225
261
|
allDependencies.set(`${workspaceLocator.name}${WORKSPACE_NAME_SUFFIX}`, workspaceLocator.reference);
|
|
226
262
|
}
|
|
227
263
|
}
|
|
228
|
-
|
|
229
|
-
|
|
264
|
+
if (pkg !== parentPkg || pkg.linkType !== LinkType.SOFT || !options.selfReferencesByCwd || options.selfReferencesByCwd.get(parentRelativeCwd))
|
|
265
|
+
parent.dependencies.add(node);
|
|
266
|
+
const isWorkspaceDependency = locator !== topLocator && pkg.linkType === LinkType.SOFT && !locator.name.endsWith(WORKSPACE_NAME_SUFFIX) && !isExternalSoftLinkPackage;
|
|
267
|
+
if (!isSeen && !isWorkspaceDependency) {
|
|
230
268
|
const siblingPortalDependencyMap = new Map();
|
|
231
269
|
for (const [depName, referencish] of allDependencies) {
|
|
232
270
|
if (referencish !== null) {
|
|
@@ -235,7 +273,7 @@ const buildPackageTree = (pnp, options) => {
|
|
|
235
273
|
const depPkg = pnp.getPackageInformation(pkgLocator);
|
|
236
274
|
if (depPkg === null)
|
|
237
275
|
throw new Error(`Assertion failed: Expected the package to have been registered`);
|
|
238
|
-
const isExternalSoftLinkDep = isExternalSoftLink(depPkg, depLocator);
|
|
276
|
+
const isExternalSoftLinkDep = isExternalSoftLink(depPkg, depLocator, pnp, topPkgPortableLocation);
|
|
239
277
|
if (options.validateExternalSoftLinks && options.project && isExternalSoftLinkDep) {
|
|
240
278
|
if (depPkg.packageDependencies.size > 0)
|
|
241
279
|
preserveSymlinksRequired = true;
|
|
@@ -287,7 +325,7 @@ const buildPackageTree = (pnp, options) => {
|
|
|
287
325
|
const isHoistBorder = parentHoistingLimits === NodeModulesHoistingLimits.DEPENDENCIES
|
|
288
326
|
|| depHoistingLimits === NodeModulesHoistingLimits.DEPENDENCIES
|
|
289
327
|
|| depHoistingLimits === NodeModulesHoistingLimits.WORKSPACES;
|
|
290
|
-
addPackageToTree(
|
|
328
|
+
addPackageToTree(depName, depPkg, depLocator, node, pkg, allDependencies, relativeDepCwd, isHoistBorder);
|
|
291
329
|
}
|
|
292
330
|
}
|
|
293
331
|
}
|
|
@@ -295,6 +333,12 @@ const buildPackageTree = (pnp, options) => {
|
|
|
295
333
|
addPackageToTree(topLocator.name, topPkg, topLocator, packageTree, topPkg, topPkg.packageDependencies, fslib_2.PortablePath.dot, false);
|
|
296
334
|
return { packageTree, hoistingLimits, errors, preserveSymlinksRequired };
|
|
297
335
|
};
|
|
336
|
+
function getRealPackageLocation(pkg, locator, pnp) {
|
|
337
|
+
const realPath = pnp.resolveVirtual && locator.reference && locator.reference.startsWith(`virtual:`)
|
|
338
|
+
? pnp.resolveVirtual(pkg.packageLocation)
|
|
339
|
+
: pkg.packageLocation;
|
|
340
|
+
return fslib_1.npath.toPortablePath(realPath || pkg.packageLocation);
|
|
341
|
+
}
|
|
298
342
|
function getTargetLocatorPath(locator, pnp, options) {
|
|
299
343
|
const pkgLocator = pnp.getLocator(locator.name.replace(WORKSPACE_NAME_SUFFIX, ``), locator.reference);
|
|
300
344
|
const info = pnp.getPackageInformation(pkgLocator);
|
|
@@ -312,10 +356,7 @@ function getTargetLocatorPath(locator, pnp, options) {
|
|
|
312
356
|
linkType = LinkType.SOFT;
|
|
313
357
|
}
|
|
314
358
|
else {
|
|
315
|
-
|
|
316
|
-
? pnp.resolveVirtual(info.packageLocation)
|
|
317
|
-
: info.packageLocation;
|
|
318
|
-
target = fslib_1.npath.toPortablePath(truePath || info.packageLocation);
|
|
359
|
+
target = getRealPackageLocation(info, locator, pnp);
|
|
319
360
|
linkType = info.linkType;
|
|
320
361
|
}
|
|
321
362
|
return { linkType, target };
|
|
@@ -371,7 +412,13 @@ const populateNodeModulesTree = (pnp, hoistedTree, options) => {
|
|
|
371
412
|
const nodeModulesLocation = fslib_1.ppath.join(nodeModulesDirPath, ...packageNameParts);
|
|
372
413
|
const nodePath = `${parentNodePath}/${locator.name}`;
|
|
373
414
|
const leafNode = makeLeafNode(locator, parentNodePath, references.slice(1));
|
|
374
|
-
|
|
415
|
+
// We don't want to create self-referencing symlinks for anonymous workspaces
|
|
416
|
+
let isAnonymousWorkspace = false;
|
|
417
|
+
if (leafNode.linkType === LinkType.SOFT && options.project) {
|
|
418
|
+
const workspace = options.project.workspacesByCwd.get(leafNode.target.slice(0, -1));
|
|
419
|
+
isAnonymousWorkspace = !!(workspace && !workspace.manifest.name);
|
|
420
|
+
}
|
|
421
|
+
if (!dep.name.endsWith(WORKSPACE_NAME_SUFFIX) && !isAnonymousWorkspace) {
|
|
375
422
|
const prevNode = tree.get(nodeModulesLocation);
|
|
376
423
|
if (prevNode) {
|
|
377
424
|
if (prevNode.dirList) {
|
package/lib/hoist.d.ts
CHANGED
package/lib/hoist.js
CHANGED
|
@@ -134,7 +134,7 @@ const getUsedDependencies = (rootNodePath) => {
|
|
|
134
134
|
const decoupleGraphNode = (parent, node) => {
|
|
135
135
|
if (node.decoupled)
|
|
136
136
|
return node;
|
|
137
|
-
const { name, references, ident, locator, dependencies, originalDependencies, hoistedDependencies, peerNames, reasons, isHoistBorder, hoistPriority } = node;
|
|
137
|
+
const { name, references, ident, locator, dependencies, originalDependencies, hoistedDependencies, peerNames, reasons, isHoistBorder, hoistPriority, isWorkspace, hoistedFrom, hoistedTo } = node;
|
|
138
138
|
// To perform node hoisting from parent node we must clone parent nodes up to the root node,
|
|
139
139
|
// because some other package in the tree might depend on the parent package where hoisting
|
|
140
140
|
// cannot be performed
|
|
@@ -151,7 +151,9 @@ const decoupleGraphNode = (parent, node) => {
|
|
|
151
151
|
decoupled: true,
|
|
152
152
|
isHoistBorder,
|
|
153
153
|
hoistPriority,
|
|
154
|
-
|
|
154
|
+
isWorkspace,
|
|
155
|
+
hoistedFrom: new Map(hoistedFrom),
|
|
156
|
+
hoistedTo: new Map(hoistedTo),
|
|
155
157
|
};
|
|
156
158
|
const selfDep = clone.dependencies.get(name);
|
|
157
159
|
if (selfDep && selfDep.ident == clone.ident)
|
|
@@ -308,7 +310,7 @@ const hoistTo = (tree, rootNodePath, rootNodePathLocators, parentShadowedNodes,
|
|
|
308
310
|
}
|
|
309
311
|
return { anotherRoundNeeded, isGraphChanged };
|
|
310
312
|
};
|
|
311
|
-
const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDependencies, hoistIdents, hoistIdentMap, shadowedNodes, { outputReason }) => {
|
|
313
|
+
const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDependencies, hoistIdents, hoistIdentMap, shadowedNodes, { outputReason, fastLookupPossible }) => {
|
|
312
314
|
let reasonRoot;
|
|
313
315
|
let reason = null;
|
|
314
316
|
let dependsOn = new Set();
|
|
@@ -320,6 +322,29 @@ const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDe
|
|
|
320
322
|
let isHoistable = !isSelfReference;
|
|
321
323
|
if (outputReason && !isHoistable)
|
|
322
324
|
reason = `- self-reference`;
|
|
325
|
+
if (isHoistable) {
|
|
326
|
+
isHoistable = !node.isWorkspace;
|
|
327
|
+
if (outputReason && !isHoistable) {
|
|
328
|
+
reason = `- workspace`;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (isHoistable) {
|
|
332
|
+
// Direct workspace dependencies must be hoisted to any common ancestor workspace of all the
|
|
333
|
+
// graph paths that include the dependency, because otherwise running app with
|
|
334
|
+
// `--preserve-symlinks` will become broken (without this flag the Node.js will pick dependency
|
|
335
|
+
// from the ancestor on the file system and with this flag it will pick ancestor from the graph
|
|
336
|
+
// and if these ancestors are different, the behavious of the application will be different).
|
|
337
|
+
// Another problem, which is prevented - is a creation of multiple hoisting layouts
|
|
338
|
+
// for the same workspace, because different dependencies of the same workspace might be hoisted
|
|
339
|
+
// differently, depending on the recepient workspace.
|
|
340
|
+
// It is difficult to find all common ancestors, but there is one easy to find common ancestor -
|
|
341
|
+
// the root workspace, so, for now, we either hoist direct dependencies into the root workspace, or we keep them
|
|
342
|
+
// unhoisted, thus we are safe from various pathological cases with `--preserve-symlinks`
|
|
343
|
+
isHoistable = !parentNode.isWorkspace || parentNode.hoistedFrom.has(node.name) || rootNodePathLocators.size === 1;
|
|
344
|
+
if (outputReason && !isHoistable) {
|
|
345
|
+
reason = parentNode.reasons.get(node.name);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
323
348
|
if (isHoistable) {
|
|
324
349
|
isHoistable = !rootNode.peerNames.has(node.name);
|
|
325
350
|
if (outputReason && !isHoistable) {
|
|
@@ -388,6 +413,17 @@ const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDe
|
|
|
388
413
|
}
|
|
389
414
|
isHoistable = arePeerDepsSatisfied;
|
|
390
415
|
}
|
|
416
|
+
if (isHoistable && !fastLookupPossible) {
|
|
417
|
+
for (const origDep of node.hoistedDependencies.values()) {
|
|
418
|
+
const usedDep = usedDependencies.get(origDep.name);
|
|
419
|
+
if (!usedDep || origDep.ident !== usedDep.ident) {
|
|
420
|
+
isHoistable = false;
|
|
421
|
+
if (outputReason)
|
|
422
|
+
reason = `- previously hoisted dependency mismatch, needed: ${prettyPrintLocator(origDep.locator)}, available: ${prettyPrintLocator(usedDep === null || usedDep === void 0 ? void 0 : usedDep.locator)}`;
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
391
427
|
if (dependsOn !== null && dependsOn.size > 0) {
|
|
392
428
|
return { isHoistable: Hoistable.DEPENDS, dependsOn, reason };
|
|
393
429
|
}
|
|
@@ -416,7 +452,7 @@ const hoistGraph = (tree, rootNodePath, rootNodePathLocators, usedDependencies,
|
|
|
416
452
|
const dependantTree = new Map();
|
|
417
453
|
const hoistInfos = new Map();
|
|
418
454
|
for (const subDependency of getSortedRegularDependencies(parentNode)) {
|
|
419
|
-
const hoistInfo = getNodeHoistInfo(rootNode, rootNodePathLocators, [rootNode, ...nodePath, parentNode], subDependency, usedDependencies, hoistIdents, hoistIdentMap, shadowedNodes, { outputReason: options.debugLevel >= DebugLevel.REASONS });
|
|
455
|
+
const hoistInfo = getNodeHoistInfo(rootNode, rootNodePathLocators, [rootNode, ...nodePath, parentNode], subDependency, usedDependencies, hoistIdents, hoistIdentMap, shadowedNodes, { outputReason: options.debugLevel >= DebugLevel.REASONS, fastLookupPossible: options.fastLookupPossible });
|
|
420
456
|
hoistInfos.set(subDependency, hoistInfo);
|
|
421
457
|
if (hoistInfo.isHoistable === Hoistable.DEPENDS) {
|
|
422
458
|
for (const node of hoistInfo.dependsOn) {
|
|
@@ -449,25 +485,27 @@ const hoistGraph = (tree, rootNodePath, rootNodePathLocators, usedDependencies,
|
|
|
449
485
|
parentNode.hoistedDependencies.set(node.name, node);
|
|
450
486
|
parentNode.reasons.delete(node.name);
|
|
451
487
|
const hoistedNode = rootNode.dependencies.get(node.name);
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
488
|
+
if (options.debugLevel >= DebugLevel.REASONS) {
|
|
489
|
+
const hoistedFrom = Array.from(locatorPath).concat([parentNode.locator]).map(x => prettyPrintLocator(x)).join(`→`);
|
|
490
|
+
let hoistedFromArray = rootNode.hoistedFrom.get(node.name);
|
|
491
|
+
if (!hoistedFromArray) {
|
|
492
|
+
hoistedFromArray = [];
|
|
493
|
+
rootNode.hoistedFrom.set(node.name, hoistedFromArray);
|
|
494
|
+
}
|
|
495
|
+
hoistedFromArray.push(hoistedFrom);
|
|
496
|
+
parentNode.hoistedTo.set(node.name, Array.from(rootNodePath).map(x => prettyPrintLocator(x.locator)).join(`→`));
|
|
497
|
+
}
|
|
455
498
|
// Add hoisted node to root node, in case it is not already there
|
|
456
499
|
if (!hoistedNode) {
|
|
457
500
|
// Avoid adding other version of root node to itself
|
|
458
501
|
if (rootNode.ident !== node.ident) {
|
|
459
502
|
rootNode.dependencies.set(node.name, node);
|
|
460
|
-
if (options.debugLevel >= DebugLevel.REASONS)
|
|
461
|
-
node.hoistedFrom.push(hoistedFrom);
|
|
462
503
|
newNodes.add(node);
|
|
463
504
|
}
|
|
464
505
|
}
|
|
465
506
|
else {
|
|
466
507
|
for (const reference of node.references) {
|
|
467
508
|
hoistedNode.references.add(reference);
|
|
468
|
-
if (options.debugLevel >= DebugLevel.REASONS) {
|
|
469
|
-
hoistedNode.hoistedFrom.push(hoistedFrom);
|
|
470
|
-
}
|
|
471
509
|
}
|
|
472
510
|
}
|
|
473
511
|
}
|
|
@@ -512,7 +550,7 @@ const selfCheck = (tree) => {
|
|
|
512
550
|
const log = [];
|
|
513
551
|
const seenNodes = new Set();
|
|
514
552
|
const parents = new Set();
|
|
515
|
-
const checkNode = (node, parentDeps) => {
|
|
553
|
+
const checkNode = (node, parentDeps, parent) => {
|
|
516
554
|
if (seenNodes.has(node))
|
|
517
555
|
return;
|
|
518
556
|
seenNodes.add(node);
|
|
@@ -532,23 +570,28 @@ const selfCheck = (tree) => {
|
|
|
532
570
|
}
|
|
533
571
|
}
|
|
534
572
|
else {
|
|
573
|
+
const hoistedFrom = parent.hoistedFrom.get(node.name);
|
|
574
|
+
const originalHoistedTo = node.hoistedTo.get(origDep.name);
|
|
575
|
+
const prettyHoistedFrom = `${hoistedFrom ? ` hoisted from ${hoistedFrom.join(`, `)}` : ``}`;
|
|
576
|
+
const prettyOriginalHoistedTo = `${originalHoistedTo ? ` hoisted to ${originalHoistedTo}` : ``}`;
|
|
577
|
+
const prettyNodePath = `${prettyPrintTreePath()}${prettyHoistedFrom}`;
|
|
535
578
|
if (!dep) {
|
|
536
|
-
log.push(`${
|
|
579
|
+
log.push(`${prettyNodePath} - broken require promise: no required dependency ${origDep.name}${prettyOriginalHoistedTo} found`);
|
|
537
580
|
}
|
|
538
581
|
else if (dep.ident !== origDep.ident) {
|
|
539
|
-
log.push(`${
|
|
582
|
+
log.push(`${prettyNodePath} - broken require promise for ${origDep.name}${prettyOriginalHoistedTo}: expected ${origDep.ident}, but found: ${dep.ident}`);
|
|
540
583
|
}
|
|
541
584
|
}
|
|
542
585
|
}
|
|
543
586
|
parents.add(node);
|
|
544
587
|
for (const dep of node.dependencies.values()) {
|
|
545
588
|
if (!node.peerNames.has(dep.name)) {
|
|
546
|
-
checkNode(dep, dependencies);
|
|
589
|
+
checkNode(dep, dependencies, node);
|
|
547
590
|
}
|
|
548
591
|
}
|
|
549
592
|
parents.delete(node);
|
|
550
593
|
};
|
|
551
|
-
checkNode(tree, tree.dependencies);
|
|
594
|
+
checkNode(tree, tree.dependencies, tree);
|
|
552
595
|
return log.join(`\n`);
|
|
553
596
|
};
|
|
554
597
|
/**
|
|
@@ -571,14 +614,16 @@ const cloneTree = (tree, options) => {
|
|
|
571
614
|
decoupled: true,
|
|
572
615
|
isHoistBorder: true,
|
|
573
616
|
hoistPriority: 0,
|
|
574
|
-
|
|
617
|
+
isWorkspace: true,
|
|
618
|
+
hoistedFrom: new Map(),
|
|
619
|
+
hoistedTo: new Map(),
|
|
575
620
|
};
|
|
576
621
|
const seenNodes = new Map([[tree, treeCopy]]);
|
|
577
622
|
const addNode = (node, parentNode) => {
|
|
578
623
|
let workNode = seenNodes.get(node);
|
|
579
624
|
const isSeen = !!workNode;
|
|
580
625
|
if (!workNode) {
|
|
581
|
-
const { name, identName, reference, peerNames, hoistPriority } = node;
|
|
626
|
+
const { name, identName, reference, peerNames, hoistPriority, isWorkspace } = node;
|
|
582
627
|
const dependenciesNmHoistingLimits = options.hoistingLimits.get(parentNode.locator);
|
|
583
628
|
workNode = {
|
|
584
629
|
name,
|
|
@@ -593,7 +638,9 @@ const cloneTree = (tree, options) => {
|
|
|
593
638
|
decoupled: true,
|
|
594
639
|
isHoistBorder: dependenciesNmHoistingLimits ? dependenciesNmHoistingLimits.has(name) : false,
|
|
595
640
|
hoistPriority: hoistPriority || 0,
|
|
596
|
-
|
|
641
|
+
isWorkspace: isWorkspace || false,
|
|
642
|
+
hoistedFrom: new Map(),
|
|
643
|
+
hoistedTo: new Map(),
|
|
597
644
|
};
|
|
598
645
|
seenNodes.set(node, workNode);
|
|
599
646
|
}
|
|
@@ -713,6 +760,8 @@ const buildPreferenceMap = (rootNode) => {
|
|
|
713
760
|
return preferenceMap;
|
|
714
761
|
};
|
|
715
762
|
const prettyPrintLocator = (locator) => {
|
|
763
|
+
if (!locator)
|
|
764
|
+
return `none`;
|
|
716
765
|
const idx = locator.indexOf(`@`, 1);
|
|
717
766
|
let name = locator.substring(0, idx);
|
|
718
767
|
if (name.endsWith(`$wsroot$`))
|
|
@@ -760,7 +809,8 @@ const dumpDepTree = (tree) => {
|
|
|
760
809
|
if (!pkg.peerNames.has(dep.name) && dep !== pkg) {
|
|
761
810
|
const reason = pkg.reasons.get(dep.name);
|
|
762
811
|
const identName = getIdentName(dep.locator);
|
|
763
|
-
|
|
812
|
+
const hoistedFrom = pkg.hoistedFrom.get(dep.name) || [];
|
|
813
|
+
str += `${prefix}${idx < dependencies.length - 1 ? `├─` : `└─`}${(parents.has(dep) ? `>` : ``) + (identName !== dep.name ? `a:${dep.name}:` : ``) + prettyPrintLocator(dep.locator) + (reason ? ` ${reason}` : ``) + (dep !== pkg && hoistedFrom.length > 0 ? `, hoisted from: ${hoistedFrom.join(`, `)}` : ``)}\n`;
|
|
764
814
|
str += dumpPackage(dep, parents, `${prefix}${idx < dependencies.length - 1 ? `│ ` : ` `}`);
|
|
765
815
|
}
|
|
766
816
|
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yarnpkg/nm",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1-rc.1",
|
|
4
4
|
"license": "BSD-2-Clause",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"sideEffects": false,
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@yarnpkg/core": "^3.
|
|
10
|
-
"@yarnpkg/fslib": "^2.6.0
|
|
9
|
+
"@yarnpkg/core": "^3.2.0-rc.1",
|
|
10
|
+
"@yarnpkg/fslib": "^2.6.0"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@yarnpkg/pnp": "^3.1.
|
|
13
|
+
"@yarnpkg/pnp": "^3.1.1-rc.1"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"postpack": "rm -rf lib",
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=12 <14 || 14.2 - 14.9 || >14.10.0"
|
|
35
35
|
},
|
|
36
|
-
"stableVersion": "
|
|
36
|
+
"stableVersion": "3.0.0"
|
|
37
37
|
}
|