-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathfocus.ts
112 lines (92 loc) Β· 4.51 KB
/
focus.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
103
104
105
106
107
108
109
110
111
112
import {BaseCommand, WorkspaceRequiredError} from '@yarnpkg/cli';
import {Cache, Configuration, Manifest, Project, StreamReport, Workspace} from '@yarnpkg/core';
import {structUtils} from '@yarnpkg/core';
import {Command, Usage} from 'clipanion';
import * as yup from 'yup';
// eslint-disable-next-line arca/no-default-export
export default class WorkspacesFocus extends BaseCommand {
@Command.Rest()
workspaces: Array<string> = [];
@Command.Boolean(`--json`, {description: `Format the output as an NDJSON stream`})
json: boolean = false;
@Command.Boolean(`--production`, {description: `Only install regular dependencies by omitting dev dependencies`})
production: boolean = false;
@Command.Boolean(`-A,--all`, {description: `Install the entire project`})
all: boolean = false;
static usage: Usage = Command.Usage({
category: `Workspace-related commands`,
description: `install a single workspace and its dependencies`,
details: `
This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.
Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the \`.pnp.js\` file, at the cost of introducing an extra complexity.
If the \`-A,--all\` flag is set, the entire project will be installed. Combine with \`--production\` to replicate the old \`yarn install --production\`.
`,
});
static schema = yup.object().shape({
all: yup.bool(),
workspaces: yup.array().when(`all`, {
is: true,
then: yup.array().max(0, `Cannot specify workspaces when using the --all flag`),
otherwise: yup.array(),
}),
});
@Command.Path(`workspaces`, `focus`)
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);
let requiredWorkspaces: Set<Workspace>;
if (this.all) {
requiredWorkspaces = new Set(project.workspaces);
} else if (this.workspaces.length === 0) {
if (!workspace)
throw new WorkspaceRequiredError(project.cwd, this.context.cwd);
requiredWorkspaces = new Set([workspace]);
} else {
requiredWorkspaces = new Set(this.workspaces.map(name => {
return project.getWorkspaceByIdent(structUtils.parseIdent(name));
}));
}
// First we compute the dependency chain to see what workspaces are
// dependencies of the one we're trying to focus on.
//
// Note: remember that new elements can be added in a set even while
// iterating over it (because they're added at the end)
for (const workspace of requiredWorkspaces) {
for (const dependencyType of Manifest.hardDependencies) {
for (const descriptor of workspace.manifest.getForScope(dependencyType).values()) {
const matchingWorkspace = project.tryWorkspaceByDescriptor(descriptor);
if (matchingWorkspace === null)
continue;
requiredWorkspaces.add(matchingWorkspace);
}
}
}
// Then we go over each workspace that didn't get selected, and remove all
// their dependencies.
for (const workspace of project.workspaces) {
if (requiredWorkspaces.has(workspace)) {
if (this.production) {
workspace.manifest.devDependencies.clear();
}
} else {
workspace.manifest.dependencies.clear();
workspace.manifest.devDependencies.clear();
workspace.manifest.peerDependencies.clear();
workspace.manifest.scripts.clear();
}
}
// And finally we can run the install, but we have to make sure we don't
// persist the project state on the disk (otherwise all workspaces would
// lose their dependencies!).
const report = await StreamReport.start({
configuration,
json: this.json,
stdout: this.context.stdout,
includeLogs: true,
}, async (report: StreamReport) => {
await project.install({cache, report, persistProject: false});
});
return report.exitCode();
}
}