@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.
- package/lib/PnpmLinker.d.ts +8 -4
- package/lib/PnpmLinker.js +91 -4
- package/lib/index.d.ts +1 -0
- package/lib/index.js +5 -0
- package/package.json +8 -7
package/lib/PnpmLinker.d.ts
CHANGED
|
@@ -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
|
-
|
|
7
|
-
|
|
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
|
-
|
|
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
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.
|
|
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.
|
|
12
|
-
"@yarnpkg/plugin-pnp": "^4.
|
|
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.
|
|
20
|
-
"@yarnpkg/core": "^4.
|
|
19
|
+
"@yarnpkg/cli": "^4.17.0",
|
|
20
|
+
"@yarnpkg/core": "^4.9.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@yarnpkg/cli": "^4.
|
|
24
|
-
"@yarnpkg/core": "^4.
|
|
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",
|