@yarnpkg/nm 3.0.1-rc.9 → 4.0.0-rc.2

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.
@@ -202,7 +202,7 @@ const buildPackageTree = (pnp, options) => {
202
202
  reference: topLocator.reference,
203
203
  peerNames: topPkg.packagePeers,
204
204
  dependencies: new Set(),
205
- isWorkspace: true,
205
+ dependencyKind: hoist_1.HoisterDependencyKind.WORKSPACE,
206
206
  };
207
207
  const nodes = new Map();
208
208
  const getNodeKey = (name, locator) => `${stringifyLocator(locator)}:${name}`;
@@ -217,7 +217,11 @@ const buildPackageTree = (pnp, options) => {
217
217
  }
218
218
  const isExternalSoftLinkPackage = isExternalSoftLink(pkg, locator, pnp, topPkgPortableLocation);
219
219
  if (!node) {
220
- const isWorkspace = pkg.linkType === LinkType.SOFT && locator.name.endsWith(WORKSPACE_NAME_SUFFIX);
220
+ let dependencyKind = hoist_1.HoisterDependencyKind.REGULAR;
221
+ if (isExternalSoftLinkPackage)
222
+ dependencyKind = hoist_1.HoisterDependencyKind.EXTERNAL_SOFT_LINK;
223
+ else if (pkg.linkType === LinkType.SOFT && locator.name.endsWith(WORKSPACE_NAME_SUFFIX))
224
+ dependencyKind = hoist_1.HoisterDependencyKind.WORKSPACE;
221
225
  node = {
222
226
  name,
223
227
  identName: locator.name,
@@ -225,8 +229,8 @@ const buildPackageTree = (pnp, options) => {
225
229
  dependencies: new Set(),
226
230
  // View peer dependencies as regular dependencies for workspaces
227
231
  // (meeting workspace peer dependency constraints is sometimes hard, sometimes impossible for the nm linker)
228
- peerNames: isWorkspace ? new Set() : pkg.packagePeers,
229
- isWorkspace,
232
+ peerNames: dependencyKind === hoist_1.HoisterDependencyKind.WORKSPACE ? new Set() : pkg.packagePeers,
233
+ dependencyKind,
230
234
  };
231
235
  nodes.set(nodeKey, node);
232
236
  }
@@ -269,7 +273,7 @@ const buildPackageTree = (pnp, options) => {
269
273
  allDependencies.set(`${workspaceLocator.name}${WORKSPACE_NAME_SUFFIX}`, workspaceLocator.reference);
270
274
  }
271
275
  }
272
- if (pkg !== parentPkg || pkg.linkType !== LinkType.SOFT || !options.selfReferencesByCwd || options.selfReferencesByCwd.get(parentRelativeCwd))
276
+ if (pkg !== parentPkg || pkg.linkType !== LinkType.SOFT || (!isExternalSoftLinkPackage && (!options.selfReferencesByCwd || options.selfReferencesByCwd.get(parentRelativeCwd))))
273
277
  parent.dependencies.add(node);
274
278
  const isWorkspaceDependency = locator !== topLocator && pkg.linkType === LinkType.SOFT && !locator.name.endsWith(WORKSPACE_NAME_SUFFIX) && !isExternalSoftLinkPackage;
