@pnpm/installing.commands 1004.6.10
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/LICENSE +22 -0
- package/README.md +15 -0
- package/lib/add.d.ts +17 -0
- package/lib/add.js +285 -0
- package/lib/ci.d.ts +6 -0
- package/lib/ci.js +20 -0
- package/lib/createProjectManifestWriter.d.ts +2 -0
- package/lib/createProjectManifestWriter.js +17 -0
- package/lib/dedupe.d.ts +9 -0
- package/lib/dedupe.js +59 -0
- package/lib/fetch.d.ts +10 -0
- package/lib/fetch.js +75 -0
- package/lib/getFetchFullMetadata.d.ts +8 -0
- package/lib/getFetchFullMetadata.js +7 -0
- package/lib/getPinnedVersion.d.ts +4 -0
- package/lib/getPinnedVersion.js +6 -0
- package/lib/getSaveType.d.ts +3 -0
- package/lib/getSaveType.js +10 -0
- package/lib/import/index.d.ts +9 -0
- package/lib/import/index.js +238 -0
- package/lib/import/yarnUtil.d.ts +8 -0
- package/lib/import/yarnUtil.js +65 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +13 -0
- package/lib/install.d.ts +28 -0
- package/lib/install.js +281 -0
- package/lib/installDeps.d.ts +41 -0
- package/lib/installDeps.js +349 -0
- package/lib/link.d.ts +9 -0
- package/lib/link.js +130 -0
- package/lib/nodeExecPath.d.ts +1 -0
- package/lib/nodeExecPath.js +16 -0
- package/lib/prune.d.ts +6 -0
- package/lib/prune.js +49 -0
- package/lib/recursive.d.ts +41 -0
- package/lib/recursive.js +406 -0
- package/lib/remove.d.ts +12 -0
- package/lib/remove.js +189 -0
- package/lib/unlink.d.ts +6 -0
- package/lib/unlink.js +62 -0
- package/lib/update/getUpdateChoices.d.ts +14 -0
- package/lib/update/getUpdateChoices.js +126 -0
- package/lib/update/index.d.ts +15 -0
- package/lib/update/index.js +295 -0
- package/lib/updateWorkspaceDependencies.d.ts +4 -0
- package/lib/updateWorkspaceDependencies.js +27 -0
- package/package.json +134 -0
package/lib/recursive.js
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { rebuild } from '@pnpm/building.commands';
|
|
4
|
+
import { throwOnCommandFail, } from '@pnpm/cli.utils';
|
|
5
|
+
import { createMatcherWithIndex } from '@pnpm/config.matcher';
|
|
6
|
+
import { createProjectConfigRecord, getWorkspaceConcurrency, } from '@pnpm/config.reader';
|
|
7
|
+
import { PnpmError } from '@pnpm/error';
|
|
8
|
+
import { requireHooks } from '@pnpm/hooks.pnpmfile';
|
|
9
|
+
import { arrayOfWorkspacePackagesToMap } from '@pnpm/installing.context';
|
|
10
|
+
import { addDependenciesToPackage, IgnoredBuildsError, install, mutateModules, } from '@pnpm/installing.deps-installer';
|
|
11
|
+
import { logger } from '@pnpm/logger';
|
|
12
|
+
import { filterDependenciesByType } from '@pnpm/pkg-manifest.utils';
|
|
13
|
+
import { createStoreController } from '@pnpm/store.connection-manager';
|
|
14
|
+
import { sortProjects } from '@pnpm/workspace.projects-sorter';
|
|
15
|
+
import { updateWorkspaceManifest } from '@pnpm/workspace.workspace-manifest-writer';
|
|
16
|
+
import { isSubdir } from 'is-subdir';
|
|
17
|
+
import pFilter from 'p-filter';
|
|
18
|
+
import pLimit from 'p-limit';
|
|
19
|
+
import { getPinnedVersion } from './getPinnedVersion.js';
|
|
20
|
+
import { getSaveType } from './getSaveType.js';
|
|
21
|
+
import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from './updateWorkspaceDependencies.js';
|
|
22
|
+
export async function recursive(allProjects, params, opts, cmdFullName) {
|
|
23
|
+
if (allProjects.length === 0) {
|
|
24
|
+
// It might make sense to throw an exception in this case
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const pkgs = Object.values(opts.selectedProjectsGraph).map((wsPkg) => wsPkg.package);
|
|
28
|
+
if (pkgs.length === 0) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const manifestsByPath = getManifestsByPath(allProjects);
|
|
32
|
+
const throwOnFail = throwOnCommandFail.bind(null, `pnpm recursive ${cmdFullName}`);
|
|
33
|
+
const store = opts.storeControllerAndDir ?? await createStoreController(opts);
|
|
34
|
+
const workspacePackages = arrayOfWorkspacePackagesToMap(allProjects);
|
|
35
|
+
const targetDependenciesField = getSaveType(opts);
|
|
36
|
+
const installOpts = Object.assign(opts, {
|
|
37
|
+
allProjects: getAllProjects(manifestsByPath, opts.allProjectsGraph, opts.sort),
|
|
38
|
+
linkWorkspacePackagesDepth: opts.linkWorkspacePackages === 'deep' ? Infinity : opts.linkWorkspacePackages ? 0 : -1,
|
|
39
|
+
ownLifecycleHooksStdio: 'pipe',
|
|
40
|
+
peer: opts.savePeer,
|
|
41
|
+
pruneLockfileImporters: opts.pruneLockfileImporters ??
|
|
42
|
+
(((opts.ignoredPackages == null) || opts.ignoredPackages.size === 0) &&
|
|
43
|
+
pkgs.length === allProjects.length),
|
|
44
|
+
saveCatalogName: opts.saveCatalogName,
|
|
45
|
+
storeController: store.ctrl,
|
|
46
|
+
storeDir: store.dir,
|
|
47
|
+
targetDependenciesField,
|
|
48
|
+
workspacePackages,
|
|
49
|
+
forceHoistPattern: typeof opts.rawLocalConfig?.['hoist-pattern'] !== 'undefined' || typeof opts.rawLocalConfig?.['hoist'] !== 'undefined',
|
|
50
|
+
forceShamefullyHoist: typeof opts.rawLocalConfig?.['shamefully-hoist'] !== 'undefined',
|
|
51
|
+
});
|
|
52
|
+
const result = {};
|
|
53
|
+
const projectConfigRecord = createProjectConfigRecord(opts);
|
|
54
|
+
const getProjectConfig = projectConfigRecord
|
|
55
|
+
? manifest => manifest.name ? projectConfigRecord[manifest.name] : undefined
|
|
56
|
+
: () => undefined;
|
|
57
|
+
const updateToLatest = opts.update && opts.latest;
|
|
58
|
+
const includeDirect = opts.includeDirect ?? {
|
|
59
|
+
dependencies: true,
|
|
60
|
+
devDependencies: true,
|
|
61
|
+
optionalDependencies: true,
|
|
62
|
+
};
|
|
63
|
+
let updateMatch;
|
|
64
|
+
if (cmdFullName === 'update') {
|
|
65
|
+
if (params.length === 0) {
|
|
66
|
+
const ignoreDeps = opts.updateConfig?.ignoreDependencies;
|
|
67
|
+
if (ignoreDeps?.length) {
|
|
68
|
+
params = makeIgnorePatterns(ignoreDeps);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
updateMatch = params.length ? createMatcher(params) : null;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
updateMatch = null;
|
|
75
|
+
}
|
|
76
|
+
// For a workspace with shared lockfile
|
|
77
|
+
if (opts.lockfileDir && ['add', 'install', 'remove', 'update', 'import'].includes(cmdFullName)) {
|
|
78
|
+
let importers = getImporters(opts);
|
|
79
|
+
const calculatedRepositoryRoot = await fs.realpath(calculateRepositoryRoot(opts.workspaceDir, importers.map(x => x.rootDir)));
|
|
80
|
+
const isFromWorkspace = isSubdir.bind(null, calculatedRepositoryRoot);
|
|
81
|
+
importers = await pFilter(importers, async ({ rootDirRealPath }) => isFromWorkspace(rootDirRealPath));
|
|
82
|
+
if (importers.length === 0)
|
|
83
|
+
return true;
|
|
84
|
+
let mutation;
|
|
85
|
+
switch (cmdFullName) {
|
|
86
|
+
case 'remove':
|
|
87
|
+
mutation = 'uninstallSome';
|
|
88
|
+
break;
|
|
89
|
+
case 'import':
|
|
90
|
+
mutation = 'install';
|
|
91
|
+
break;
|
|
92
|
+
default:
|
|
93
|
+
mutation = (params.length === 0 && !updateToLatest ? 'install' : 'installSome');
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
const mutatedImporters = [];
|
|
97
|
+
await Promise.all(importers.map(async ({ rootDir }) => {
|
|
98
|
+
const { manifest } = manifestsByPath[rootDir];
|
|
99
|
+
const localConfig = getProjectConfig(manifest) ?? {};
|
|
100
|
+
const modulesDir = localConfig.modulesDir ?? opts.modulesDir;
|
|
101
|
+
let currentInput = [...params];
|
|
102
|
+
if (updateMatch != null) {
|
|
103
|
+
currentInput = matchDependencies(updateMatch, manifest, includeDirect);
|
|
104
|
+
if ((currentInput.length === 0) && (typeof opts.depth === 'undefined' || opts.depth <= 0)) {
|
|
105
|
+
installOpts.pruneLockfileImporters = false;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (updateToLatest && (!params || (params.length === 0))) {
|
|
110
|
+
currentInput = Object.keys(filterDependenciesByType(manifest, includeDirect));
|
|
111
|
+
}
|
|
112
|
+
if (opts.workspace) {
|
|
113
|
+
if (!currentInput || (currentInput.length === 0)) {
|
|
114
|
+
currentInput = updateToWorkspacePackagesFromManifest(manifest, includeDirect, workspacePackages);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
currentInput = createWorkspaceSpecs(currentInput, workspacePackages);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
switch (mutation) {
|
|
121
|
+
case 'uninstallSome':
|
|
122
|
+
mutatedImporters.push({
|
|
123
|
+
dependencyNames: currentInput,
|
|
124
|
+
modulesDir,
|
|
125
|
+
mutation,
|
|
126
|
+
rootDir,
|
|
127
|
+
targetDependenciesField,
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
case 'installSome':
|
|
131
|
+
mutatedImporters.push({
|
|
132
|
+
allowNew: cmdFullName === 'install' || cmdFullName === 'add',
|
|
133
|
+
dependencySelectors: currentInput,
|
|
134
|
+
modulesDir,
|
|
135
|
+
mutation,
|
|
136
|
+
peer: opts.savePeer,
|
|
137
|
+
pinnedVersion: getPinnedVersion({
|
|
138
|
+
saveExact: typeof localConfig.saveExact === 'boolean' ? localConfig.saveExact : opts.saveExact,
|
|
139
|
+
savePrefix: typeof localConfig.savePrefix === 'string' ? localConfig.savePrefix : opts.savePrefix,
|
|
140
|
+
}),
|
|
141
|
+
rootDir,
|
|
142
|
+
targetDependenciesField,
|
|
143
|
+
update: opts.update,
|
|
144
|
+
updateMatching: opts.updateMatching,
|
|
145
|
+
updatePackageManifest: opts.updatePackageManifest,
|
|
146
|
+
updateToLatest: opts.latest,
|
|
147
|
+
});
|
|
148
|
+
return;
|
|
149
|
+
case 'install':
|
|
150
|
+
mutatedImporters.push({
|
|
151
|
+
modulesDir,
|
|
152
|
+
mutation,
|
|
153
|
+
pruneDirectDependencies: opts.pruneDirectDependencies,
|
|
154
|
+
rootDir,
|
|
155
|
+
update: opts.update,
|
|
156
|
+
updateMatching: opts.updateMatching,
|
|
157
|
+
updatePackageManifest: opts.updatePackageManifest,
|
|
158
|
+
updateToLatest: opts.latest,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}));
|
|
162
|
+
if (!opts.selectedProjectsGraph[opts.workspaceDir] && manifestsByPath[opts.workspaceDir] != null) {
|
|
163
|
+
mutatedImporters.push({
|
|
164
|
+
mutation: 'install',
|
|
165
|
+
rootDir: opts.workspaceDir,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if ((mutatedImporters.length === 0) && cmdFullName === 'update' && opts.depth === 0) {
|
|
169
|
+
throw new PnpmError('NO_PACKAGE_IN_DEPENDENCIES', 'None of the specified packages were found in the dependencies of any of the projects.');
|
|
170
|
+
}
|
|
171
|
+
const { updatedCatalogs, updatedProjects: mutatedPkgs, ignoredBuilds, } = await mutateModules(mutatedImporters, {
|
|
172
|
+
...installOpts,
|
|
173
|
+
storeController: store.ctrl,
|
|
174
|
+
});
|
|
175
|
+
if (opts.save !== false) {
|
|
176
|
+
const promises = mutatedPkgs.map(async ({ originalManifest, manifest, rootDir }) => {
|
|
177
|
+
return manifestsByPath[rootDir].writeProjectManifest(originalManifest ?? manifest);
|
|
178
|
+
});
|
|
179
|
+
promises.push(updateWorkspaceManifest(opts.workspaceDir, {
|
|
180
|
+
updatedCatalogs,
|
|
181
|
+
cleanupUnusedCatalogs: opts.cleanupUnusedCatalogs,
|
|
182
|
+
allProjects,
|
|
183
|
+
}));
|
|
184
|
+
await Promise.all(promises);
|
|
185
|
+
}
|
|
186
|
+
if (opts.strictDepBuilds && ignoredBuilds?.size) {
|
|
187
|
+
throw new IgnoredBuildsError(ignoredBuilds);
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
const pkgPaths = Object.keys(opts.selectedProjectsGraph).sort();
|
|
192
|
+
let updatedCatalogs;
|
|
193
|
+
const limitInstallation = pLimit(getWorkspaceConcurrency(opts.workspaceConcurrency));
|
|
194
|
+
await Promise.all(pkgPaths.map(async (rootDir) => limitInstallation(async () => {
|
|
195
|
+
const hooks = opts.ignorePnpmfile
|
|
196
|
+
? {}
|
|
197
|
+
: await (async () => {
|
|
198
|
+
const { hooks: pnpmfileHooks } = await requireHooks(rootDir, opts);
|
|
199
|
+
return {
|
|
200
|
+
...opts.hooks,
|
|
201
|
+
...pnpmfileHooks,
|
|
202
|
+
afterAllResolved: [...(pnpmfileHooks.afterAllResolved ?? []), ...(opts.hooks?.afterAllResolved ?? [])],
|
|
203
|
+
readPackage: [...(pnpmfileHooks.readPackage ?? []), ...(opts.hooks?.readPackage ?? [])],
|
|
204
|
+
};
|
|
205
|
+
})();
|
|
206
|
+
try {
|
|
207
|
+
if (opts.ignoredPackages?.has(rootDir)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
result[rootDir] = { status: 'running' };
|
|
211
|
+
const { manifest, writeProjectManifest } = manifestsByPath[rootDir];
|
|
212
|
+
let currentInput = [...params];
|
|
213
|
+
if (updateMatch != null) {
|
|
214
|
+
currentInput = matchDependencies(updateMatch, manifest, includeDirect);
|
|
215
|
+
if (currentInput.length === 0)
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (updateToLatest && (!params || (params.length === 0))) {
|
|
219
|
+
currentInput = Object.keys(filterDependenciesByType(manifest, includeDirect));
|
|
220
|
+
}
|
|
221
|
+
if (opts.workspace) {
|
|
222
|
+
if (!currentInput || (currentInput.length === 0)) {
|
|
223
|
+
currentInput = updateToWorkspacePackagesFromManifest(manifest, includeDirect, workspacePackages);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
currentInput = createWorkspaceSpecs(currentInput, workspacePackages);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
let action;
|
|
230
|
+
switch (cmdFullName) {
|
|
231
|
+
case 'remove':
|
|
232
|
+
action = async (manifest, opts) => {
|
|
233
|
+
const mutationResult = await mutateModules([
|
|
234
|
+
{
|
|
235
|
+
dependencyNames: currentInput,
|
|
236
|
+
mutation: 'uninstallSome',
|
|
237
|
+
rootDir,
|
|
238
|
+
},
|
|
239
|
+
], opts);
|
|
240
|
+
return {
|
|
241
|
+
updatedCatalogs: undefined, // there's no reason to add new or update catalogs on `pnpm remove`
|
|
242
|
+
updatedManifest: mutationResult.updatedProjects[0].manifest,
|
|
243
|
+
ignoredBuilds: mutationResult.ignoredBuilds,
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
break;
|
|
247
|
+
default:
|
|
248
|
+
action = currentInput.length === 0
|
|
249
|
+
? install
|
|
250
|
+
: async (manifest, opts) => addDependenciesToPackage(manifest, currentInput, opts);
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
const localConfig = getProjectConfig(manifest) ?? {};
|
|
254
|
+
const { updatedCatalogs: newCatalogsAddition, updatedManifest: newManifest, ignoredBuilds, } = await action(manifest, {
|
|
255
|
+
...installOpts,
|
|
256
|
+
...localConfig,
|
|
257
|
+
...opts.allProjectsGraph[rootDir]?.package,
|
|
258
|
+
bin: path.join(rootDir, 'node_modules', '.bin'),
|
|
259
|
+
dir: rootDir,
|
|
260
|
+
hooks,
|
|
261
|
+
ignoreScripts: true,
|
|
262
|
+
pinnedVersion: getPinnedVersion({
|
|
263
|
+
saveExact: typeof localConfig.saveExact === 'boolean' ? localConfig.saveExact : opts.saveExact,
|
|
264
|
+
savePrefix: typeof localConfig.savePrefix === 'string' ? localConfig.savePrefix : opts.savePrefix,
|
|
265
|
+
}),
|
|
266
|
+
rawConfig: {
|
|
267
|
+
...installOpts.rawConfig,
|
|
268
|
+
...localConfig,
|
|
269
|
+
},
|
|
270
|
+
storeController: store.ctrl,
|
|
271
|
+
});
|
|
272
|
+
if (opts.save !== false) {
|
|
273
|
+
await writeProjectManifest(newManifest);
|
|
274
|
+
if (newCatalogsAddition) {
|
|
275
|
+
updatedCatalogs ??= {};
|
|
276
|
+
Object.assign(updatedCatalogs, newCatalogsAddition);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (opts.strictDepBuilds && ignoredBuilds?.size) {
|
|
280
|
+
throw new IgnoredBuildsError(ignoredBuilds);
|
|
281
|
+
}
|
|
282
|
+
result[rootDir].status = 'passed';
|
|
283
|
+
}
|
|
284
|
+
catch (err) { // eslint-disable-line
|
|
285
|
+
logger.info(err);
|
|
286
|
+
if (!opts.bail) {
|
|
287
|
+
result[rootDir] = {
|
|
288
|
+
status: 'failure',
|
|
289
|
+
error: err,
|
|
290
|
+
message: err.message,
|
|
291
|
+
prefix: rootDir,
|
|
292
|
+
};
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
err['prefix'] = rootDir;
|
|
296
|
+
throw err;
|
|
297
|
+
}
|
|
298
|
+
})));
|
|
299
|
+
await updateWorkspaceManifest(opts.workspaceDir, {
|
|
300
|
+
updatedCatalogs,
|
|
301
|
+
cleanupUnusedCatalogs: opts.cleanupUnusedCatalogs,
|
|
302
|
+
allProjects,
|
|
303
|
+
});
|
|
304
|
+
if (!opts.lockfileOnly && !opts.ignoreScripts && (cmdFullName === 'add' ||
|
|
305
|
+
cmdFullName === 'install' ||
|
|
306
|
+
cmdFullName === 'update')) {
|
|
307
|
+
await rebuild.handler({
|
|
308
|
+
...opts,
|
|
309
|
+
pending: opts.pending === true,
|
|
310
|
+
skipIfHasSideEffectsCache: true,
|
|
311
|
+
}, []);
|
|
312
|
+
}
|
|
313
|
+
throwOnFail(result);
|
|
314
|
+
if (!Object.values(result).filter(({ status }) => status === 'passed').length && cmdFullName === 'update' && opts.depth === 0) {
|
|
315
|
+
throw new PnpmError('NO_PACKAGE_IN_DEPENDENCIES', 'None of the specified packages were found in the dependencies of any of the projects.');
|
|
316
|
+
}
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
function calculateRepositoryRoot(workspaceDir, projectDirs) {
|
|
320
|
+
// assume repo root is workspace dir
|
|
321
|
+
let relativeRepoRoot = '.';
|
|
322
|
+
for (const rootDir of projectDirs) {
|
|
323
|
+
const relativePartRegExp = new RegExp(`^(\\.\\.\\${path.sep})+`);
|
|
324
|
+
const relativePartMatch = relativePartRegExp.exec(path.relative(workspaceDir, rootDir));
|
|
325
|
+
if (relativePartMatch != null) {
|
|
326
|
+
const relativePart = relativePartMatch[0];
|
|
327
|
+
if (relativePart.length > relativeRepoRoot.length) {
|
|
328
|
+
relativeRepoRoot = relativePart;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return path.resolve(workspaceDir, relativeRepoRoot);
|
|
333
|
+
}
|
|
334
|
+
export function matchDependencies(match, manifest, include) {
|
|
335
|
+
const deps = Object.keys(filterDependenciesByType(manifest, include));
|
|
336
|
+
const matchedDeps = [];
|
|
337
|
+
for (const dep of deps) {
|
|
338
|
+
const spec = match(dep);
|
|
339
|
+
if (spec === null)
|
|
340
|
+
continue;
|
|
341
|
+
matchedDeps.push(spec ? `${dep}@${spec}` : dep);
|
|
342
|
+
}
|
|
343
|
+
return matchedDeps;
|
|
344
|
+
}
|
|
345
|
+
export function createMatcher(params) {
|
|
346
|
+
const patterns = [];
|
|
347
|
+
const specs = [];
|
|
348
|
+
for (const param of params) {
|
|
349
|
+
const { pattern, versionSpec } = parseUpdateParam(param);
|
|
350
|
+
patterns.push(pattern);
|
|
351
|
+
specs.push(versionSpec ?? '');
|
|
352
|
+
}
|
|
353
|
+
const matcher = createMatcherWithIndex(patterns);
|
|
354
|
+
return (depName) => {
|
|
355
|
+
const index = matcher(depName);
|
|
356
|
+
if (index === -1)
|
|
357
|
+
return null;
|
|
358
|
+
return specs[index];
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
export function parseUpdateParam(param) {
|
|
362
|
+
const atIndex = param.indexOf('@', param[0] === '!' ? 2 : 1);
|
|
363
|
+
if (atIndex === -1) {
|
|
364
|
+
return {
|
|
365
|
+
pattern: param,
|
|
366
|
+
versionSpec: undefined,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
return {
|
|
370
|
+
pattern: param.slice(0, atIndex),
|
|
371
|
+
versionSpec: param.slice(atIndex + 1),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
export function makeIgnorePatterns(ignoredDependencies) {
|
|
375
|
+
return ignoredDependencies.map(depName => `!${depName}`);
|
|
376
|
+
}
|
|
377
|
+
function getAllProjects(manifestsByPath, allProjectsGraph, sort) {
|
|
378
|
+
const chunks = sort !== false
|
|
379
|
+
? sortProjects(allProjectsGraph)
|
|
380
|
+
: [Object.keys(allProjectsGraph).sort()];
|
|
381
|
+
return chunks.map((prefixes, buildIndex) => prefixes.map((rootDir) => {
|
|
382
|
+
const { rootDirRealPath, modulesDir } = allProjectsGraph[rootDir].package;
|
|
383
|
+
return {
|
|
384
|
+
buildIndex,
|
|
385
|
+
manifest: manifestsByPath[rootDir].manifest,
|
|
386
|
+
rootDir,
|
|
387
|
+
rootDirRealPath,
|
|
388
|
+
modulesDir,
|
|
389
|
+
};
|
|
390
|
+
})).flat();
|
|
391
|
+
}
|
|
392
|
+
function getManifestsByPath(projects) {
|
|
393
|
+
const manifestsByPath = {};
|
|
394
|
+
for (const { rootDir, manifest, writeProjectManifest } of projects) {
|
|
395
|
+
manifestsByPath[rootDir] = { manifest, writeProjectManifest };
|
|
396
|
+
}
|
|
397
|
+
return manifestsByPath;
|
|
398
|
+
}
|
|
399
|
+
function getImporters(opts) {
|
|
400
|
+
let rootDirs = Object.keys(opts.selectedProjectsGraph);
|
|
401
|
+
if (opts.ignoredPackages != null) {
|
|
402
|
+
rootDirs = rootDirs.filter((rootDir) => !opts.ignoredPackages.has(rootDir));
|
|
403
|
+
}
|
|
404
|
+
return rootDirs.map((rootDir) => ({ rootDir, rootDirRealPath: opts.selectedProjectsGraph[rootDir].package.rootDirRealPath }));
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=recursive.js.map
|
package/lib/remove.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CompletionFunc } from '@pnpm/cli.command';
|
|
2
|
+
import { type Config } from '@pnpm/config.reader';
|
|
3
|
+
import { type CreateStoreControllerOptions } from '@pnpm/store.connection-manager';
|
|
4
|
+
export declare function rcOptionsTypes(): Record<string, unknown>;
|
|
5
|
+
export declare const cliOptionsTypes: () => Record<string, unknown>;
|
|
6
|
+
export declare function help(): string;
|
|
7
|
+
export declare const commandNames: string[];
|
|
8
|
+
export declare const completion: CompletionFunc;
|
|
9
|
+
export declare function handler(opts: CreateStoreControllerOptions & Pick<Config, 'allProjects' | 'allProjectsGraph' | 'bail' | 'bin' | 'configDependencies' | 'dev' | 'engineStrict' | 'globalPnpmfile' | 'hooks' | 'ignorePnpmfile' | 'linkWorkspacePackages' | 'lockfileDir' | 'optional' | 'production' | 'rawLocalConfig' | 'registries' | 'rootProjectManifest' | 'rootProjectManifestDir' | 'saveDev' | 'saveOptional' | 'saveProd' | 'selectedProjectsGraph' | 'workspaceDir' | 'workspacePackagePatterns' | 'sharedWorkspaceLockfile' | 'cleanupUnusedCatalogs'> & {
|
|
10
|
+
recursive?: boolean;
|
|
11
|
+
pnpmfile: string[];
|
|
12
|
+
} & Partial<Pick<Config, 'global' | 'globalPkgDir'>>, params: string[]): Promise<void>;
|
package/lib/remove.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { FILTERING, OPTIONS, UNIVERSAL_OPTIONS } from '@pnpm/cli.common-cli-options-help';
|
|
2
|
+
import { docsUrl, readDepNameCompletions, readProjectManifest, } from '@pnpm/cli.utils';
|
|
3
|
+
import { types as allTypes } from '@pnpm/config.reader';
|
|
4
|
+
import { PnpmError } from '@pnpm/error';
|
|
5
|
+
import { handleGlobalRemove } from '@pnpm/global.commands';
|
|
6
|
+
import { arrayOfWorkspacePackagesToMap } from '@pnpm/installing.context';
|
|
7
|
+
import { mutateModulesInSingleProject } from '@pnpm/installing.deps-installer';
|
|
8
|
+
import { getAllDependenciesFromManifest } from '@pnpm/pkg-manifest.utils';
|
|
9
|
+
import { createStoreController } from '@pnpm/store.connection-manager';
|
|
10
|
+
import { findWorkspaceProjects } from '@pnpm/workspace.projects-reader';
|
|
11
|
+
import { updateWorkspaceManifest } from '@pnpm/workspace.workspace-manifest-writer';
|
|
12
|
+
import { pick, without } from 'ramda';
|
|
13
|
+
import { renderHelp } from 'render-help';
|
|
14
|
+
import { getSaveType } from './getSaveType.js';
|
|
15
|
+
import { recursive } from './recursive.js';
|
|
16
|
+
class RemoveMissingDepsError extends PnpmError {
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
let message = 'Cannot remove ';
|
|
19
|
+
message += `${opts.nonMatchedDependencies.map(dep => `'${dep}'`).join(', ')}: `;
|
|
20
|
+
if (opts.availableDependencies.length > 0) {
|
|
21
|
+
message += `no such ${opts.nonMatchedDependencies.length > 1 ? 'dependencies' : 'dependency'} `;
|
|
22
|
+
message += `found${opts.targetDependenciesField ? ` in '${opts.targetDependenciesField}'` : ''}`;
|
|
23
|
+
const hint = `Available dependencies: ${opts.availableDependencies.join(', ')}`;
|
|
24
|
+
super('CANNOT_REMOVE_MISSING_DEPS', message, { hint });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
message += opts.targetDependenciesField
|
|
28
|
+
? `project has no '${opts.targetDependenciesField}'`
|
|
29
|
+
: 'project has no dependencies of any kind';
|
|
30
|
+
super('CANNOT_REMOVE_MISSING_DEPS', message);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function rcOptionsTypes() {
|
|
34
|
+
return pick([
|
|
35
|
+
'cache-dir',
|
|
36
|
+
'global-dir',
|
|
37
|
+
'global-pnpmfile',
|
|
38
|
+
'global',
|
|
39
|
+
'lockfile-dir',
|
|
40
|
+
'lockfile-directory',
|
|
41
|
+
'lockfile-only',
|
|
42
|
+
'lockfile',
|
|
43
|
+
'node-linker',
|
|
44
|
+
'package-import-method',
|
|
45
|
+
'pnpmfile',
|
|
46
|
+
'reporter',
|
|
47
|
+
'save-dev',
|
|
48
|
+
'save-optional',
|
|
49
|
+
'save-prod',
|
|
50
|
+
'shared-workspace-lockfile',
|
|
51
|
+
'store-dir',
|
|
52
|
+
'strict-peer-dependencies',
|
|
53
|
+
'virtual-store-dir',
|
|
54
|
+
], allTypes);
|
|
55
|
+
}
|
|
56
|
+
export const cliOptionsTypes = () => ({
|
|
57
|
+
...rcOptionsTypes(),
|
|
58
|
+
...pick(['force'], allTypes),
|
|
59
|
+
recursive: Boolean,
|
|
60
|
+
});
|
|
61
|
+
export function help() {
|
|
62
|
+
return renderHelp({
|
|
63
|
+
aliases: ['rm', 'uninstall', 'un'],
|
|
64
|
+
description: 'Removes packages from `node_modules` and from the project\'s `package.json`.',
|
|
65
|
+
descriptionLists: [
|
|
66
|
+
{
|
|
67
|
+
title: 'Options',
|
|
68
|
+
list: [
|
|
69
|
+
{
|
|
70
|
+
description: 'Remove from every package found in subdirectories \
|
|
71
|
+
or from every workspace package, when executed inside a workspace. \
|
|
72
|
+
For options that may be used with `-r`, see "pnpm help recursive"',
|
|
73
|
+
name: '--recursive',
|
|
74
|
+
shortAlias: '-r',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
description: 'Remove the dependency only from "devDependencies"',
|
|
78
|
+
name: '--save-dev',
|
|
79
|
+
shortAlias: '-D',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
description: 'Remove the dependency only from "optionalDependencies"',
|
|
83
|
+
name: '--save-optional',
|
|
84
|
+
shortAlias: '-O',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
description: 'Remove the dependency only from "dependencies"',
|
|
88
|
+
name: '--save-prod',
|
|
89
|
+
shortAlias: '-P',
|
|
90
|
+
},
|
|
91
|
+
OPTIONS.globalDir,
|
|
92
|
+
...UNIVERSAL_OPTIONS,
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
FILTERING,
|
|
96
|
+
],
|
|
97
|
+
url: docsUrl('remove'),
|
|
98
|
+
usages: ['pnpm remove <pkg>[@<version>]...'],
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// Unlike npm, pnpm does not treat "r" as an alias of "remove".
|
|
102
|
+
// This way we avoid the confusion about whether "pnpm r" means remove, run, or recursive.
|
|
103
|
+
export const commandNames = ['remove', 'uninstall', 'rm', 'un', 'uni'];
|
|
104
|
+
export const completion = async (cliOpts) => {
|
|
105
|
+
return readDepNameCompletions(cliOpts.dir);
|
|
106
|
+
};
|
|
107
|
+
export async function handler(opts, params) {
|
|
108
|
+
if (params.length === 0)
|
|
109
|
+
throw new PnpmError('MUST_REMOVE_SOMETHING', 'At least one dependency name should be specified for removal');
|
|
110
|
+
if (opts.global) {
|
|
111
|
+
if (!opts.bin) {
|
|
112
|
+
throw new PnpmError('NO_GLOBAL_BIN_DIR', 'Unable to find the global bin directory', {
|
|
113
|
+
hint: 'Run "pnpm setup" to create it automatically, or set the global-bin-dir setting, or the PNPM_HOME env variable. The global bin directory should be in the PATH.',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return handleGlobalRemove(opts, params);
|
|
117
|
+
}
|
|
118
|
+
const include = {
|
|
119
|
+
dependencies: opts.production !== false,
|
|
120
|
+
devDependencies: opts.dev !== false,
|
|
121
|
+
optionalDependencies: opts.optional !== false,
|
|
122
|
+
};
|
|
123
|
+
const store = await createStoreController(opts);
|
|
124
|
+
if (opts.recursive && (opts.allProjects != null) && (opts.selectedProjectsGraph != null) && opts.workspaceDir) {
|
|
125
|
+
await recursive(opts.allProjects, params, {
|
|
126
|
+
...opts,
|
|
127
|
+
allProjectsGraph: opts.allProjectsGraph,
|
|
128
|
+
include,
|
|
129
|
+
selectedProjectsGraph: opts.selectedProjectsGraph,
|
|
130
|
+
storeControllerAndDir: store,
|
|
131
|
+
workspaceDir: opts.workspaceDir,
|
|
132
|
+
}, 'remove');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const removeOpts = Object.assign(opts, {
|
|
136
|
+
linkWorkspacePackagesDepth: opts.linkWorkspacePackages === 'deep' ? Infinity : opts.linkWorkspacePackages ? 0 : -1,
|
|
137
|
+
storeController: store.ctrl,
|
|
138
|
+
storeDir: store.dir,
|
|
139
|
+
include,
|
|
140
|
+
});
|
|
141
|
+
const allProjects = opts.allProjects ?? (opts.workspaceDir
|
|
142
|
+
? await findWorkspaceProjects(opts.workspaceDir, { ...opts, patterns: opts.workspacePackagePatterns })
|
|
143
|
+
: undefined);
|
|
144
|
+
// @ts-expect-error
|
|
145
|
+
removeOpts['workspacePackages'] = allProjects
|
|
146
|
+
? arrayOfWorkspacePackagesToMap(allProjects)
|
|
147
|
+
: undefined;
|
|
148
|
+
const targetDependenciesField = getSaveType(opts);
|
|
149
|
+
const { manifest: currentManifest, writeProjectManifest, } = await readProjectManifest(opts.dir, opts);
|
|
150
|
+
const availableDependencies = Object.keys(targetDependenciesField === undefined
|
|
151
|
+
? getAllDependenciesFromManifest(currentManifest)
|
|
152
|
+
: currentManifest[targetDependenciesField] ?? {});
|
|
153
|
+
const nonMatchedDependencies = without(availableDependencies, params);
|
|
154
|
+
if (nonMatchedDependencies.length !== 0) {
|
|
155
|
+
throw new RemoveMissingDepsError({
|
|
156
|
+
availableDependencies,
|
|
157
|
+
nonMatchedDependencies,
|
|
158
|
+
targetDependenciesField,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
const mutationResult = await mutateModulesInSingleProject({
|
|
162
|
+
binsDir: opts.bin,
|
|
163
|
+
dependencyNames: params,
|
|
164
|
+
manifest: currentManifest,
|
|
165
|
+
mutation: 'uninstallSome',
|
|
166
|
+
rootDir: opts.dir,
|
|
167
|
+
targetDependenciesField,
|
|
168
|
+
}, removeOpts);
|
|
169
|
+
await writeProjectManifest(mutationResult.updatedProject.manifest);
|
|
170
|
+
const updatedProjects = [];
|
|
171
|
+
if (allProjects != null) {
|
|
172
|
+
for (const project of allProjects) {
|
|
173
|
+
if (project.rootDir === mutationResult.updatedProject.rootDir) {
|
|
174
|
+
updatedProjects.push({
|
|
175
|
+
...project,
|
|
176
|
+
manifest: mutationResult.updatedProject.manifest,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
updatedProjects.push(project);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
await updateWorkspaceManifest(opts.workspaceDir ?? opts.dir, {
|
|
185
|
+
cleanupUnusedCatalogs: opts.cleanupUnusedCatalogs,
|
|
186
|
+
allProjects: updatedProjects,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=remove.js.map
|
package/lib/unlink.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as install from './install.js';
|
|
2
|
+
export declare const cliOptionsTypes: () => Record<string, unknown>;
|
|
3
|
+
export declare const rcOptionsTypes: typeof install.rcOptionsTypes;
|
|
4
|
+
export declare const commandNames: string[];
|
|
5
|
+
export declare function help(): string;
|
|
6
|
+
export declare function handler(opts: install.InstallCommandOptions, params: string[]): Promise<undefined | string>;
|
package/lib/unlink.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { UNIVERSAL_OPTIONS } from '@pnpm/cli.common-cli-options-help';
|
|
2
|
+
import { docsUrl } from '@pnpm/cli.utils';
|
|
3
|
+
import { writeSettings } from '@pnpm/config.writer';
|
|
4
|
+
import { renderHelp } from 'render-help';
|
|
5
|
+
import * as install from './install.js';
|
|
6
|
+
export const cliOptionsTypes = install.cliOptionsTypes;
|
|
7
|
+
export const rcOptionsTypes = install.rcOptionsTypes;
|
|
8
|
+
export const commandNames = ['unlink', 'dislink'];
|
|
9
|
+
export function help() {
|
|
10
|
+
return renderHelp({
|
|
11
|
+
aliases: ['dislink'],
|
|
12
|
+
description: 'Removes the link created by `pnpm link` and reinstalls package if it is saved in `package.json`',
|
|
13
|
+
descriptionLists: [
|
|
14
|
+
{
|
|
15
|
+
title: 'Options',
|
|
16
|
+
list: [
|
|
17
|
+
{
|
|
18
|
+
description: 'Unlink in every package found in subdirectories \
|
|
19
|
+
or in every workspace package, when executed inside a workspace. \
|
|
20
|
+
For options that may be used with `-r`, see "pnpm help recursive"',
|
|
21
|
+
name: '--recursive',
|
|
22
|
+
shortAlias: '-r',
|
|
23
|
+
},
|
|
24
|
+
...UNIVERSAL_OPTIONS,
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
url: docsUrl('unlink'),
|
|
29
|
+
usages: [
|
|
30
|
+
'pnpm unlink (in package dir)',
|
|
31
|
+
'pnpm unlink <pkg>...',
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export async function handler(opts, params) {
|
|
36
|
+
if (!opts.overrides)
|
|
37
|
+
return 'Nothing to unlink';
|
|
38
|
+
if (!params || (params.length === 0)) {
|
|
39
|
+
for (const selector in opts.overrides) {
|
|
40
|
+
if (opts.overrides[selector].startsWith('link:')) {
|
|
41
|
+
delete opts.overrides[selector];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
for (const selector in opts.overrides) {
|
|
47
|
+
if (opts.overrides[selector].startsWith('link:') && params.includes(selector)) {
|
|
48
|
+
delete opts.overrides[selector];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
await writeSettings({
|
|
53
|
+
workspaceDir: opts.workspaceDir ?? opts.rootProjectManifestDir,
|
|
54
|
+
rootProjectManifestDir: opts.rootProjectManifestDir,
|
|
55
|
+
updatedSettings: {
|
|
56
|
+
overrides: opts.overrides,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
await install.handler(opts);
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=unlink.js.map
|