@yarnpkg/plugin-pnpm 2.1.2 → 2.3.0

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.
@@ -2,10 +2,11 @@ import { Descriptor, FetchResult, Installer, InstallPackageExtraApi, Linker, Lin
2
2
  import { PortablePath } from '@yarnpkg/fslib';
3
3
  export type PnpmCustomData = {
4
4
  locatorByPath: Map<PortablePath, string>;
5
- pathsByLocator: Map<LocatorHash, {
6
- packageLocation: PortablePath;
7
- dependenciesLocation: PortablePath | null;
8
- }>;
5
+ pathsByLocator: Map<LocatorHash, PnpmPackagePaths>;
6
+ };
7
+ export type PnpmPackagePaths = {
8
+ packageLocation: PortablePath;
9
+ dependenciesLocation: PortablePath | null;
9
10
  };
10
11
  export declare class PnpmLinker implements Linker {
11
12
  getCustomDataKey(): string;
@@ -21,7 +22,10 @@ declare class PnpmInstaller implements Installer {
21
22
  private readonly indexFolderPromise;
22
23
  constructor(opts: LinkOptions);
23
24
  private customData;
25
+ private packageMapNodesByLocator;
24
26
  attachCustomData(customData: any): void;
27
+ private registerPackageMapNode;
28
+ private registerPackageMapDependency;
25
29
  installPackage(pkg: Package, fetchResult: FetchResult, api: InstallPackageExtraApi): Promise<{
26
30
  packageLocation: PortablePath;
27
31
  buildRequest: import("@yarnpkg/core").BuildRequest | null;
package/lib/PnpmLinker.js CHANGED
@@ -5,6 +5,7 @@ const core_1 = require("@yarnpkg/core");
5
5
  const fslib_1 = require("@yarnpkg/fslib");
6
6
  const plugin_pnp_1 = require("@yarnpkg/plugin-pnp");
7
7
  const clipanion_1 = require("clipanion");
8
+ const PACKAGE_MAP_FILE = `.package-map.json`;
8
9
  class PnpmLinker {
9
10
  getCustomDataKey() {
10
11
  return JSON.stringify({
@@ -64,11 +65,12 @@ exports.PnpmLinker = PnpmLinker;
64
65
  class PnpmInstaller {
65
66
  constructor(opts) {
66
67
  this.opts = opts;
67
- this.asyncActions = new core_1.miscUtils.AsyncActions(10);
68
68
  this.customData = {
69
69
  pathsByLocator: new Map(),
70
70
  locatorByPath: new Map(),
71
71
  };
72
+ this.packageMapNodesByLocator = new Map();
73
+ this.asyncActions = new core_1.miscUtils.AsyncActions(opts.project.configuration.get(`pnpmInstallConcurrency`));
72
74
  this.indexFolderPromise = (0, fslib_1.setupCopyIndex)(fslib_1.xfs, {
73
75
  indexPath: fslib_1.ppath.join(opts.project.configuration.get(`globalFolder`), `index`),
74
76
  });
@@ -77,6 +79,20 @@ class PnpmInstaller {
77
79
  // We don't want to attach the data because it's only used in the Linker and we'll recompute it anyways in the Installer,
78
80
  // it needs to be invalidated because otherwise we'll never prune the store or we might run into various issues.
79
81
  }
82
+ registerPackageMapNode(locatorHash, { packageLocation }) {
83
+ const normalizedPackageLocation = stripTrailingSeparators(packageLocation);
84
+ if (!this.packageMapNodesByLocator.has(locatorHash)) {
85
+ this.packageMapNodesByLocator.set(locatorHash, {
86
+ packageLocation: normalizedPackageLocation,
87
+ dependencies: new Map(),
88
+ });
89
+ }
90
+ }
91
+ registerPackageMapDependency(packageMapNode, dependencyName, dependency) {
92
+ if (!this.packageMapNodesByLocator.has(dependency.locatorHash))
93
+ throw new Error(`Assertion failed: Expected the package to have been registered (${core_1.structUtils.stringifyLocator(dependency)})`);
94
+ packageMapNode.dependencies.set(dependencyName, dependency.locatorHash);
95
+ }
80
96
  async installPackage(pkg, fetchResult, api) {
81
97
  switch (pkg.linkType) {
82
98
  case core_1.LinkType.SOFT: return this.installPackageSoft(pkg, fetchResult, api);
@@ -89,10 +105,12 @@ class PnpmInstaller {
89
105
  const dependenciesLocation = this.opts.project.tryWorkspaceByLocator(pkg)
90
106
  ? fslib_1.ppath.join(packageLocation, fslib_1.Filename.nodeModules)
91
107
  : null;
92
- this.customData.pathsByLocator.set(pkg.locatorHash, {
108
+ const packagePaths = {
93
109
  packageLocation,
94
110
  dependenciesLocation,
95
- });
111
+ };
112
+ this.customData.pathsByLocator.set(pkg.locatorHash, packagePaths);
113
+ this.registerPackageMapNode(pkg.locatorHash, packagePaths);
96
114
  return {
97
115
  packageLocation,
98
116
  buildRequest: null,
@@ -103,6 +121,7 @@ class PnpmInstaller {
103
121
  const packageLocation = packagePaths.packageLocation;
104
122
  this.customData.locatorByPath.set(packageLocation, core_1.structUtils.stringifyLocator(pkg));
105
123
  this.customData.pathsByLocator.set(pkg.locatorHash, packagePaths);
124
+ this.registerPackageMapNode(pkg.locatorHash, packagePaths);
106
125
  api.holdFetchResult(this.asyncActions.set(pkg.locatorHash, async () => {
107
126
  await fslib_1.xfs.mkdirPromise(packageLocation, { recursive: true });
108
127
  // Copy the package source into the <root>/n_m/.store/<hash> directory, so
@@ -144,6 +163,9 @@ class PnpmInstaller {
144
163
  const { dependenciesLocation, } = packagePaths;
145
164
  if (!dependenciesLocation)
146
165
  return;
166
+ const packageMapNode = this.packageMapNodesByLocator.get(locator.locatorHash);
167
+ if (typeof packageMapNode === `undefined`)
168
+ throw new Error(`Assertion failed: Expected the package to have been registered (${core_1.structUtils.stringifyLocator(locator)})`);
147
169
  this.asyncActions.reduce(locator.locatorHash, async (action) => {
148
170
  await fslib_1.xfs.mkdirPromise(dependenciesLocation, { recursive: true });
149
171
  // Retrieve what's currently inside the package's true nm folder. We
@@ -163,6 +185,7 @@ class PnpmInstaller {
163
185
  if (typeof depSrcPaths === `undefined`)
164
186
  throw new Error(`Assertion failed: Expected the package to have been registered (${core_1.structUtils.stringifyLocator(dependency)})`);
165
187
  const name = core_1.structUtils.stringifyIdent(descriptor);
188
+ this.registerPackageMapDependency(packageMapNode, name, targetDependency);
166
189
  const depDstPath = fslib_1.ppath.join(dependenciesLocation, name);
167
190
  const depLinkPath = fslib_1.ppath.relative(fslib_1.ppath.dirname(depDstPath), depSrcPaths.packageLocation);
168
191
  const existing = extraneous.get(name);
@@ -227,8 +250,23 @@ class PnpmInstaller {
227
250
  await fslib_1.xfs.removePromise(fslib_1.ppath.join(storeLocation, extraneousEntry));
228
251
  }));
229
252
  }
230
- // Wait for the package installs to catch up
231
253
  await this.asyncActions.wait();
254
+ const nodeLinker = this.opts.project.configuration.get(`nodeLinker`);
255
+ if (nodeLinker === `pnpm`) {
256
+ const packageMap = buildPackageMap({
257
+ basePath: getNodeModulesLocation(this.opts.project),
258
+ packageMapNodesByLocator: this.packageMapNodesByLocator,
259
+ topLevelLocatorHash: this.opts.project.topLevelWorkspace.anchoredLocator.locatorHash,
260
+ type: this.opts.project.configuration.get(`nodePackageMapType`),
261
+ });
262
+ await fslib_1.xfs.mkdirPromise(getNodeModulesLocation(this.opts.project), { recursive: true });
263
+ await fslib_1.xfs.changeFilePromise(fslib_1.ppath.join(getNodeModulesLocation(this.opts.project), PACKAGE_MAP_FILE), JSON.stringify(packageMap, null, 2), {
264
+ automaticNewlines: true,
265
+ });
266
+ }
267
+ else if (nodeLinker !== `node-modules`) {
268
+ await fslib_1.xfs.removePromise(fslib_1.ppath.join(getNodeModulesLocation(this.opts.project), PACKAGE_MAP_FILE));
269
+ }
232
270
  await removeIfEmpty(storeLocation);
233
271
  if (this.opts.project.configuration.get(`nodeLinker`) !== `node-modules`)
234
272
  await removeIfEmpty(getNodeModulesLocation(this.opts.project));
@@ -250,6 +288,55 @@ function getPackagePaths(locator, { project }) {
250
288
  const dependenciesLocation = fslib_1.ppath.join(storeLocation, pkgKey, fslib_1.Filename.nodeModules);
251
289
  return { packageLocation, dependenciesLocation };
252
290
  }
291
+ function stripTrailingSeparators(path) {
292
+ while (path !== fslib_1.PortablePath.root && path.endsWith(fslib_1.ppath.sep))
293
+ path = path.slice(0, -1);
294
+ return path;
295
+ }
296
+ function getRelativeUrl(from, to) {
297
+ let relativePath = fslib_1.ppath.relative(from, to) || fslib_1.PortablePath.dot;
298
+ if (!relativePath.startsWith(`.`))
299
+ relativePath = `./${relativePath}`;
300
+ return relativePath;
301
+ }
302
+ function getPackageId(basePath, location) {
303
+ const relativePath = fslib_1.ppath.relative(basePath, location) || fslib_1.PortablePath.dot;
304
+ return relativePath === `..` ? fslib_1.PortablePath.dot : relativePath;
305
+ }
306
+ function compareStrings(a, b) {
307
+ return a < b ? -1 : a > b ? 1 : 0;
308
+ }
309
+ function buildPackageMap({ basePath, packageMapNodesByLocator, topLevelLocatorHash, type }) {
310
+ basePath = stripTrailingSeparators(basePath);
311
+ const topLevelPackageMapNode = packageMapNodesByLocator.get(topLevelLocatorHash);
312
+ if (typeof topLevelPackageMapNode === `undefined`)
313
+ throw new Error(`Assertion failed: Expected the top-level package to have been registered`);
314
+ const packageIdsByLocator = new Map();
315
+ for (const [locatorHash, packageMapNode] of packageMapNodesByLocator)
316
+ packageIdsByLocator.set(locatorHash, getPackageId(basePath, packageMapNode.packageLocation));
317
+ const serializeDependencies = (dependencies) => {
318
+ return Object.fromEntries(Array.from(dependencies).sort(([a], [b]) => compareStrings(a, b)).map(([dependencyName, dependencyLocatorHash]) => {
319
+ const dependencyPackageId = packageIdsByLocator.get(dependencyLocatorHash);
320
+ if (typeof dependencyPackageId === `undefined`)
321
+ throw new Error(`Assertion failed: Expected the package to have been registered (${dependencyLocatorHash})`);
322
+ return [dependencyName, dependencyPackageId];
323
+ }));
324
+ };
325
+ const packages = {};
326
+ for (const packageMapNode of Array.from(packageMapNodesByLocator.values()).sort((a, b) => compareStrings(getPackageId(basePath, a.packageLocation), getPackageId(basePath, b.packageLocation)))) {
327
+ const packageDependencies = type === plugin_pnp_1.NodePackageMapType.LOOSE
328
+ ? new Map([
329
+ ...topLevelPackageMapNode.dependencies,
330
+ ...packageMapNode.dependencies,
331
+ ])
332
+ : packageMapNode.dependencies;
333
+ packages[getPackageId(basePath, packageMapNode.packageLocation)] = {
334
+ url: getRelativeUrl(basePath, packageMapNode.packageLocation),
335
+ dependencies: serializeDependencies(packageDependencies),
336
+ };
337
+ }
338
+ return { packages };
339
+ }
253
340
  function isPnpmVirtualCompatible(locator, { project }) {
254
341
  // The pnpm install strategy has a limitation: because Node would always
255
342
  // resolve symbolic path to their true location, and because we can't just
package/lib/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export { PnpmLinker };
5
5
  declare module '@yarnpkg/core' {
6
6
  interface ConfigurationValueMap {
7
7
  pnpmStoreFolder: PortablePath;
8
+ pnpmInstallConcurrency: number;
8
9
  }
9
10
  }
10
11
  declare const plugin: Plugin;
package/lib/index.js CHANGED
@@ -11,6 +11,11 @@ const plugin = {
11
11
  type: core_1.SettingsType.ABSOLUTE_PATH,
12
12
  default: `./node_modules/.store`,
13
13
  },
14
+ pnpmInstallConcurrency: {
15
+ description: `Maximum number of packages the pnpm linker will install in parallel. Lower this on monorepos with very large caches if you hit "Couldn't allocate enough memory" from the bundled libzip WASM heap.`,
16
+ type: core_1.SettingsType.NUMBER,
17
+ default: 10,
18
+ },
14
19
  },
15
20
  linkers: [
16
21
  PnpmLinker_1.PnpmLinker,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yarnpkg/plugin-pnpm",
3
- "version": "2.1.2",
3
+ "version": "2.3.0",
4
4
  "license": "BSD-2-Clause",
5
5
  "main": "./lib/index.js",
6
6
  "exports": {
@@ -8,20 +8,21 @@
8
8
  "./package.json": "./package.json"
9
9
  },
10
10
  "dependencies": {
11
- "@yarnpkg/fslib": "^3.1.2",
12
- "@yarnpkg/plugin-pnp": "^4.1.1",
11
+ "@yarnpkg/fslib": "^3.1.5",
12
+ "@yarnpkg/plugin-pnp": "^4.2.0",
13
13
  "@yarnpkg/plugin-stage": "^4.0.2",
14
14
  "clipanion": "^4.0.0-rc.2",
15
15
  "p-limit": "^2.2.0",
16
16
  "tslib": "^2.4.0"
17
17
  },
18
18
  "peerDependencies": {
19
- "@yarnpkg/cli": "^4.9.3",
20
- "@yarnpkg/core": "^4.4.3"
19
+ "@yarnpkg/cli": "^4.17.0",
20
+ "@yarnpkg/core": "^4.9.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@yarnpkg/cli": "^4.9.3",
24
- "@yarnpkg/core": "^4.4.3"
23
+ "@yarnpkg/cli": "^4.17.0",
24
+ "@yarnpkg/core": "^4.9.0",
25
+ "@yarnpkg/nm": "^4.1.0"
25
26
  },
26
27
  "repository": {
27
28
  "type": "git",