275
279
  if (!isSeen && !isWorkspaceDependency) {
@@ -352,22 +356,14 @@ function getTargetLocatorPath(locator, pnp, options) {
352
356
  const info = pnp.getPackageInformation(pkgLocator);
353
357
  if (info === null)
354
358
  throw new Error(`Assertion failed: Expected the package to be registered`);
355
- let linkType;
356
- let target;
357
- if (options.pnpifyFs) {
359
+ return options.pnpifyFs
358
360
  // In case of pnpifyFs we represent modules as symlinks to archives in NodeModulesFS
359
361
  // `/home/user/project/foo` is a symlink to `/home/user/project/.yarn/.cache/foo.zip/node_modules/foo`
360
362
  // To make this fs layout work with legacy tools we make
361
363
  // `/home/user/project/.yarn/.cache/foo.zip/node_modules/foo/node_modules` (which normally does not exist inside archive) a symlink to:
362
364
  // `/home/user/project/node_modules/foo/node_modules`, so that the tools were able to access it
363
- target = fslib_1.npath.toPortablePath(info.packageLocation);
364
- linkType = LinkType.SOFT;
365
- }
366
- else {
367
- target = getRealPackageLocation(info, locator, pnp);
368
- linkType = info.linkType;
369
- }
370
- return { linkType, target };
365
+ ? { linkType: LinkType.SOFT, target: fslib_1.npath.toPortablePath(info.packageLocation) }
366
+ : { linkType: info.linkType, target: getRealPackageLocation(info, locator, pnp) };
371
367
  }
372
368
  /**
373
369
  * Converts hoisted tree to node modules map
@@ -445,8 +441,7 @@ const populateNodeModulesTree = (pnp, hoistedTree, options) => {
445
441
  tree.set(nodeModulesLocation, leafNode);
446
442
  const segments = nodeModulesLocation.split(`/`);
447
443
  const nodeModulesIdx = segments.indexOf(NODE_MODULES);
448
- let segCount = segments.length - 1;
449
- while (nodeModulesIdx >= 0 && segCount > nodeModulesIdx) {
444
+ for (let segCount = segments.length - 1; nodeModulesIdx >= 0 && segCount > nodeModulesIdx; segCount--) {
450
445
  const dirPath = fslib_1.npath.toPortablePath(segments.slice(0, segCount).join(fslib_1.ppath.sep));
451
446
  const targetDir = (0, fslib_1.toFilename)(segments[segCount]);
452
447
  const subdirs = tree.get(dirPath);
@@ -461,7 +456,6 @@ const populateNodeModulesTree = (pnp, hoistedTree, options) => {
461
456
  subdirs.dirList.add(targetDir);
462
457
  }
463
458
  }
464
- segCount--;
465
459
  }
466
460
  }
467
461
  buildTree(dep, leafNode.linkType === LinkType.SOFT ? leafNode.target : nodeModulesLocation, nodePath);
package/lib/hoist.d.ts CHANGED
@@ -46,6 +46,11 @@
46
46
  * until you run out of candidates for current tree root.
47
47
  */
48
48
  declare type PackageName = string;
49
+ export declare enum HoisterDependencyKind {
50
+ REGULAR = 0,
51
+ WORKSPACE = 1,
52
+ EXTERNAL_SOFT_LINK = 2
53
+ }
49
54
  export declare type HoisterTree = {
50
55
  name: PackageName;
51
56
  identName: PackageName;
@@ -53,7 +58,7 @@ export declare type HoisterTree = {
53
58
  dependencies: Set<HoisterTree>;
54
59
  peerNames: Set<PackageName>;
55
60
  hoistPriority?: number;
56
- isWorkspace?: boolean;
61
+ dependencyKind?: HoisterDependencyKind;
57
62
  };
58
63
  export declare type HoisterResult = {
59
64
  name: PackageName;
package/lib/hoist.js CHANGED
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hoist = void 0;
3
+ exports.hoist = exports.HoisterDependencyKind = void 0;
4
+ var HoisterDependencyKind;
5
+ (function (HoisterDependencyKind) {
6
+ HoisterDependencyKind[HoisterDependencyKind["REGULAR"] = 0] = "REGULAR";
7
+ HoisterDependencyKind[HoisterDependencyKind["WORKSPACE"] = 1] = "WORKSPACE";
8
+ HoisterDependencyKind[HoisterDependencyKind["EXTERNAL_SOFT_LINK"] = 2] = "EXTERNAL_SOFT_LINK";
9
+ })(HoisterDependencyKind = exports.HoisterDependencyKind || (exports.HoisterDependencyKind = {}));
4
10
  var Hoistable;
5
11
  (function (Hoistable) {
6
12
  Hoistable[Hoistable["YES"] = 0] = "YES";
@@ -134,7 +140,7 @@ const getUsedDependencies = (rootNodePath) => {
134
140
  const decoupleGraphNode = (parent, node) => {
135
141
  if (node.decoupled)
136
142
  return node;
137
- const { name, references, ident, locator, dependencies, originalDependencies, hoistedDependencies, peerNames, reasons, isHoistBorder, hoistPriority, isWorkspace, hoistedFrom, hoistedTo } = node;
143
+ const { name, references, ident, locator, dependencies, originalDependencies, hoistedDependencies, peerNames, reasons, isHoistBorder, hoistPriority, dependencyKind, hoistedFrom, hoistedTo } = node;
138
144
  // To perform node hoisting from parent node we must clone parent nodes up to the root node,
139
145
  // because some other package in the tree might depend on the parent package where hoisting
140
146
  // cannot be performed
@@ -151,7 +157,7 @@ const decoupleGraphNode = (parent, node) => {
151
157
  decoupled: true,
152
158
  isHoistBorder,
153
159
  hoistPriority,
154
- isWorkspace,
160
+ dependencyKind,
155
161
  hoistedFrom: new Map(hoistedFrom),
156
162
  hoistedTo: new Map(hoistedTo),
157
163
  };
@@ -275,7 +281,10 @@ const hoistTo = (tree, rootNodePath, rootNodePathLocators, parentShadowedNodes,
275
281
  seenNodes.add(rootNode);
276
282
  const preferenceMap = buildPreferenceMap(rootNode);
277
283
  const hoistIdentMap = getHoistIdentMap(rootNode, preferenceMap);
278
- const usedDependencies = tree == rootNode ? new Map() : (options.fastLookupPossible ? getZeroRoundUsedDependencies(rootNodePath) : getUsedDependencies(rootNodePath));
284
+ const usedDependencies = tree == rootNode ? new Map() :
285
+ (options.fastLookupPossible
286
+ ? getZeroRoundUsedDependencies(rootNodePath)
287
+ : getUsedDependencies(rootNodePath));
279
288
  let wasStateChanged;
280
289
  let anotherRoundNeeded = false;
281
290
  let isGraphChanged = false;
@@ -310,6 +319,14 @@ const hoistTo = (tree, rootNodePath, rootNodePathLocators, parentShadowedNodes,
310
319
  }
311
320
  return { anotherRoundNeeded, isGraphChanged };
312
321
  };
322
+ const hasUnhoistedDependencies = (node) => {
323
+ for (const [subName, subDependency] of node.dependencies) {
324
+ if (!node.peerNames.has(subName) && subDependency.ident !== node.ident) {
325
+ return true;
326
+ }
327
+ }
328
+ return false;
329
+ };
313
330
  const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDependencies, hoistIdents, hoistIdentMap, shadowedNodes, { outputReason, fastLookupPossible }) => {
314
331
  let reasonRoot;
315
332
  let reason = null;
@@ -323,11 +340,17 @@ const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDe
323
340
  if (outputReason && !isHoistable)
324
341
  reason = `- self-reference`;
325
342
  if (isHoistable) {
326
- isHoistable = !node.isWorkspace;
343
+ isHoistable = node.dependencyKind !== HoisterDependencyKind.WORKSPACE;
327
344
  if (outputReason && !isHoistable) {
328
345
  reason = `- workspace`;
329
346
  }
330
347
  }
348
+ if (isHoistable && node.dependencyKind === HoisterDependencyKind.EXTERNAL_SOFT_LINK) {
349
+ isHoistable = !hasUnhoistedDependencies(node);
350
+ if (outputReason && !isHoistable) {
351
+ reason = `- external soft link with unhoisted dependencies`;
352
+ }
353
+ }
331
354
  if (isHoistable) {
332
355
  // Direct workspace dependencies must be hoisted to any common ancestor workspace of all the
333
356
  // graph paths that include the dependency, because otherwise running app with
@@ -340,7 +363,7 @@ const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDe
340
363
  // It is difficult to find all common ancestors, but there is one easy to find common ancestor -
341
364
  // the root workspace, so, for now, we either hoist direct dependencies into the root workspace, or we keep them
342
365
  // unhoisted, thus we are safe from various pathological cases with `--preserve-symlinks`
343
- isHoistable = !parentNode.isWorkspace || parentNode.hoistedFrom.has(node.name) || rootNodePathLocators.size === 1;
366
+ isHoistable = parentNode.dependencyKind !== HoisterDependencyKind.WORKSPACE || parentNode.hoistedFrom.has(node.name) || rootNodePathLocators.size === 1;
344
367
  if (outputReason && !isHoistable) {
345
368
  reason = parentNode.reasons.get(node.name);
346
369
  }
@@ -415,7 +438,7 @@ const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDe
415
438
  }
416
439
  if (isHoistable && !fastLookupPossible) {
417
440
  for (const origDep of node.hoistedDependencies.values()) {
418
- const usedDep = usedDependencies.get(origDep.name);
441
+ const usedDep = usedDependencies.get(origDep.name) || rootNode.dependencies.get(origDep.name);
419
442
  if (!usedDep || origDep.ident !== usedDep.ident) {
420
443
  isHoistable = false;
421
444
  if (outputReason)
@@ -431,6 +454,7 @@ const getNodeHoistInfo = (rootNode, rootNodePathLocators, nodePath, node, usedDe
431
454
  return { isHoistable: isHoistable ? Hoistable.YES : Hoistable.NO, reason };
432
455
  }
433
456
  };
457
+ const getAliasedLocator = (node) => `${node.name}@${node.locator}`;
434
458
  /**
435
459
  * Performs actual graph transformation, by hoisting packages to the root node.
436
460
  *
@@ -445,10 +469,11 @@ const hoistGraph = (tree, rootNodePath, rootNodePathLocators, usedDependencies,
445
469
  const seenNodes = new Set();
446
470
  let anotherRoundNeeded = false;
447
471
  let isGraphChanged = false;
448
- const hoistNodeDependencies = (nodePath, locatorPath, parentNode, newNodes) => {
472
+ const hoistNodeDependencies = (nodePath, locatorPath, aliasedLocatorPath, parentNode, newNodes) => {
449
473
  if (seenNodes.has(parentNode))
450
474
  return;
451
- const nextLocatorPath = [...locatorPath, parentNode.locator];
475
+ const nextLocatorPath = [...locatorPath, getAliasedLocator(parentNode)];
476
+ const nextAliasedLocatorPath = [...aliasedLocatorPath, getAliasedLocator(parentNode)];
452
477
  const dependantTree = new Map();
453
478
  const hoistInfos = new Map();
454
479
  for (const subDependency of getSortedRegularDependencies(parentNode)) {
@@ -475,12 +500,14 @@ const hoistGraph = (tree, rootNodePath, rootNodePathLocators, usedDependencies,
475
500
  for (const [node, hoistInfo] of hoistInfos)
476
501
  if (hoistInfo.isHoistable === Hoistable.NO)
477
502
  addUnhoistableNode(node, hoistInfo, hoistInfo.reason);
503
+ let wereNodesHoisted = false;
478
504
  for (const node of hoistInfos.keys()) {
479
505
  if (!unhoistableNodes.has(node)) {
480
506
  isGraphChanged = true;
481
507
  const shadowedNames = parentShadowedNodes.get(parentNode);
482
508
  if (shadowedNames && shadowedNames.has(node.name))
483
509
  anotherRoundNeeded = true;
510
+ wereNodesHoisted = true;
484
511
  parentNode.dependencies.delete(node.name);
485
512
  parentNode.hoistedDependencies.set(node.name, node);
486
513
  parentNode.reasons.delete(node.name);
@@ -510,6 +537,8 @@ const hoistGraph = (tree, rootNodePath, rootNodePathLocators, usedDependencies,
510
537
  }
511
538
  }
512
539
  }
540
+ if (parentNode.dependencyKind === HoisterDependencyKind.EXTERNAL_SOFT_LINK && wereNodesHoisted)
541
+ anotherRoundNeeded = true;
513
542
  if (options.check) {
514
543
  const checkLog = selfCheck(tree);
515
544
  if (checkLog) {
@@ -523,10 +552,10 @@ const hoistGraph = (tree, rootNodePath, rootNodePathLocators, usedDependencies,
523
552
  const hoistableIdent = hoistIdents.get(node.name);
524
553
  if ((hoistableIdent === node.ident || !parentNode.reasons.has(node.name)) && hoistInfo.isHoistable !== Hoistable.YES)
525
554
  parentNode.reasons.set(node.name, hoistInfo.reason);
526
- if (!node.isHoistBorder && nextLocatorPath.indexOf(node.locator) < 0) {
555
+ if (!node.isHoistBorder && nextAliasedLocatorPath.indexOf(getAliasedLocator(node)) < 0) {
527
556
  seenNodes.add(parentNode);
528
557
  const decoupledNode = decoupleGraphNode(parentNode, node);
529
- hoistNodeDependencies([...nodePath, parentNode], [...locatorPath, parentNode.locator], decoupledNode, nextNewNodes);
558
+ hoistNodeDependencies([...nodePath, parentNode], nextLocatorPath, nextAliasedLocatorPath, decoupledNode, nextNewNodes);
530
559
  seenNodes.delete(parentNode);
531
560
  }
532
561
  }
@@ -534,6 +563,7 @@ const hoistGraph = (tree, rootNodePath, rootNodePathLocators, usedDependencies,
534
563
  };
535
564
  let newNodes;
536
565
  let nextNewNodes = new Set(getSortedRegularDependencies(rootNode));
566
+ const aliasedRootNodePathLocators = Array.from(rootNodePath).map(x => getAliasedLocator(x));
537
567
  do {
538
568
  newNodes = nextNewNodes;
539
569
  nextNewNodes = new Set();
@@ -541,7 +571,7 @@ const hoistGraph = (tree, rootNodePath, rootNodePathLocators, usedDependencies,
541
571
  if (dep.locator === rootNode.locator || dep.isHoistBorder)
542
572
  continue;
543
573
  const decoupledDependency = decoupleGraphNode(rootNode, dep);
544
- hoistNodeDependencies([], Array.from(rootNodePathLocators), decoupledDependency, nextNewNodes);
574
+ hoistNodeDependencies([], Array.from(rootNodePathLocators), aliasedRootNodePathLocators, decoupledDependency, nextNewNodes);
545
575
  }
546
576
  } while (nextNewNodes.size > 0);
547
577
  return { anotherRoundNeeded, isGraphChanged };
@@ -614,7 +644,7 @@ const cloneTree = (tree, options) => {
614
644
  decoupled: true,
615
645
  isHoistBorder: true,
616
646
  hoistPriority: 0,
617
- isWorkspace: true,
647
+ dependencyKind: HoisterDependencyKind.WORKSPACE,
618
648
  hoistedFrom: new Map(),
619
649
  hoistedTo: new Map(),
620
650
  };
@@ -623,7 +653,7 @@ const cloneTree = (tree, options) => {
623
653
  let workNode = seenNodes.get(node);
624
654
  const isSeen = !!workNode;
625
655
  if (!workNode) {
626
- const { name, identName, reference, peerNames, hoistPriority, isWorkspace } = node;
656
+ const { name, identName, reference, peerNames, hoistPriority, dependencyKind } = node;
627
657
  const dependenciesNmHoistingLimits = options.hoistingLimits.get(parentNode.locator);
628
658
  workNode = {
629
659
  name,
@@ -638,7 +668,7 @@ const cloneTree = (tree, options) => {
638
668
  decoupled: true,
639
669
  isHoistBorder: dependenciesNmHoistingLimits ? dependenciesNmHoistingLimits.has(name) : false,
640
670
  hoistPriority: hoistPriority || 0,
641
- isWorkspace: isWorkspace || false,
671
+ dependencyKind: dependencyKind || HoisterDependencyKind.REGULAR,
642
672
  hoistedFrom: new Map(),
643
673
  hoistedTo: new Map(),
644
674
  };
@@ -816,8 +846,7 @@ const dumpDepTree = (tree) => {
816
846
  if (!pkg.peerNames.has(dep.name) && dep !== pkg) {
817
847
  const reason = pkg.reasons.get(dep.name);
818
848
  const identName = getIdentName(dep.locator);
819
- const hoistedFrom = pkg.hoistedFrom.get(dep.name) || [];
820
- 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`;
849
+ str += `${prefix}${idx < dependencies.length - 1 ? `├─` : `└─`}${(parents.has(dep) ? `>` : ``) + (identName !== dep.name ? `a:${dep.name}:` : ``) + prettyPrintLocator(dep.locator) + (reason ? ` ${reason}` : ``)}\n`;
821
850
  str += dumpPackage(dep, parents, `${prefix}${idx < dependencies.length - 1 ? `│ ` : ` `}`);
822
851
  }
823
852
  }
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@yarnpkg/nm",
3
- "version": "3.0.1-rc.9",
3
+ "version": "4.0.0-rc.2",
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.2.0-rc.9",
10
- "@yarnpkg/fslib": "^2.6.1-rc.4"
9
+ "@yarnpkg/core": "^4.0.0-rc.2",
10
+ "@yarnpkg/fslib": "^3.0.0-rc.2"
11
11
  },
12
12
  "devDependencies": {
13
- "@yarnpkg/pnp": "^3.1.1-rc.9"
13
+ "@yarnpkg/pnp": "^4.0.0-rc.2"
14
14
  },
15
15
  "scripts": {
16
16
  "postpack": "rm -rf lib",
@@ -31,7 +31,7 @@
31
31
  "directory": "packages/yarnpkg-nm"
32
32
  },
33
33
  "engines": {
34
- "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0"
34
+ "node": ">=14.15.0"
35
35
  },
36
- "stableVersion": "3.0.0"
36
+ "stableVersion": "3.0.1"
37
37
  }