-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathcli.js
More file actions
executable file
·205 lines (183 loc) · 6.24 KB
/
cli.js
File metadata and controls
executable file
·205 lines (183 loc) · 6.24 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/usr/bin/env node
import "@babel/polyfill";
import colors from "picocolors";
import { Command } from "commander";
import { confirm } from "promptly";
import pkg from "../package.json";
import * as C from "./constants";
import hasYarn from "./has-yarn";
import { parsePackageString } from "./helpers";
import installPeerDeps from "./install-peerdeps";
// Create program object
const program = new Command("install-peerdeps");
// Get relevant package information
const { name, version } = pkg;
/**
* Error message that is printed when the program can't
* parse the package string.
*/
function printPackageFormatError() {
console.error(
`${C.errorText} Please specify the package to install with peerDeps in the form of \`package\` or \`package@n.n.n\``
);
console.error(
`${C.errorText} At this time you must provide the full semver version of the package.`
);
console.error(
`${C.errorText} Alternatively, omit it to automatically install the latest version of the package.`
);
}
// Create program
program
.version(version)
.description("Installs the specified package along with correct peerDeps.")
.option("-D", "Install the package as a devDependency (alias for `-d`)")
.option("-d, --dev", "Install the package as a devDependency")
.option("-g, --global", "Install the package globally")
.option("-o, --only-peers", "Install only peerDependencies of the package")
.option("-S, --silent", "If using npm, don't save in package.json")
.option("-Y, --yarn", "Install with Yarn")
.option("-P, --pnpm", "Install with pnpm")
.option(
"-n, --no-registry",
"Use local node_modules instead of a remote registry to get the list of peerDependencies"
)
.option(
"--dry-run",
"Do not install packages, but show the install command that will be run"
)
.option(
'-x, --extra-args "<extra_args>"',
"Extra arguments to pass through to the underlying package manager"
)
.usage("<package>[@<version>], default version is 'latest'")
.parse(process.argv);
// Print program name and version (like what Yarn does)
console.log(colors.bold(`${name} v${version}`));
// Make sure we're installing at least one package
if (program.args.length === 0) {
console.error(
`${C.errorText} Please specify a package to install with peerDeps.`
);
// An exit code of "9" indicates an invalid argument
// See https://nodejs.org/api/process.html#process_exit_codes
process.exitCode = 9;
program.help();
}
// Make sure we're installing no more than one package
if (program.args.length > 1) {
console.error(
`${C.errorText} Too many arguments. Please specify ONE package at a time to install with peerDeps. Alternatively, pass extra arguments with --extra-args "<extra_args>".`
);
// An exit code of "9" indicates an invalid argument
// See https://nodejs.org/api/process.html#process_exit_codes
process.exit(9);
}
// The first argument after the options is the name of the package
const packageString = program.args[0];
const { packageName, packageVersion } = parsePackageString(packageString);
// If we can't get a package name out,
// print the format error
if (!packageName) {
printPackageFormatError();
process.exit(9);
}
/** @type {C.npm | C.yarn | C.pnpm} */
let packageManager = C.npm; // Default package manager is npm
if (program.yarn && program.pnpm) {
console.error(
`${C.errorText} Option --yarn and --pnpm cannot be used concurrently.`
);
process.exit(9);
}
if (program.yarn) {
packageManager = C.yarn;
}
if (program.pnpm) {
packageManager = C.pnpm;
}
// Yarn does not allow silent install of dependencies
if (program.yarn && program.silent) {
console.error(`${C.errorText} Option --silent cannot be used with --yarn.`);
process.exit(9);
}
const devMode = program.dev || program.D;
// Dev option can't be used with silent,
// since --dev means it should be saved
// as a devDependency
if (devMode && program.silent) {
console.error(`${C.errorText} Option --silent cannot be used with --dev.`);
process.exit(9);
}
// Dev option can't be used with global,
// since --dev means it should be saved
// as a devDependency (locally)
if (devMode && program.silent) {
console.error(`${C.errorText} Option --dev cannot be used with --global.`);
process.exit(9);
}
// Define options object to pass to
// the installPeerDeps function
const options = {
packageName,
// If packageVersion is undefined, default to "latest"
version: packageVersion || "latest",
noRegistry: program.noRegistry,
dev: devMode,
global: program.global,
onlyPeers: program.onlyPeers,
silent: program.silent,
packageManager,
dryRun: program.dryRun,
auth: program.auth,
// Args after -- will be passed through
extraArgs: program.extraArgs || "",
};
// Disabled this rule so we can hoist the callback
/* eslint-disable no-use-before-define */
// Check if the user has Yarn but didn't specify the Yarn option
// However, don't show prompt if user wants to install silently
if (hasYarn() && packageManager !== C.yarn && !program.silent) {
// If they do, ask if they want to use Yarn
confirm(
"It seems as if you are using Yarn. Would you like to use Yarn for the installation? (y/n)"
)
.then((value) => {
// Value is true or false; if true, they want to use Yarn
if (value) {
packageManager = C.yarn;
}
// Now install, but with the new packageManager
installPeerDeps({ ...options, packageManager }, installCb);
})
.catch((err) => {
if (err) {
console.error(`${C.errorText} ${err.message}`);
process.exit(1);
}
});
} else {
// If they don't have Yarn or they've already
// opted to use Yarn, go ahead and install
installPeerDeps(options, installCb);
}
/**
* Callback which is called after the installation
* process finishes
* @callback
* @param {Error} [err] - the error, if any, that occurred during installation
*/
function installCb(err) {
if (err) {
console.error(`${C.errorText} ${err.message}`);
process.exit(1);
}
let successMessage = `${C.successText} ${packageName} and its peerDeps were installed successfully.`;
if (program.onlyPeers) {
successMessage = `${C.successText} The peerDeps of ${packageName} were installed successfully.`;
}
console.log(successMessage);
process.exit(0);
}
/* eslint-enable */
export default program;