-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
unlink.ts
102 lines (87 loc) Β· 4 KB
/
unlink.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import {BaseCommand, WorkspaceRequiredError} from '@yarnpkg/cli';
import {Cache, Configuration, miscUtils, Project, structUtils} from '@yarnpkg/core';
import {npath, ppath} from '@yarnpkg/fslib';
import {Command, Option, Usage, UsageError} from 'clipanion';
import micromatch from 'micromatch';
// eslint-disable-next-line arca/no-default-export
export default class UnlinkCommand extends BaseCommand {
static paths = [
[`unlink`],
];
static usage: Usage = Command.Usage({
description: `disconnect the local project from another one`,
details: `
This command will remove any resolutions in the project-level manifest that would have been added via a yarn link with similar arguments.
`,
examples: [[
`Unregister a remote workspace in the current project`,
`$0 unlink ~/ts-loader`,
], [
`Unregister all workspaces from a remote project in the current project`,
`$0 unlink ~/jest --all`,
], [
`Unregister all previously linked workspaces`,
`$0 unlink --all`,
], [
`Unregister all workspaces matching a glob`,
`$0 unlink '@babel/*' 'pkg-{a,b}'`,
]],
});
all = Option.Boolean(`-A,--all`, false, {
description: `Unlink all workspaces belonging to the target project from the current one`,
});
leadingArguments = Option.Rest();
async execute() {
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);
const {project, workspace} = await Project.find(configuration, this.context.cwd);
const cache = await Cache.find(configuration);
if (!workspace)
throw new WorkspaceRequiredError(project.cwd, this.context.cwd);
const topLevelWorkspace = project.topLevelWorkspace;
const workspacesToUnlink = new Set<string>();
if (this.leadingArguments.length === 0 && this.all) {
for (const {pattern, reference} of topLevelWorkspace.manifest.resolutions) {
if (reference.startsWith(`portal:`)) {
workspacesToUnlink.add(pattern.descriptor.fullName);
}
}
}
if (this.leadingArguments.length > 0) {
for (const leadingArgument of this.leadingArguments) {
const absoluteDestination = ppath.resolve(this.context.cwd, npath.toPortablePath(leadingArgument));
if (miscUtils.isPathLike(leadingArgument)) {
const configuration2 = await Configuration.find(absoluteDestination, this.context.plugins, {useRc: false, strict: false});
const {project: project2, workspace: workspace2} = await Project.find(configuration2, absoluteDestination);
if (!workspace2)
throw new WorkspaceRequiredError(project2.cwd, absoluteDestination);
if (this.all) {
for (const workspace of project2.workspaces)
if (workspace.manifest.name)
workspacesToUnlink.add(structUtils.stringifyIdent(workspace.anchoredLocator));
if (workspacesToUnlink.size === 0) {
throw new UsageError(`No workspace found to be unlinked in the target project`);
}
} else {
if (!workspace2.manifest.name)
throw new UsageError(`The target workspace doesn't have a name and thus cannot be unlinked`);
workspacesToUnlink.add(structUtils.stringifyIdent(workspace2.anchoredLocator));
}
} else {
const fullNames = [...topLevelWorkspace.manifest.resolutions.map(({pattern}) => pattern.descriptor.fullName)];
for (const fullName of micromatch(fullNames, leadingArgument)) {
workspacesToUnlink.add(fullName);
}
}
}
}
topLevelWorkspace.manifest.resolutions = topLevelWorkspace.manifest.resolutions.filter(({pattern}) => {
return !workspacesToUnlink.has(pattern.descriptor.fullName);
});
return await project.installWithNewReport({
stdout: this.context.stdout,
quiet: this.context.quiet,
}, {
cache,
});
}
}