@pnpm/installing.linking.real-hoist 1100.1.20 → 1100.1.22

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/lib/index.js +138 -107
  3. package/package.json +7 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @pnpm/real-hoist
2
2
 
3
+ ## 1100.1.22
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies:
8
+ - @pnpm/deps.path@1101.0.6
9
+ - @pnpm/error@1100.2.2
10
+ - @pnpm/lockfile.utils@1102.1.6
11
+
12
+ ## 1100.1.21
13
+
14
+ ### Patch Changes
15
+
16
+ - `pnpm install` no longer fails when a package from the registry declares a `file:` dependency on a directory inside itself, such as `"@types/css-tree": "file:./typings/css-tree"`. pnpm links that dependency to the directory inside the package, as npm and Yarn do. The lockfile records it as `link:<root>/typings/css-tree` [#9141](https://github.com/pnpm/pnpm/issues/9141).
17
+
18
+ - Updated dependencies:
19
+ - @pnpm/deps.path@1101.0.5
20
+ - @pnpm/error@1100.2.1
21
+ - @pnpm/lockfile.types@1100.1.4
22
+ - @pnpm/lockfile.utils@1102.1.5
23
+
3
24
  ## 1100.1.20
4
25
 
5
26
  ### Patch Changes
package/lib/index.js CHANGED
@@ -53,137 +53,168 @@ export function getHoistingLimits(lockfile, mode) {
53
53
  const hoistingLimits = new Map();
54
54
  const rootHoistingLimit = new Set();
55
55
  for (const [importerId, importer] of Object.entries(lockfile.importers)) {
56
- const isWorkspaceRoot = importerId === '.';
57
- const encodedId = encodeURIComponent(importerId);
58
- if (!isWorkspaceRoot) {
59
- rootHoistingLimit.add(encodedId);
60
- if (mode !== 'dependencies') {
61
- // In `'workspaces'` mode it's enough to border each workspace
62
- // package at the root; their own direct deps don't need a
63
- // per-importer border.
64
- continue;
65
- }
66
- }
67
- const reference = isWorkspaceRoot ? '' : `workspace:${importerId}`;
68
- const hoistingLimit = isWorkspaceRoot ? rootHoistingLimit : new Set();
69
- hoistingLimits.set(`${encodedId}@${reference}`, hoistingLimit);
70
- for (const deps of [importer.dependencies, importer.devDependencies, importer.optionalDependencies]) {
71
- if (!deps)
72
- continue;
73
- for (const dep of Object.keys(deps)) {
74
- hoistingLimit.add(dep);
75
- }
76
- }
56
+ addImporterHoistingLimits({
57
+ hoistingLimits,
58
+ importer,
59
+ importerId,
60
+ mode,
61
+ rootHoistingLimit,
62
+ });
77
63
  }
78
64
  if (!hoistingLimits.has('.@')) {
79
65
  hoistingLimits.set('.@', rootHoistingLimit);
80
66
  }
81
67
  return hoistingLimits;
82
68
  }
69
+ function addImporterHoistingLimits(opts) {
70
+ const { hoistingLimits, importer, importerId, mode, rootHoistingLimit } = opts;
71
+ const isWorkspaceRoot = importerId === '.';
72
+ const encodedId = encodeURIComponent(importerId);
73
+ if (!isWorkspaceRoot) {
74
+ rootHoistingLimit.add(encodedId);
75
+ if (mode !== 'dependencies') {
76
+ return;
77
+ }
78
+ }
79
+ const reference = isWorkspaceRoot ? '' : `workspace:${importerId}`;
80
+ const hoistingLimit = isWorkspaceRoot ? rootHoistingLimit : new Set();
81
+ hoistingLimits.set(`${encodedId}@${reference}`, hoistingLimit);
82
+ collectDirectDeps(importer, hoistingLimit);
83
+ }
84
+ function collectDirectDeps(importer, targetSet) {
85
+ const depGroups = [importer.dependencies, importer.devDependencies, importer.optionalDependencies];
86
+ for (const deps of depGroups) {
87
+ if (!deps)
88
+ continue;
89
+ for (const dep of Object.keys(deps)) {
90
+ targetSet.add(dep);
91
+ }
92
+ }
93
+ }
83
94
  export function hoist(lockfile, opts) {
84
- const nodes = new Map();
85
95
  const ctx = {
86
96
  autoInstallPeers: opts?.autoInstallPeers,
87
- nodes,
88
- lockfile,
89
97
  depPathByPkgId: new Map(),
98
+ lockfile,
99
+ nodes: new Map(),
90
100
  };
91
- const _toTree = toTree.bind(null, ctx);
92
- const node = {
93
- name: '.',
94
- identName: '.',
95
- reference: '',
96
- peerNames: new Set([]),
97
- dependencyKind: HoisterDependencyKind.WORKSPACE,
98
- dependencies: _toTree({
99
- ...lockfile.importers['.']?.dependencies,
100
- ...lockfile.importers['.']?.devDependencies,
101
- ...lockfile.importers['.']?.optionalDependencies,
102
- ...(Array.from(opts?.externalDependencies ?? [])).reduce((acc, dep) => {
103
- // It doesn't matter what version spec is used here.
104
- // This dependency will be removed from the tree anyway.
105
- // It is only needed to prevent the hoister from hoisting deps with this name to the root of node_modules.
106
- acc[dep] = 'link:';
107
- return acc;
108
- }, {}),
109
- }),
110
- };
101
+ const rootNode = buildRootHoisterTree(lockfile, ctx, opts?.externalDependencies);
111
102
  for (const [importerId, importer] of Object.entries(lockfile.importers)) {
112
103
  if (importerId === '.')
113
104
  continue;
114
- const importerNode = {
115
- name: encodeURIComponent(importerId),
116
- identName: encodeURIComponent(importerId),
117
- reference: `workspace:${importerId}`,
118
- peerNames: new Set([]),
119
- dependencyKind: HoisterDependencyKind.WORKSPACE,
120
- dependencies: _toTree({
121
- ...importer.dependencies,
122
- ...importer.devDependencies,
123
- ...importer.optionalDependencies,
124
- }),
125
- };
126
- node.dependencies.add(importerNode);
105
+ rootNode.dependencies.add(buildImporterHoisterTree(importerId, importer, ctx));
127
106
  }
128
107
  const hoistingLimits = getHoistingLimits(lockfile, opts?.hoistingLimits);
129
- const hoisterResult = _hoist(node, { ...opts, hoistingLimits });
108
+ const hoisterResult = _hoist(rootNode, { ...opts, hoistingLimits });
130
109
  if (opts?.externalDependencies) {
131
- for (const hoistedDep of hoisterResult.dependencies.values()) {
132
- if (opts.externalDependencies.has(hoistedDep.name)) {
133
- hoisterResult.dependencies.delete(hoistedDep);
134
- }
135
- }
110
+ filterExternalDependencies(hoisterResult, opts.externalDependencies);
136
111
  }
137
112
  return hoisterResult;
138
113
  }
139
- function toTree({ nodes, lockfile, depPathByPkgId, autoInstallPeers }, deps) {
114
+ function buildRootHoisterTree(lockfile, ctx, externalDependencies) {
115
+ const rootImporter = lockfile.importers['.'];
116
+ const externalDepsMap = {};
117
+ for (const dep of externalDependencies ?? []) {
118
+ externalDepsMap[dep] = 'link:';
119
+ }
120
+ return {
121
+ dependencies: toTree(ctx, {
122
+ ...rootImporter?.dependencies,
123
+ ...rootImporter?.devDependencies,
124
+ ...rootImporter?.optionalDependencies,
125
+ ...externalDepsMap,
126
+ }),
127
+ dependencyKind: HoisterDependencyKind.WORKSPACE,
128
+ identName: '.',
129
+ name: '.',
130
+ peerNames: new Set([]),
131
+ reference: '',
132
+ };
133
+ }
134
+ function buildImporterHoisterTree(importerId, importer, ctx) {
135
+ return {
136
+ dependencies: toTree(ctx, {
137
+ ...importer.dependencies,
138
+ ...importer.devDependencies,
139
+ ...importer.optionalDependencies,
140
+ }),
141
+ dependencyKind: HoisterDependencyKind.WORKSPACE,
142
+ identName: encodeURIComponent(importerId),
143
+ name: encodeURIComponent(importerId),
144
+ peerNames: new Set([]),
145
+ reference: `workspace:${importerId}`,
146
+ };
147
+ }
148
+ function filterExternalDependencies(result, externalDependencies) {
149
+ for (const hoistedDep of result.dependencies.values()) {
150
+ if (externalDependencies.has(hoistedDep.name)) {
151
+ result.dependencies.delete(hoistedDep);
152
+ }
153
+ }
154
+ }
155
+ function toTree(ctx, deps) {
140
156
  return new Set(Object.entries(deps).map(([alias, ref]) => {
141
157
  const depPath = dp.refToRelative(ref, alias);
142
158
  if (!depPath) {
143
- const key = `${alias}:${ref}`;
144
- let node = nodes.get(key);
145
- if (!node) {
146
- node = {
147
- name: alias,
148
- identName: alias,
149
- reference: ref,
150
- dependencyKind: HoisterDependencyKind.REGULAR,
151
- dependencies: new Set(),
152
- peerNames: new Set(),
153
- };
154
- nodes.set(key, node);
155
- }
156
- return node;
157
- }
158
- const key = `${alias}:${depPath}`;
159
- let node = nodes.get(key);
160
- if (!node) {
161
- const pkgSnapshot = lockfile.packages[depPath];
162
- if (!pkgSnapshot) {
163
- throw new LockfileMissingDependencyError(depPath);
164
- }
165
- const { name: pkgName } = nameVerFromPkgSnapshot(depPath, pkgSnapshot);
166
- const id = getHoisterPkgId(depPath, pkgSnapshot);
167
- if (!depPathByPkgId.has(id)) {
168
- depPathByPkgId.set(id, depPath);
169
- }
170
- node = {
171
- name: alias,
172
- identName: pkgName,
173
- reference: depPathByPkgId.get(id),
174
- dependencyKind: HoisterDependencyKind.REGULAR,
175
- dependencies: new Set(),
176
- peerNames: new Set(autoInstallPeers
177
- ? []
178
- : [
179
- ...Object.keys(pkgSnapshot.peerDependencies ?? {}),
180
- ...(pkgSnapshot.transitivePeerDependencies ?? []),
181
- ]),
182
- };
183
- nodes.set(key, node);
184
- node.dependencies = toTree({ nodes, lockfile, depPathByPkgId, autoInstallPeers }, { ...pkgSnapshot.dependencies, ...pkgSnapshot.optionalDependencies });
159
+ return getOrCreateWorkspaceNode(ctx.nodes, alias, ref);
185
160
  }
186
- return node;
161
+ return getOrCreatePackageNode(ctx, alias, depPath);
187
162
  }));
188
163
  }
164
+ function getOrCreateWorkspaceNode(nodes, alias, ref) {
165
+ const key = `${alias}:${ref}`;
166
+ let node = nodes.get(key);
167
+ if (!node) {
168
+ node = {
169
+ dependencies: new Set(),
170
+ dependencyKind: dp.packageRootLinkTarget(ref) != null
171
+ ? HoisterDependencyKind.WORKSPACE
172
+ : HoisterDependencyKind.REGULAR,
173
+ identName: alias,
174
+ name: alias,
175
+ peerNames: new Set(),
176
+ reference: ref,
177
+ };
178
+ nodes.set(key, node);
179
+ }
180
+ return node;
181
+ }
182
+ function getOrCreatePackageNode(ctx, alias, depPath) {
183
+ const key = `${alias}:${depPath}`;
184
+ let node = ctx.nodes.get(key);
185
+ if (!node) {
186
+ const pkgSnapshot = ctx.lockfile.packages?.[depPath];
187
+ if (!pkgSnapshot) {
188
+ throw new LockfileMissingDependencyError(depPath);
189
+ }
190
+ const { name: pkgName } = nameVerFromPkgSnapshot(depPath, pkgSnapshot);
191
+ const id = getHoisterPkgId(depPath, pkgSnapshot);
192
+ if (!ctx.depPathByPkgId.has(id)) {
193
+ ctx.depPathByPkgId.set(id, depPath);
194
+ }
195
+ node = {
196
+ dependencies: new Set(),
197
+ dependencyKind: HoisterDependencyKind.REGULAR,
198
+ identName: pkgName,
199
+ name: alias,
200
+ peerNames: resolvePeerNames(pkgSnapshot, ctx.autoInstallPeers),
201
+ reference: ctx.depPathByPkgId.get(id),
202
+ };
203
+ ctx.nodes.set(key, node);
204
+ node.dependencies = toTree(ctx, {
205
+ ...pkgSnapshot.dependencies,
206
+ ...pkgSnapshot.optionalDependencies,
207
+ });
208
+ }
209
+ return node;
210
+ }
211
+ function resolvePeerNames(pkgSnapshot, autoInstallPeers) {
212
+ if (autoInstallPeers) {
213
+ return new Set();
214
+ }
215
+ return new Set([
216
+ ...Object.keys(pkgSnapshot.peerDependencies ?? {}),
217
+ ...(pkgSnapshot.transitivePeerDependencies ?? []),
218
+ ]);
219
+ }
189
220
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/installing.linking.real-hoist",
3
- "version": "1100.1.20",
3
+ "version": "1100.1.22",
4
4
  "description": "Hoists dependencies in a node_modules created by pnpm",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -27,16 +27,16 @@
27
27
  "!*.map"
28
28
  ],
29
29
  "dependencies": {
30
- "@pnpm/deps.path": "1101.0.4",
31
- "@pnpm/error": "1100.2.0",
32
- "@pnpm/lockfile.types": "1100.1.3",
33
- "@pnpm/lockfile.utils": "1102.1.4",
30
+ "@pnpm/deps.path": "1101.0.6",
31
+ "@pnpm/error": "1100.2.2",
32
+ "@pnpm/lockfile.types": "1100.1.4",
33
+ "@pnpm/lockfile.utils": "1102.1.6",
34
34
  "@yarnpkg/nm": "4.1.1"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@jest/globals": "30.4.1",
38
- "@pnpm/installing.linking.real-hoist": "1100.1.20",
39
- "@pnpm/lockfile.fs": "1100.2.9",
38
+ "@pnpm/installing.linking.real-hoist": "1100.1.22",
39
+ "@pnpm/lockfile.fs": "1100.2.13",
40
40
  "@pnpm/test-fixtures": "1100.0.1",
41
41
  "@pnpm/types": "1102.1.1"
42
42
  },