burgee 0.0.0 → 0.2.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/README.md +28 -1
- package/dist/agent.d.ts +19 -0
- package/dist/agent.js +25 -0
- package/dist/brand.d.ts +186 -0
- package/dist/brand.js +232 -0
- package/dist/cli.d.ts +51 -0
- package/dist/cli.js +105 -0
- package/dist/commander-argument.d.ts +22 -0
- package/dist/commander-argument.js +72 -0
- package/dist/commander-command.d.ts +345 -0
- package/dist/commander-command.js +1605 -0
- package/dist/commander-error.d.ts +10 -0
- package/dist/commander-error.js +20 -0
- package/dist/commander-help.d.ts +67 -0
- package/dist/commander-help.js +319 -0
- package/dist/commander-option.d.ts +58 -0
- package/dist/commander-option.js +164 -0
- package/dist/commander-suggest.d.ts +2 -0
- package/dist/commander-suggest.js +59 -0
- package/dist/commander.d.ts +18 -0
- package/dist/commander.js +12 -0
- package/dist/completions.d.ts +39 -0
- package/dist/completions.js +224 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.js +98 -0
- package/dist/contrast.d.ts +70 -0
- package/dist/contrast.js +93 -0
- package/dist/execute.d.ts +97 -0
- package/dist/execute.js +433 -0
- package/dist/exit-code.d.ts +18 -0
- package/dist/exit-code.js +12 -0
- package/dist/help.d.ts +22 -0
- package/dist/help.js +158 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.js +9 -2
- package/dist/manifest.d.ts +192 -0
- package/dist/manifest.js +55 -0
- package/dist/mcp.d.ts +40 -0
- package/dist/mcp.js +111 -0
- package/dist/names.d.ts +5 -0
- package/dist/names.js +6 -0
- package/dist/pkg.d.ts +5 -0
- package/dist/pkg.js +21 -0
- package/dist/precedence.d.ts +55 -0
- package/dist/precedence.js +100 -0
- package/dist/runtime.d.ts +27 -0
- package/dist/runtime.js +17 -0
- package/dist/schema.d.ts +71 -0
- package/dist/schema.js +108 -0
- package/dist/testing-helpers.d.ts +62 -0
- package/dist/testing-helpers.js +110 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.js +3 -0
- package/dist/validate.d.ts +27 -0
- package/dist/validate.js +133 -0
- package/dist/yargs-burgee.d.ts +50 -0
- package/dist/yargs-burgee.js +104 -0
- package/dist/yargs-cliui.d.ts +56 -0
- package/dist/yargs-cliui.js +421 -0
- package/dist/yargs-command.d.ts +82 -0
- package/dist/yargs-command.js +414 -0
- package/dist/yargs-completion.d.ts +41 -0
- package/dist/yargs-completion.js +271 -0
- package/dist/yargs-factory.d.ts +193 -0
- package/dist/yargs-factory.js +1606 -0
- package/dist/yargs-helpers.d.ts +6 -0
- package/dist/yargs-helpers.js +2 -0
- package/dist/yargs-middleware.d.ts +32 -0
- package/dist/yargs-middleware.js +81 -0
- package/dist/yargs-parser.d.ts +41 -0
- package/dist/yargs-parser.js +929 -0
- package/dist/yargs-shim.d.ts +54 -0
- package/dist/yargs-shim.js +84 -0
- package/dist/yargs-usage.d.ts +42 -0
- package/dist/yargs-usage.js +479 -0
- package/dist/yargs-utils.d.ts +33 -0
- package/dist/yargs-utils.js +209 -0
- package/dist/yargs-validation.d.ts +26 -0
- package/dist/yargs-validation.js +261 -0
- package/dist/yargs-y18n.d.ts +21 -0
- package/dist/yargs-y18n.js +117 -0
- package/dist/yargs.d.ts +6 -0
- package/dist/yargs.js +8 -0
- package/locales/be.json +46 -0
- package/locales/cs.json +51 -0
- package/locales/de.json +46 -0
- package/locales/en.json +55 -0
- package/locales/es.json +46 -0
- package/locales/fi.json +49 -0
- package/locales/fr.json +53 -0
- package/locales/he.json +55 -0
- package/locales/hi.json +49 -0
- package/locales/hu.json +46 -0
- package/locales/id.json +50 -0
- package/locales/it.json +46 -0
- package/locales/ja.json +51 -0
- package/locales/ka.json +55 -0
- package/locales/ko.json +49 -0
- package/locales/nb.json +44 -0
- package/locales/nl.json +49 -0
- package/locales/nn.json +44 -0
- package/locales/pirate.json +13 -0
- package/locales/pl.json +49 -0
- package/locales/pt.json +45 -0
- package/locales/pt_BR.json +48 -0
- package/locales/ru.json +51 -0
- package/locales/th.json +46 -0
- package/locales/tr.json +48 -0
- package/locales/uk_UA.json +51 -0
- package/locales/uz.json +52 -0
- package/locales/zh_CN.json +48 -0
- package/locales/zh_TW.json +51 -0
- package/package.json +61 -8
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,1605 @@
|
|
|
1
|
+
import childProcess from 'node:child_process';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import { stripVTControlCharacters } from 'node:util';
|
|
7
|
+
import { Argument, humanReadableArgName } from './commander-argument.js';
|
|
8
|
+
import { CommanderError } from './commander-error.js';
|
|
9
|
+
import { Help } from './commander-help.js';
|
|
10
|
+
import { DualOptions, Option } from './commander-option.js';
|
|
11
|
+
import { suggestSimilar } from './commander-suggest.js';
|
|
12
|
+
import { ExitCode } from './exit-code.js';
|
|
13
|
+
import { Manifest } from './manifest.js';
|
|
14
|
+
import { serveMcp } from './mcp.js';
|
|
15
|
+
import { schemaOf } from './schema.js';
|
|
16
|
+
const POLLUTING = new Set(['__proto__', 'constructor', 'prototype']);
|
|
17
|
+
const ENV_SOURCES = ['default', 'config', 'env'];
|
|
18
|
+
const IMPLIED_SOURCES = ['default', 'implied'];
|
|
19
|
+
const HOOK_EVENTS = ['preSubcommand', 'preAction', 'postAction'];
|
|
20
|
+
const HELP_POSITIONS = ['beforeAll', 'before', 'after', 'afterAll'];
|
|
21
|
+
const SOURCE_EXT = ['.js', '.ts', '.tsx', '.mjs', '.cjs'];
|
|
22
|
+
const FORWARDED_SIGNALS = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
|
|
23
|
+
const quoted = (s) => `'${s}'`;
|
|
24
|
+
function isThenable(value) {
|
|
25
|
+
return typeof value?.then === 'function';
|
|
26
|
+
}
|
|
27
|
+
function e1(err) {
|
|
28
|
+
switch (err.code) {
|
|
29
|
+
case 'commander.helpDisplayed':
|
|
30
|
+
case 'commander.version':
|
|
31
|
+
return ExitCode.OK;
|
|
32
|
+
case 'commander.help':
|
|
33
|
+
return err.exitCode === 0 ? ExitCode.OK : ExitCode.USAGE;
|
|
34
|
+
case 'commander.error':
|
|
35
|
+
case 'commander.executeSubCommandAsync':
|
|
36
|
+
return err.exitCode;
|
|
37
|
+
default:
|
|
38
|
+
return err.exitCode === 1 ? ExitCode.USAGE : err.exitCode;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function render(value) {
|
|
42
|
+
if (value === undefined || value === null)
|
|
43
|
+
return '';
|
|
44
|
+
if (typeof value === 'string')
|
|
45
|
+
return `${value}\n`;
|
|
46
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
47
|
+
return Object.entries(value)
|
|
48
|
+
.map(([k, v]) => `${k}: ${typeof v === 'string' ? v : JSON.stringify(v)}\n`)
|
|
49
|
+
.join('');
|
|
50
|
+
}
|
|
51
|
+
return `${JSON.stringify(value)}\n`;
|
|
52
|
+
}
|
|
53
|
+
export class Command extends EventEmitter {
|
|
54
|
+
commands = [];
|
|
55
|
+
options = [];
|
|
56
|
+
parent = null;
|
|
57
|
+
registeredArguments = [];
|
|
58
|
+
_args;
|
|
59
|
+
args = [];
|
|
60
|
+
rawArgs = [];
|
|
61
|
+
processedArgs = [];
|
|
62
|
+
runningCommand = undefined;
|
|
63
|
+
_allowUnknownOption = false;
|
|
64
|
+
_allowExcessArguments = false;
|
|
65
|
+
_scriptPath = null;
|
|
66
|
+
_name;
|
|
67
|
+
_optionValues = {};
|
|
68
|
+
_optionValueSources = {};
|
|
69
|
+
_storeOptionsAsProperties = false;
|
|
70
|
+
_actionHandler = null;
|
|
71
|
+
_executableHandler = false;
|
|
72
|
+
_executableFile = null;
|
|
73
|
+
_executableDir = null;
|
|
74
|
+
_defaultCommandName = null;
|
|
75
|
+
_exitCallback = null;
|
|
76
|
+
_aliases = [];
|
|
77
|
+
_combineFlagAndOptionalValue = true;
|
|
78
|
+
_description = '';
|
|
79
|
+
_summary = '';
|
|
80
|
+
_argsDescription = undefined;
|
|
81
|
+
_enablePositionalOptions = false;
|
|
82
|
+
_passThroughOptions = false;
|
|
83
|
+
_lifeCycleHooks = {};
|
|
84
|
+
_showHelpAfterError = false;
|
|
85
|
+
_showSuggestionAfterError = true;
|
|
86
|
+
_savedState = null;
|
|
87
|
+
_outputConfiguration;
|
|
88
|
+
_hidden = false;
|
|
89
|
+
_helpOption = undefined;
|
|
90
|
+
_addImplicitHelpCommand = undefined;
|
|
91
|
+
_helpCommand = undefined;
|
|
92
|
+
_helpConfiguration = {};
|
|
93
|
+
_helpGroupHeading = undefined;
|
|
94
|
+
_defaultCommandGroup = undefined;
|
|
95
|
+
_defaultOptionGroup = undefined;
|
|
96
|
+
_version = undefined;
|
|
97
|
+
_versionOptionName = undefined;
|
|
98
|
+
_usage = undefined;
|
|
99
|
+
_manifest = undefined;
|
|
100
|
+
_effects = undefined;
|
|
101
|
+
_burgee = undefined;
|
|
102
|
+
constructor(name) {
|
|
103
|
+
super();
|
|
104
|
+
this._args = this.registeredArguments;
|
|
105
|
+
this._name = name || '';
|
|
106
|
+
this._outputConfiguration = {
|
|
107
|
+
writeOut: (str) => process.stdout.write(str),
|
|
108
|
+
writeErr: (str) => process.stderr.write(str),
|
|
109
|
+
outputError: (str, write) => write(str),
|
|
110
|
+
getOutHelpWidth: () => (process.stdout.isTTY ? process.stdout.columns : undefined),
|
|
111
|
+
getErrHelpWidth: () => (process.stderr.isTTY ? process.stderr.columns : undefined),
|
|
112
|
+
getOutHasColors: () => useColor() ?? (process.stdout.isTTY && process.stdout.hasColors?.()),
|
|
113
|
+
getErrHasColors: () => useColor() ?? (process.stderr.isTTY && process.stderr.hasColors?.()),
|
|
114
|
+
stripColor: (str) => stripVTControlCharacters(str),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
copyInheritedSettings(sourceCommand) {
|
|
118
|
+
this._outputConfiguration = sourceCommand._outputConfiguration;
|
|
119
|
+
this._helpOption = sourceCommand._helpOption;
|
|
120
|
+
this._helpCommand = sourceCommand._helpCommand;
|
|
121
|
+
this._helpConfiguration = sourceCommand._helpConfiguration;
|
|
122
|
+
this._exitCallback = sourceCommand._exitCallback;
|
|
123
|
+
this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
|
|
124
|
+
this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
|
|
125
|
+
this._allowExcessArguments = sourceCommand._allowExcessArguments;
|
|
126
|
+
this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
|
|
127
|
+
this._showHelpAfterError = sourceCommand._showHelpAfterError;
|
|
128
|
+
this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
_getCommandAndAncestors() {
|
|
132
|
+
const result = [];
|
|
133
|
+
for (let command = this; command; command = command.parent)
|
|
134
|
+
result.push(command);
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
|
|
138
|
+
let desc = typeof actionOptsOrExecDesc === 'string' ? actionOptsOrExecDesc : null;
|
|
139
|
+
let opts = execOpts;
|
|
140
|
+
if (typeof actionOptsOrExecDesc === 'object' && actionOptsOrExecDesc !== null) {
|
|
141
|
+
opts = actionOptsOrExecDesc;
|
|
142
|
+
desc = null;
|
|
143
|
+
}
|
|
144
|
+
opts = opts ?? {};
|
|
145
|
+
const [, name, args] = /([^ ]+) *(.*)/.exec(nameAndArgs) ?? [];
|
|
146
|
+
const cmd = this.createCommand(name);
|
|
147
|
+
if (desc) {
|
|
148
|
+
cmd.description(desc);
|
|
149
|
+
cmd._executableHandler = true;
|
|
150
|
+
}
|
|
151
|
+
if (opts.isDefault)
|
|
152
|
+
this._defaultCommandName = cmd._name;
|
|
153
|
+
cmd._hidden = !!(opts.noHelp || opts.hidden);
|
|
154
|
+
cmd._executableFile = opts.executableFile || null;
|
|
155
|
+
if (args)
|
|
156
|
+
cmd.arguments(args);
|
|
157
|
+
this._registerCommand(cmd);
|
|
158
|
+
cmd.parent = this;
|
|
159
|
+
cmd.copyInheritedSettings(this);
|
|
160
|
+
if (desc)
|
|
161
|
+
return this;
|
|
162
|
+
return cmd;
|
|
163
|
+
}
|
|
164
|
+
createCommand(name) {
|
|
165
|
+
return new Command(name);
|
|
166
|
+
}
|
|
167
|
+
createHelp() {
|
|
168
|
+
return Object.assign(new Help(), this.configureHelp());
|
|
169
|
+
}
|
|
170
|
+
configureHelp(configuration) {
|
|
171
|
+
if (configuration === undefined)
|
|
172
|
+
return this._helpConfiguration;
|
|
173
|
+
this._helpConfiguration = configuration;
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
configureOutput(configuration) {
|
|
177
|
+
if (configuration === undefined)
|
|
178
|
+
return this._outputConfiguration;
|
|
179
|
+
this._outputConfiguration = { ...this._outputConfiguration, ...configuration };
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
showHelpAfterError(displayHelp = true) {
|
|
183
|
+
this._showHelpAfterError = typeof displayHelp === 'string' ? displayHelp : !!displayHelp;
|
|
184
|
+
return this;
|
|
185
|
+
}
|
|
186
|
+
showSuggestionAfterError(displaySuggestion = true) {
|
|
187
|
+
this._showSuggestionAfterError = !!displaySuggestion;
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
addCommand(cmd, opts) {
|
|
191
|
+
if (!cmd._name) {
|
|
192
|
+
throw new Error(`Command passed to .addCommand() must have a name
|
|
193
|
+
- specify the name in Command constructor or using .name()`);
|
|
194
|
+
}
|
|
195
|
+
opts = opts ?? {};
|
|
196
|
+
if (opts.isDefault)
|
|
197
|
+
this._defaultCommandName = cmd._name;
|
|
198
|
+
if (opts.noHelp || opts.hidden)
|
|
199
|
+
cmd._hidden = true;
|
|
200
|
+
this._registerCommand(cmd);
|
|
201
|
+
cmd.parent = this;
|
|
202
|
+
cmd._checkForBrokenPassThrough();
|
|
203
|
+
return this;
|
|
204
|
+
}
|
|
205
|
+
createArgument(name, description) {
|
|
206
|
+
return new Argument(name, description);
|
|
207
|
+
}
|
|
208
|
+
argument(name, description, parseArg, defaultValue) {
|
|
209
|
+
const argument = this.createArgument(name, description);
|
|
210
|
+
if (typeof parseArg === 'function') {
|
|
211
|
+
argument.default(defaultValue).argParser(parseArg);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
argument.default(parseArg);
|
|
215
|
+
}
|
|
216
|
+
this.addArgument(argument);
|
|
217
|
+
return this;
|
|
218
|
+
}
|
|
219
|
+
arguments(names) {
|
|
220
|
+
for (const detail of names.trim().split(/ +/))
|
|
221
|
+
this.argument(detail);
|
|
222
|
+
return this;
|
|
223
|
+
}
|
|
224
|
+
addArgument(argument) {
|
|
225
|
+
const previousArgument = this.registeredArguments.slice(-1)[0];
|
|
226
|
+
if (previousArgument?.variadic) {
|
|
227
|
+
throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);
|
|
228
|
+
}
|
|
229
|
+
if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) {
|
|
230
|
+
throw new Error(`a default value for a required argument is never used: '${argument.name()}'`);
|
|
231
|
+
}
|
|
232
|
+
this.registeredArguments.push(argument);
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
helpCommand(enableOrNameAndArgs, description) {
|
|
236
|
+
if (typeof enableOrNameAndArgs === 'boolean') {
|
|
237
|
+
this._addImplicitHelpCommand = enableOrNameAndArgs;
|
|
238
|
+
if (enableOrNameAndArgs && this._defaultCommandGroup) {
|
|
239
|
+
const helpCommand = this._getHelpCommand();
|
|
240
|
+
if (helpCommand)
|
|
241
|
+
this._initCommandGroup(helpCommand);
|
|
242
|
+
}
|
|
243
|
+
return this;
|
|
244
|
+
}
|
|
245
|
+
const nameAndArgs = enableOrNameAndArgs ?? 'help [command]';
|
|
246
|
+
const [, helpName, helpArgs] = /([^ ]+) *(.*)/.exec(nameAndArgs) ?? [];
|
|
247
|
+
const helpDescription = description ?? 'display help for command';
|
|
248
|
+
const helpCommand = this.createCommand(helpName);
|
|
249
|
+
helpCommand.helpOption(false);
|
|
250
|
+
if (helpArgs)
|
|
251
|
+
helpCommand.arguments(helpArgs);
|
|
252
|
+
if (helpDescription)
|
|
253
|
+
helpCommand.description(helpDescription);
|
|
254
|
+
this._addImplicitHelpCommand = true;
|
|
255
|
+
this._helpCommand = helpCommand;
|
|
256
|
+
if (enableOrNameAndArgs || description)
|
|
257
|
+
this._initCommandGroup(helpCommand);
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
addHelpCommand(helpCommand, deprecatedDescription) {
|
|
261
|
+
if (typeof helpCommand !== 'object') {
|
|
262
|
+
this.helpCommand(helpCommand, deprecatedDescription);
|
|
263
|
+
return this;
|
|
264
|
+
}
|
|
265
|
+
this._addImplicitHelpCommand = true;
|
|
266
|
+
this._helpCommand = helpCommand;
|
|
267
|
+
this._initCommandGroup(helpCommand);
|
|
268
|
+
return this;
|
|
269
|
+
}
|
|
270
|
+
_getHelpCommand() {
|
|
271
|
+
const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand('help'));
|
|
272
|
+
if (hasImplicitHelpCommand) {
|
|
273
|
+
if (this._helpCommand === undefined)
|
|
274
|
+
this.helpCommand(undefined, undefined);
|
|
275
|
+
return this._helpCommand ?? null;
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
hook(event, listener) {
|
|
280
|
+
if (!HOOK_EVENTS.includes(event)) {
|
|
281
|
+
throw new Error(`Unexpected value for event passed to hook : '${String(event)}'.
|
|
282
|
+
Expecting one of '${HOOK_EVENTS.join("', '")}'`);
|
|
283
|
+
}
|
|
284
|
+
const hooks = this._lifeCycleHooks[event];
|
|
285
|
+
if (hooks)
|
|
286
|
+
hooks.push(listener);
|
|
287
|
+
else
|
|
288
|
+
this._lifeCycleHooks[event] = [listener];
|
|
289
|
+
return this;
|
|
290
|
+
}
|
|
291
|
+
exitOverride(fn) {
|
|
292
|
+
this._exitCallback =
|
|
293
|
+
fn ??
|
|
294
|
+
((err) => {
|
|
295
|
+
if (err.code !== 'commander.executeSubCommandAsync')
|
|
296
|
+
throw err;
|
|
297
|
+
});
|
|
298
|
+
return this;
|
|
299
|
+
}
|
|
300
|
+
_exit(exitCode, code, message) {
|
|
301
|
+
if (this._exitCallback) {
|
|
302
|
+
this._exitCallback(new CommanderError(exitCode, code, message));
|
|
303
|
+
}
|
|
304
|
+
process.exit(exitCode);
|
|
305
|
+
}
|
|
306
|
+
action(fn) {
|
|
307
|
+
const listener = (args) => {
|
|
308
|
+
const expectedArgsCount = this.registeredArguments.length;
|
|
309
|
+
const actionArgs = args.slice(0, expectedArgsCount);
|
|
310
|
+
actionArgs[expectedArgsCount] = this._storeOptionsAsProperties ? this : this.opts();
|
|
311
|
+
actionArgs.push(this);
|
|
312
|
+
return fn.apply(this, actionArgs);
|
|
313
|
+
};
|
|
314
|
+
this._actionHandler = listener;
|
|
315
|
+
return this;
|
|
316
|
+
}
|
|
317
|
+
createOption(flags, description) {
|
|
318
|
+
return new Option(flags, description);
|
|
319
|
+
}
|
|
320
|
+
_callParseArg(target, value, previous, invalidArgumentMessage) {
|
|
321
|
+
try {
|
|
322
|
+
return target.parseArg?.(value, previous);
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
const e = err;
|
|
326
|
+
if (e.code === 'commander.invalidArgument') {
|
|
327
|
+
const options = { code: e.code };
|
|
328
|
+
if (e.exitCode !== undefined)
|
|
329
|
+
options.exitCode = e.exitCode;
|
|
330
|
+
this.error(`${invalidArgumentMessage} ${e.message}`, options);
|
|
331
|
+
}
|
|
332
|
+
throw err;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
_registerOption(option) {
|
|
336
|
+
const matchingOption = (option.short && this._findOption(option.short)) || (option.long && this._findOption(option.long));
|
|
337
|
+
if (matchingOption) {
|
|
338
|
+
const matchingFlag = option.long && this._findOption(option.long) ? option.long : option.short;
|
|
339
|
+
throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
|
|
340
|
+
- already used by option '${matchingOption.flags}'`);
|
|
341
|
+
}
|
|
342
|
+
this._initOptionGroup(option);
|
|
343
|
+
this.options.push(option);
|
|
344
|
+
}
|
|
345
|
+
_registerCommand(command) {
|
|
346
|
+
const knownBy = (cmd) => [cmd.name()].concat(cmd.aliases());
|
|
347
|
+
const alreadyUsed = knownBy(command).find((name) => this._findCommand(name));
|
|
348
|
+
if (alreadyUsed) {
|
|
349
|
+
const existing = this._findCommand(alreadyUsed);
|
|
350
|
+
const existingCmd = existing ? knownBy(existing).join('|') : alreadyUsed;
|
|
351
|
+
const newCmd = knownBy(command).join('|');
|
|
352
|
+
throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`);
|
|
353
|
+
}
|
|
354
|
+
this._initCommandGroup(command);
|
|
355
|
+
this.commands.push(command);
|
|
356
|
+
}
|
|
357
|
+
addOption(option) {
|
|
358
|
+
const oname = option.name();
|
|
359
|
+
const name = option.attributeName();
|
|
360
|
+
if (POLLUTING.has(name) || POLLUTING.has(oname)) {
|
|
361
|
+
throw new Error(`burgee: option name "${oname}" is not allowed — it would reach Object.prototype`);
|
|
362
|
+
}
|
|
363
|
+
this._registerOption(option);
|
|
364
|
+
if (option.defaultValue !== undefined) {
|
|
365
|
+
this.setOptionValueWithSource(name, option.defaultValue, 'default');
|
|
366
|
+
}
|
|
367
|
+
const handleOptionValue = (val, invalidValueMessage, valueSource) => {
|
|
368
|
+
let value = val;
|
|
369
|
+
if (value == null && option.presetArg !== undefined)
|
|
370
|
+
value = option.presetArg;
|
|
371
|
+
const oldValue = this.getOptionValue(name);
|
|
372
|
+
if (value !== null && option.parseArg) {
|
|
373
|
+
value = this._callParseArg(option, value, oldValue, invalidValueMessage);
|
|
374
|
+
}
|
|
375
|
+
else if (value !== null && option.variadic) {
|
|
376
|
+
value = option._collectValue(value, oldValue);
|
|
377
|
+
}
|
|
378
|
+
if (value == null) {
|
|
379
|
+
if (option.negate)
|
|
380
|
+
value = false;
|
|
381
|
+
else if (option.isBoolean() || option.optional)
|
|
382
|
+
value = true;
|
|
383
|
+
else
|
|
384
|
+
value = '';
|
|
385
|
+
}
|
|
386
|
+
this.setOptionValueWithSource(name, value, valueSource);
|
|
387
|
+
};
|
|
388
|
+
this.on(`option:${oname}`, (val) => {
|
|
389
|
+
handleOptionValue(val, `error: option '${option.flags}' argument '${val}' is invalid.`, 'cli');
|
|
390
|
+
});
|
|
391
|
+
if (option.envVar) {
|
|
392
|
+
this.on(`optionEnv:${oname}`, (val) => {
|
|
393
|
+
handleOptionValue(val, `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`, 'env');
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return this;
|
|
397
|
+
}
|
|
398
|
+
_optionEx(config, flags, description, fn, defaultValue) {
|
|
399
|
+
if (typeof flags === 'object' && flags instanceof Option) {
|
|
400
|
+
throw new Error('To add an Option object use addOption() instead of option() or requiredOption()');
|
|
401
|
+
}
|
|
402
|
+
const option = this.createOption(flags, description);
|
|
403
|
+
option.makeOptionMandatory(!!config.mandatory);
|
|
404
|
+
if (typeof fn === 'function') {
|
|
405
|
+
option.default(defaultValue).argParser(fn);
|
|
406
|
+
}
|
|
407
|
+
else if (fn instanceof RegExp) {
|
|
408
|
+
const regex = fn;
|
|
409
|
+
option.default(defaultValue).argParser((val, def) => {
|
|
410
|
+
const m = regex.exec(val);
|
|
411
|
+
return m ? m[0] : def;
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
option.default(fn);
|
|
416
|
+
}
|
|
417
|
+
return this.addOption(option);
|
|
418
|
+
}
|
|
419
|
+
option(flags, description, parseArg, defaultValue) {
|
|
420
|
+
return this._optionEx({}, flags, description, parseArg, defaultValue);
|
|
421
|
+
}
|
|
422
|
+
requiredOption(flags, description, parseArg, defaultValue) {
|
|
423
|
+
return this._optionEx({ mandatory: true }, flags, description, parseArg, defaultValue);
|
|
424
|
+
}
|
|
425
|
+
combineFlagAndOptionalValue(combine = true) {
|
|
426
|
+
this._combineFlagAndOptionalValue = !!combine;
|
|
427
|
+
return this;
|
|
428
|
+
}
|
|
429
|
+
allowUnknownOption(allowUnknown = true) {
|
|
430
|
+
this._allowUnknownOption = !!allowUnknown;
|
|
431
|
+
return this;
|
|
432
|
+
}
|
|
433
|
+
allowExcessArguments(allowExcess = true) {
|
|
434
|
+
this._allowExcessArguments = !!allowExcess;
|
|
435
|
+
return this;
|
|
436
|
+
}
|
|
437
|
+
enablePositionalOptions(positional = true) {
|
|
438
|
+
this._enablePositionalOptions = !!positional;
|
|
439
|
+
return this;
|
|
440
|
+
}
|
|
441
|
+
passThroughOptions(passThrough = true) {
|
|
442
|
+
this._passThroughOptions = !!passThrough;
|
|
443
|
+
this._checkForBrokenPassThrough();
|
|
444
|
+
return this;
|
|
445
|
+
}
|
|
446
|
+
_checkForBrokenPassThrough() {
|
|
447
|
+
if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
|
|
448
|
+
throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
storeOptionsAsProperties(storeAsProperties = true) {
|
|
452
|
+
if (this.options.length)
|
|
453
|
+
throw new Error('call .storeOptionsAsProperties() before adding options');
|
|
454
|
+
if (Object.keys(this._optionValues).length)
|
|
455
|
+
throw new Error('call .storeOptionsAsProperties() before setting option values');
|
|
456
|
+
this._storeOptionsAsProperties = !!storeAsProperties;
|
|
457
|
+
return this;
|
|
458
|
+
}
|
|
459
|
+
getOptionValue(key) {
|
|
460
|
+
if (this._storeOptionsAsProperties)
|
|
461
|
+
return this[key];
|
|
462
|
+
return this._optionValues[key];
|
|
463
|
+
}
|
|
464
|
+
setOptionValue(key, value) {
|
|
465
|
+
return this.setOptionValueWithSource(key, value, undefined);
|
|
466
|
+
}
|
|
467
|
+
setOptionValueWithSource(key, value, source) {
|
|
468
|
+
if (this._storeOptionsAsProperties)
|
|
469
|
+
this[key] = value;
|
|
470
|
+
else
|
|
471
|
+
this._optionValues[key] = value;
|
|
472
|
+
this._optionValueSources[key] = source;
|
|
473
|
+
return this;
|
|
474
|
+
}
|
|
475
|
+
getOptionValueSource(key) {
|
|
476
|
+
return this._optionValueSources[key];
|
|
477
|
+
}
|
|
478
|
+
getOptionValueSourceWithGlobals(key) {
|
|
479
|
+
let source;
|
|
480
|
+
for (const cmd of this._getCommandAndAncestors()) {
|
|
481
|
+
if (cmd.getOptionValueSource(key) !== undefined)
|
|
482
|
+
source = cmd.getOptionValueSource(key);
|
|
483
|
+
}
|
|
484
|
+
return source;
|
|
485
|
+
}
|
|
486
|
+
_prepareUserArgs(argv, parseOptions) {
|
|
487
|
+
if (argv !== undefined && !Array.isArray(argv))
|
|
488
|
+
throw new Error('first parameter to parse must be array or undefined');
|
|
489
|
+
parseOptions = parseOptions ?? {};
|
|
490
|
+
if (argv === undefined && parseOptions.from === undefined) {
|
|
491
|
+
if (process.versions['electron'])
|
|
492
|
+
parseOptions.from = 'electron';
|
|
493
|
+
const execArgv = process.execArgv ?? [];
|
|
494
|
+
if (execArgv.includes('-e') || execArgv.includes('--eval') || execArgv.includes('-p') || execArgv.includes('--print')) {
|
|
495
|
+
parseOptions.from = 'eval';
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
if (argv === undefined)
|
|
499
|
+
argv = process.argv;
|
|
500
|
+
this.rawArgs = argv.slice();
|
|
501
|
+
let userArgs;
|
|
502
|
+
switch (parseOptions.from) {
|
|
503
|
+
case undefined:
|
|
504
|
+
case 'node':
|
|
505
|
+
this._scriptPath = argv[1] ?? null;
|
|
506
|
+
userArgs = argv.slice(2);
|
|
507
|
+
break;
|
|
508
|
+
case 'electron':
|
|
509
|
+
if (process.defaultApp) {
|
|
510
|
+
this._scriptPath = argv[1] ?? null;
|
|
511
|
+
userArgs = argv.slice(2);
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
userArgs = argv.slice(1);
|
|
515
|
+
}
|
|
516
|
+
break;
|
|
517
|
+
case 'user':
|
|
518
|
+
userArgs = argv.slice(0);
|
|
519
|
+
break;
|
|
520
|
+
case 'eval':
|
|
521
|
+
userArgs = argv.slice(1);
|
|
522
|
+
break;
|
|
523
|
+
default:
|
|
524
|
+
throw new Error(`unexpected parse option { from: '${String(parseOptions.from)}' }`);
|
|
525
|
+
}
|
|
526
|
+
if (!this._name && this._scriptPath)
|
|
527
|
+
this.nameFromFilename(this._scriptPath);
|
|
528
|
+
this._name = this._name || 'program';
|
|
529
|
+
return userArgs;
|
|
530
|
+
}
|
|
531
|
+
parse(argv, parseOptions) {
|
|
532
|
+
const from = this._prepareBurgee(parseOptions);
|
|
533
|
+
this._prepareForParse();
|
|
534
|
+
const userArgs = this._prepareUserArgs(argv, from);
|
|
535
|
+
this._runBurgee(() => {
|
|
536
|
+
const served = this._burgeeSurface(userArgs);
|
|
537
|
+
if (isThenable(served))
|
|
538
|
+
return served.then((s) => (s ? undefined : this._parseCommand([], userArgs)));
|
|
539
|
+
return served ? undefined : this._parseCommand([], userArgs);
|
|
540
|
+
});
|
|
541
|
+
return this;
|
|
542
|
+
}
|
|
543
|
+
async parseAsync(argv, parseOptions) {
|
|
544
|
+
const from = this._prepareBurgee(parseOptions);
|
|
545
|
+
this._prepareForParse();
|
|
546
|
+
const userArgs = this._prepareUserArgs(argv, from);
|
|
547
|
+
await this._runBurgee(() => {
|
|
548
|
+
const served = this._burgeeSurface(userArgs);
|
|
549
|
+
if (isThenable(served))
|
|
550
|
+
return served.then((s) => (s ? undefined : this._parseCommand([], userArgs)));
|
|
551
|
+
return served ? undefined : this._parseCommand([], userArgs);
|
|
552
|
+
});
|
|
553
|
+
return this;
|
|
554
|
+
}
|
|
555
|
+
_prepareForParse() {
|
|
556
|
+
if (this._savedState === null) {
|
|
557
|
+
for (const option of this.options) {
|
|
558
|
+
if (option.negate && option.defaultValue === undefined && this.getOptionValue(option.attributeName()) === undefined) {
|
|
559
|
+
const positiveLongFlag = (option.long ?? '').replace(/^--no-/, '--');
|
|
560
|
+
if (!this._findOption(positiveLongFlag))
|
|
561
|
+
this.setOptionValueWithSource(option.attributeName(), true, 'default');
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
this.saveStateBeforeParse();
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
this.restoreStateBeforeParse();
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
saveStateBeforeParse() {
|
|
571
|
+
this._savedState = {
|
|
572
|
+
_name: this._name,
|
|
573
|
+
_optionValues: { ...this._optionValues },
|
|
574
|
+
_optionValueSources: { ...this._optionValueSources },
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
restoreStateBeforeParse() {
|
|
578
|
+
if (this._storeOptionsAsProperties) {
|
|
579
|
+
throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
|
|
580
|
+
- either make a new Command for each call to parse, or stop storing options as properties`);
|
|
581
|
+
}
|
|
582
|
+
const saved = this._savedState;
|
|
583
|
+
if (saved === null)
|
|
584
|
+
return;
|
|
585
|
+
this._name = saved._name;
|
|
586
|
+
this._scriptPath = null;
|
|
587
|
+
this.rawArgs = [];
|
|
588
|
+
this._optionValues = { ...saved._optionValues };
|
|
589
|
+
this._optionValueSources = { ...saved._optionValueSources };
|
|
590
|
+
this.args = [];
|
|
591
|
+
this.processedArgs = [];
|
|
592
|
+
}
|
|
593
|
+
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
594
|
+
if (fs.existsSync(executableFile))
|
|
595
|
+
return;
|
|
596
|
+
const executableDirMessage = executableDir
|
|
597
|
+
? `searched for local subcommand relative to directory '${executableDir}'`
|
|
598
|
+
: 'no directory for search for local subcommand, use .executableDir() to supply a custom directory';
|
|
599
|
+
throw new Error(`'${executableFile}' does not exist
|
|
600
|
+
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from ${quoted('.command()')} and use '.description()' instead
|
|
601
|
+
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
602
|
+
- ${executableDirMessage}`);
|
|
603
|
+
}
|
|
604
|
+
_executeSubCommand(subcommand, args) {
|
|
605
|
+
args = args.slice();
|
|
606
|
+
const findFile = (baseDir, baseName) => {
|
|
607
|
+
const localBin = path.resolve(baseDir, baseName);
|
|
608
|
+
if (fs.existsSync(localBin))
|
|
609
|
+
return localBin;
|
|
610
|
+
if (SOURCE_EXT.includes(path.extname(baseName)))
|
|
611
|
+
return undefined;
|
|
612
|
+
const foundExt = SOURCE_EXT.find((ext) => fs.existsSync(`${localBin}${ext}`));
|
|
613
|
+
return foundExt ? `${localBin}${foundExt}` : undefined;
|
|
614
|
+
};
|
|
615
|
+
this._checkForMissingMandatoryOptions();
|
|
616
|
+
this._checkForConflictingOptions();
|
|
617
|
+
let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
|
|
618
|
+
let executableDir = this._executableDir || '';
|
|
619
|
+
if (this._scriptPath) {
|
|
620
|
+
let resolvedScriptPath;
|
|
621
|
+
try {
|
|
622
|
+
resolvedScriptPath = fs.realpathSync(this._scriptPath);
|
|
623
|
+
}
|
|
624
|
+
catch {
|
|
625
|
+
resolvedScriptPath = this._scriptPath;
|
|
626
|
+
}
|
|
627
|
+
executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir);
|
|
628
|
+
}
|
|
629
|
+
if (executableDir) {
|
|
630
|
+
let localFile = findFile(executableDir, executableFile);
|
|
631
|
+
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
632
|
+
const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath));
|
|
633
|
+
if (legacyName !== this._name)
|
|
634
|
+
localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
|
|
635
|
+
}
|
|
636
|
+
executableFile = localFile || executableFile;
|
|
637
|
+
}
|
|
638
|
+
const launchWithNode = SOURCE_EXT.includes(path.extname(executableFile));
|
|
639
|
+
let proc;
|
|
640
|
+
if (process.platform !== 'win32') {
|
|
641
|
+
if (launchWithNode) {
|
|
642
|
+
args.unshift(executableFile);
|
|
643
|
+
args = incrementNodeInspectorPort(process.execArgv).concat(args);
|
|
644
|
+
proc = childProcess.spawn(process.argv[0] ?? process.execPath, args, { stdio: 'inherit' });
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
proc = childProcess.spawn(executableFile, args, { stdio: 'inherit' });
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
|
|
652
|
+
args.unshift(executableFile);
|
|
653
|
+
args = incrementNodeInspectorPort(process.execArgv).concat(args);
|
|
654
|
+
proc = childProcess.spawn(process.execPath, args, { stdio: 'inherit' });
|
|
655
|
+
}
|
|
656
|
+
if (!proc.killed) {
|
|
657
|
+
for (const signal of FORWARDED_SIGNALS) {
|
|
658
|
+
process.on(signal, () => {
|
|
659
|
+
if (proc.killed === false && proc.exitCode === null)
|
|
660
|
+
proc.kill(signal);
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
const exitCallback = this._exitCallback;
|
|
665
|
+
proc.on('close', (code) => {
|
|
666
|
+
code = code ?? 1;
|
|
667
|
+
if (!exitCallback)
|
|
668
|
+
process.exit(code);
|
|
669
|
+
else
|
|
670
|
+
exitCallback(new CommanderError(code, 'commander.executeSubCommandAsync', '(close)'));
|
|
671
|
+
});
|
|
672
|
+
proc.on('error', (err) => {
|
|
673
|
+
if (err.code === 'ENOENT') {
|
|
674
|
+
this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
|
|
675
|
+
}
|
|
676
|
+
else if (err.code === 'EACCES') {
|
|
677
|
+
throw new Error(`'${executableFile}' not executable`);
|
|
678
|
+
}
|
|
679
|
+
if (!exitCallback) {
|
|
680
|
+
process.exit(1);
|
|
681
|
+
}
|
|
682
|
+
else {
|
|
683
|
+
const wrappedError = new CommanderError(1, 'commander.executeSubCommandAsync', '(error)');
|
|
684
|
+
wrappedError.nestedError = err;
|
|
685
|
+
exitCallback(wrappedError);
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
this.runningCommand = proc;
|
|
689
|
+
}
|
|
690
|
+
_dispatchSubcommand(commandName, operands, unknown) {
|
|
691
|
+
const subCommand = this._findCommand(commandName);
|
|
692
|
+
if (!subCommand)
|
|
693
|
+
this.help({ error: true });
|
|
694
|
+
subCommand._prepareForParse();
|
|
695
|
+
let promiseChain;
|
|
696
|
+
promiseChain = this._chainOrCallSubCommandHook(promiseChain, subCommand, 'preSubcommand');
|
|
697
|
+
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
698
|
+
if (subCommand._executableHandler) {
|
|
699
|
+
this._executeSubCommand(subCommand, operands.concat(unknown));
|
|
700
|
+
return undefined;
|
|
701
|
+
}
|
|
702
|
+
return subCommand._parseCommand(operands, unknown);
|
|
703
|
+
});
|
|
704
|
+
return promiseChain;
|
|
705
|
+
}
|
|
706
|
+
_dispatchHelpCommand(subcommandName) {
|
|
707
|
+
if (!subcommandName)
|
|
708
|
+
this.help();
|
|
709
|
+
const subCommand = this._findCommand(subcommandName);
|
|
710
|
+
if (subCommand && !subCommand._executableHandler)
|
|
711
|
+
subCommand.help();
|
|
712
|
+
return this._dispatchSubcommand(subcommandName ?? '', [], [
|
|
713
|
+
this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? '--help',
|
|
714
|
+
]);
|
|
715
|
+
}
|
|
716
|
+
_checkNumberOfArguments() {
|
|
717
|
+
this.registeredArguments.forEach((arg, i) => {
|
|
718
|
+
if (arg.required && this.args[i] == null)
|
|
719
|
+
this.missingArgument(arg.name());
|
|
720
|
+
});
|
|
721
|
+
const last = this.registeredArguments[this.registeredArguments.length - 1];
|
|
722
|
+
if (this.registeredArguments.length > 0 && last?.variadic)
|
|
723
|
+
return;
|
|
724
|
+
if (this.args.length > this.registeredArguments.length)
|
|
725
|
+
this._excessArguments(this.args);
|
|
726
|
+
}
|
|
727
|
+
_processArguments() {
|
|
728
|
+
const myParseArg = (argument, value, previous) => {
|
|
729
|
+
let parsedValue = value;
|
|
730
|
+
if (value !== null && argument.parseArg) {
|
|
731
|
+
const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
|
|
732
|
+
parsedValue = this._callParseArg(argument, value, previous, invalidValueMessage);
|
|
733
|
+
}
|
|
734
|
+
return parsedValue;
|
|
735
|
+
};
|
|
736
|
+
this._checkNumberOfArguments();
|
|
737
|
+
const processedArgs = [];
|
|
738
|
+
this.registeredArguments.forEach((declaredArg, index) => {
|
|
739
|
+
let value = declaredArg.defaultValue;
|
|
740
|
+
if (declaredArg.variadic) {
|
|
741
|
+
if (index < this.args.length) {
|
|
742
|
+
const rest = this.args.slice(index);
|
|
743
|
+
value = declaredArg.parseArg
|
|
744
|
+
? rest.reduce((processed, v) => myParseArg(declaredArg, v, processed), declaredArg.defaultValue)
|
|
745
|
+
: rest;
|
|
746
|
+
}
|
|
747
|
+
else if (value === undefined) {
|
|
748
|
+
value = [];
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
else if (index < this.args.length) {
|
|
752
|
+
const raw = this.args[index] ?? '';
|
|
753
|
+
value = declaredArg.parseArg ? myParseArg(declaredArg, raw, declaredArg.defaultValue) : raw;
|
|
754
|
+
}
|
|
755
|
+
processedArgs[index] = value;
|
|
756
|
+
});
|
|
757
|
+
this.processedArgs = processedArgs;
|
|
758
|
+
}
|
|
759
|
+
_chainOrCall(promise, fn) {
|
|
760
|
+
if (isThenable(promise))
|
|
761
|
+
return promise.then(() => fn());
|
|
762
|
+
return fn();
|
|
763
|
+
}
|
|
764
|
+
_chainOrCallHooks(promise, event) {
|
|
765
|
+
let result = promise;
|
|
766
|
+
const hooks = [];
|
|
767
|
+
for (const hookedCommand of this._getCommandAndAncestors().reverse()) {
|
|
768
|
+
for (const callback of hookedCommand._lifeCycleHooks[event] ?? [])
|
|
769
|
+
hooks.push({ hookedCommand, callback });
|
|
770
|
+
}
|
|
771
|
+
if (event === 'postAction')
|
|
772
|
+
hooks.reverse();
|
|
773
|
+
for (const hookDetail of hooks) {
|
|
774
|
+
result = this._chainOrCall(result, () => hookDetail.callback(hookDetail.hookedCommand, this));
|
|
775
|
+
}
|
|
776
|
+
return result;
|
|
777
|
+
}
|
|
778
|
+
_chainOrCallSubCommandHook(promise, subCommand, event) {
|
|
779
|
+
let result = promise;
|
|
780
|
+
for (const hook of this._lifeCycleHooks[event] ?? []) {
|
|
781
|
+
result = this._chainOrCall(result, () => hook(this, subCommand));
|
|
782
|
+
}
|
|
783
|
+
return result;
|
|
784
|
+
}
|
|
785
|
+
_parseCommand(operands, unknown) {
|
|
786
|
+
const parsed = this.parseOptions(unknown);
|
|
787
|
+
this._parseOptionsEnv();
|
|
788
|
+
this._parseOptionsImplied();
|
|
789
|
+
operands = operands.concat(parsed.operands);
|
|
790
|
+
unknown = parsed.unknown;
|
|
791
|
+
if (this._actionHandler && !this._findCommand(operands[0]) && !this._defaultCommandName)
|
|
792
|
+
this._takeJson(unknown);
|
|
793
|
+
this.args = operands.concat(unknown);
|
|
794
|
+
if (operands && this._findCommand(operands[0])) {
|
|
795
|
+
return this._dispatchSubcommand(operands[0] ?? '', operands.slice(1), unknown);
|
|
796
|
+
}
|
|
797
|
+
const helpCommand = this._getHelpCommand();
|
|
798
|
+
if (helpCommand && operands[0] === helpCommand.name()) {
|
|
799
|
+
return this._dispatchHelpCommand(operands[1]);
|
|
800
|
+
}
|
|
801
|
+
if (this._defaultCommandName) {
|
|
802
|
+
this._outputHelpIfRequested(unknown);
|
|
803
|
+
return this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
|
|
804
|
+
}
|
|
805
|
+
if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
|
|
806
|
+
this.help({ error: true });
|
|
807
|
+
}
|
|
808
|
+
this._outputHelpIfRequested(parsed.unknown);
|
|
809
|
+
this._checkForMissingMandatoryOptions();
|
|
810
|
+
this._checkForConflictingOptions();
|
|
811
|
+
const checkForUnknownOptions = () => {
|
|
812
|
+
if (parsed.unknown.length > 0)
|
|
813
|
+
this.unknownOption(parsed.unknown[0] ?? '');
|
|
814
|
+
};
|
|
815
|
+
const commandEvent = `command:${this.name()}`;
|
|
816
|
+
if (this._actionHandler) {
|
|
817
|
+
checkForUnknownOptions();
|
|
818
|
+
this._processArguments();
|
|
819
|
+
let promiseChain;
|
|
820
|
+
promiseChain = this._chainOrCallHooks(promiseChain, 'preAction');
|
|
821
|
+
promiseChain = this._chainOrCall(promiseChain, () => this._runAction());
|
|
822
|
+
if (this.parent) {
|
|
823
|
+
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
824
|
+
this.parent?.emit(commandEvent, operands, unknown);
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
promiseChain = this._chainOrCallHooks(promiseChain, 'postAction');
|
|
828
|
+
return promiseChain;
|
|
829
|
+
}
|
|
830
|
+
if (this.parent?.listenerCount(commandEvent)) {
|
|
831
|
+
checkForUnknownOptions();
|
|
832
|
+
this._processArguments();
|
|
833
|
+
this.parent.emit(commandEvent, operands, unknown);
|
|
834
|
+
}
|
|
835
|
+
else if (operands.length) {
|
|
836
|
+
if (this._findCommand('*')) {
|
|
837
|
+
return this._dispatchSubcommand('*', operands, unknown);
|
|
838
|
+
}
|
|
839
|
+
if (this.listenerCount('command:*')) {
|
|
840
|
+
this.emit('command:*', operands, unknown);
|
|
841
|
+
}
|
|
842
|
+
else if (this.commands.length) {
|
|
843
|
+
this.unknownCommand();
|
|
844
|
+
}
|
|
845
|
+
else {
|
|
846
|
+
checkForUnknownOptions();
|
|
847
|
+
this._processArguments();
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
else if (this.commands.length) {
|
|
851
|
+
checkForUnknownOptions();
|
|
852
|
+
this.help({ error: true });
|
|
853
|
+
}
|
|
854
|
+
else {
|
|
855
|
+
checkForUnknownOptions();
|
|
856
|
+
this._processArguments();
|
|
857
|
+
}
|
|
858
|
+
return undefined;
|
|
859
|
+
}
|
|
860
|
+
_findCommand(name) {
|
|
861
|
+
if (!name)
|
|
862
|
+
return undefined;
|
|
863
|
+
return this.commands.find((cmd) => cmd._name === name || cmd._aliases.includes(name));
|
|
864
|
+
}
|
|
865
|
+
_findOption(arg) {
|
|
866
|
+
return this.options.find((option) => option.is(arg));
|
|
867
|
+
}
|
|
868
|
+
_checkForMissingMandatoryOptions() {
|
|
869
|
+
for (const cmd of this._getCommandAndAncestors()) {
|
|
870
|
+
for (const anOption of cmd.options) {
|
|
871
|
+
if (anOption.mandatory && cmd.getOptionValue(anOption.attributeName()) === undefined) {
|
|
872
|
+
cmd.missingMandatoryOptionValue(anOption);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
_checkForConflictingLocalOptions() {
|
|
878
|
+
const definedNonDefaultOptions = this.options.filter((option) => {
|
|
879
|
+
const optionKey = option.attributeName();
|
|
880
|
+
if (this.getOptionValue(optionKey) === undefined)
|
|
881
|
+
return false;
|
|
882
|
+
return this.getOptionValueSource(optionKey) !== 'default';
|
|
883
|
+
});
|
|
884
|
+
const optionsWithConflicting = definedNonDefaultOptions.filter((option) => option.conflictsWith.length > 0);
|
|
885
|
+
for (const option of optionsWithConflicting) {
|
|
886
|
+
const conflictingAndDefined = definedNonDefaultOptions.find((defined) => option.conflictsWith.includes(defined.attributeName()));
|
|
887
|
+
if (conflictingAndDefined)
|
|
888
|
+
this._conflictingOption(option, conflictingAndDefined);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
_checkForConflictingOptions() {
|
|
892
|
+
for (const cmd of this._getCommandAndAncestors())
|
|
893
|
+
cmd._checkForConflictingLocalOptions();
|
|
894
|
+
}
|
|
895
|
+
parseOptions(args) {
|
|
896
|
+
const operands = [];
|
|
897
|
+
const unknown = [];
|
|
898
|
+
let dest = operands;
|
|
899
|
+
const maybeOption = (arg) => arg.length > 1 && arg[0] === '-';
|
|
900
|
+
const negativeNumberArg = (arg) => {
|
|
901
|
+
if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg))
|
|
902
|
+
return false;
|
|
903
|
+
return !this._getCommandAndAncestors().some((cmd) => cmd.options.some((opt) => /^-\d$/.test(opt.short ?? '')));
|
|
904
|
+
};
|
|
905
|
+
let activeVariadicOption = null;
|
|
906
|
+
let activeGroup = null;
|
|
907
|
+
let i = 0;
|
|
908
|
+
while (i < args.length || activeGroup) {
|
|
909
|
+
const arg = activeGroup ?? args[i++] ?? '';
|
|
910
|
+
activeGroup = null;
|
|
911
|
+
if (arg === '--') {
|
|
912
|
+
if (dest === unknown)
|
|
913
|
+
dest.push(arg);
|
|
914
|
+
dest.push(...args.slice(i));
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
if (activeVariadicOption && (!maybeOption(arg) || negativeNumberArg(arg))) {
|
|
918
|
+
this.emit(`option:${activeVariadicOption.name()}`, arg);
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
activeVariadicOption = null;
|
|
922
|
+
if (maybeOption(arg)) {
|
|
923
|
+
const option = this._findOption(arg);
|
|
924
|
+
if (option) {
|
|
925
|
+
if (option.required) {
|
|
926
|
+
const value = args[i++];
|
|
927
|
+
if (value === undefined)
|
|
928
|
+
this.optionMissingArgument(option);
|
|
929
|
+
this.emit(`option:${option.name()}`, value);
|
|
930
|
+
}
|
|
931
|
+
else if (option.optional) {
|
|
932
|
+
let value = null;
|
|
933
|
+
const next = args[i];
|
|
934
|
+
if (i < args.length && next !== undefined && (!maybeOption(next) || negativeNumberArg(next))) {
|
|
935
|
+
value = next;
|
|
936
|
+
i++;
|
|
937
|
+
}
|
|
938
|
+
this.emit(`option:${option.name()}`, value);
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
this.emit(`option:${option.name()}`);
|
|
942
|
+
}
|
|
943
|
+
activeVariadicOption = option.variadic ? option : null;
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
|
|
948
|
+
const option = this._findOption(`-${arg[1]}`);
|
|
949
|
+
if (option) {
|
|
950
|
+
if (option.required || (option.optional && this._combineFlagAndOptionalValue)) {
|
|
951
|
+
this.emit(`option:${option.name()}`, arg.slice(2));
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
this.emit(`option:${option.name()}`);
|
|
955
|
+
activeGroup = `-${arg.slice(2)}`;
|
|
956
|
+
}
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
if (/^--[^=]+=/.test(arg)) {
|
|
961
|
+
const index = arg.indexOf('=');
|
|
962
|
+
const option = this._findOption(arg.slice(0, index));
|
|
963
|
+
if (option && (option.required || option.optional)) {
|
|
964
|
+
this.emit(`option:${option.name()}`, arg.slice(index + 1));
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
|
|
969
|
+
dest = unknown;
|
|
970
|
+
}
|
|
971
|
+
if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
|
|
972
|
+
if (this._findCommand(arg)) {
|
|
973
|
+
operands.push(arg);
|
|
974
|
+
unknown.push(...args.slice(i));
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
977
|
+
else if (arg === this._getHelpCommand()?.name()) {
|
|
978
|
+
operands.push(arg, ...args.slice(i));
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
else if (this._defaultCommandName) {
|
|
982
|
+
unknown.push(arg, ...args.slice(i));
|
|
983
|
+
break;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
if (this._passThroughOptions) {
|
|
987
|
+
dest.push(arg, ...args.slice(i));
|
|
988
|
+
break;
|
|
989
|
+
}
|
|
990
|
+
dest.push(arg);
|
|
991
|
+
}
|
|
992
|
+
return { operands, unknown };
|
|
993
|
+
}
|
|
994
|
+
opts() {
|
|
995
|
+
if (this._storeOptionsAsProperties) {
|
|
996
|
+
const result = {};
|
|
997
|
+
for (const option of this.options) {
|
|
998
|
+
const key = option.attributeName();
|
|
999
|
+
result[key] = key === this._versionOptionName ? this._version : this[key];
|
|
1000
|
+
}
|
|
1001
|
+
return result;
|
|
1002
|
+
}
|
|
1003
|
+
return this._optionValues;
|
|
1004
|
+
}
|
|
1005
|
+
optsWithGlobals() {
|
|
1006
|
+
return this._getCommandAndAncestors().reduce((combined, cmd) => Object.assign(combined, cmd.opts()), {});
|
|
1007
|
+
}
|
|
1008
|
+
error(message, errorOptions) {
|
|
1009
|
+
this._outputConfiguration.outputError(`${message}\n`, this._outputConfiguration.writeErr);
|
|
1010
|
+
if (typeof this._showHelpAfterError === 'string') {
|
|
1011
|
+
this._outputConfiguration.writeErr(`${this._showHelpAfterError}\n`);
|
|
1012
|
+
}
|
|
1013
|
+
else if (this._showHelpAfterError) {
|
|
1014
|
+
this._outputConfiguration.writeErr('\n');
|
|
1015
|
+
this.outputHelp({ error: true });
|
|
1016
|
+
}
|
|
1017
|
+
const config = errorOptions ?? {};
|
|
1018
|
+
const exitCode = config.exitCode || 1;
|
|
1019
|
+
const code = config.code || 'commander.error';
|
|
1020
|
+
this._exit(exitCode, code, message);
|
|
1021
|
+
}
|
|
1022
|
+
_parseOptionsEnv() {
|
|
1023
|
+
for (const option of this.options) {
|
|
1024
|
+
if (option.envVar && option.envVar in process.env) {
|
|
1025
|
+
const optionKey = option.attributeName();
|
|
1026
|
+
if (this.getOptionValue(optionKey) === undefined || ENV_SOURCES.includes(this.getOptionValueSource(optionKey) ?? '')) {
|
|
1027
|
+
if (option.required || option.optional)
|
|
1028
|
+
this.emit(`optionEnv:${option.name()}`, process.env[option.envVar]);
|
|
1029
|
+
else
|
|
1030
|
+
this.emit(`optionEnv:${option.name()}`);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
_parseOptionsImplied() {
|
|
1036
|
+
const dualHelper = new DualOptions(this.options);
|
|
1037
|
+
const hasCustomOptionValue = (optionKey) => this.getOptionValue(optionKey) !== undefined && !IMPLIED_SOURCES.includes(this.getOptionValueSource(optionKey) ?? '');
|
|
1038
|
+
const implying = this.options.filter((option) => option.implied !== undefined &&
|
|
1039
|
+
hasCustomOptionValue(option.attributeName()) &&
|
|
1040
|
+
dualHelper.valueFromOption(this.getOptionValue(option.attributeName()), option));
|
|
1041
|
+
for (const option of implying) {
|
|
1042
|
+
for (const impliedKey of Object.keys(option.implied ?? {})) {
|
|
1043
|
+
if (!hasCustomOptionValue(impliedKey))
|
|
1044
|
+
this.setOptionValueWithSource(impliedKey, option.implied?.[impliedKey], 'implied');
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
missingArgument(name) {
|
|
1049
|
+
this.error(`error: missing required argument '${name}'`, { code: 'commander.missingArgument' });
|
|
1050
|
+
}
|
|
1051
|
+
optionMissingArgument(option) {
|
|
1052
|
+
this.error(`error: option '${option.flags}' argument missing`, { code: 'commander.optionMissingArgument' });
|
|
1053
|
+
}
|
|
1054
|
+
missingMandatoryOptionValue(option) {
|
|
1055
|
+
this.error(`error: required option '${option.flags}' not specified`, { code: 'commander.missingMandatoryOptionValue' });
|
|
1056
|
+
}
|
|
1057
|
+
_conflictingOption(option, conflictingOption) {
|
|
1058
|
+
const findBestOptionFromValue = (candidate) => {
|
|
1059
|
+
const optionKey = candidate.attributeName();
|
|
1060
|
+
const optionValue = this.getOptionValue(optionKey);
|
|
1061
|
+
const negativeOption = this.options.find((target) => target.negate && optionKey === target.attributeName());
|
|
1062
|
+
const positiveOption = this.options.find((target) => !target.negate && optionKey === target.attributeName());
|
|
1063
|
+
if (negativeOption &&
|
|
1064
|
+
((negativeOption.presetArg === undefined && optionValue === false) ||
|
|
1065
|
+
(negativeOption.presetArg !== undefined && optionValue === negativeOption.presetArg))) {
|
|
1066
|
+
return negativeOption;
|
|
1067
|
+
}
|
|
1068
|
+
return positiveOption ?? candidate;
|
|
1069
|
+
};
|
|
1070
|
+
const getErrorMessage = (candidate) => {
|
|
1071
|
+
const bestOption = findBestOptionFromValue(candidate);
|
|
1072
|
+
const source = this.getOptionValueSource(bestOption.attributeName());
|
|
1073
|
+
if (source === 'env')
|
|
1074
|
+
return `environment variable '${bestOption.envVar}'`;
|
|
1075
|
+
return `option '${bestOption.flags}'`;
|
|
1076
|
+
};
|
|
1077
|
+
const message = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
|
|
1078
|
+
this.error(message, { code: 'commander.conflictingOption' });
|
|
1079
|
+
}
|
|
1080
|
+
unknownOption(flag) {
|
|
1081
|
+
if (this._allowUnknownOption)
|
|
1082
|
+
return;
|
|
1083
|
+
let suggestion = '';
|
|
1084
|
+
if (flag.startsWith('--') && this._showSuggestionAfterError) {
|
|
1085
|
+
let candidateFlags = [];
|
|
1086
|
+
let command = this;
|
|
1087
|
+
do {
|
|
1088
|
+
const moreFlags = command
|
|
1089
|
+
.createHelp()
|
|
1090
|
+
.visibleOptions(command)
|
|
1091
|
+
.filter((option) => option.long)
|
|
1092
|
+
.map((option) => option.long ?? '');
|
|
1093
|
+
candidateFlags = candidateFlags.concat(moreFlags);
|
|
1094
|
+
command = command.parent;
|
|
1095
|
+
} while (command && !command._enablePositionalOptions);
|
|
1096
|
+
suggestion = suggestSimilar(flag, candidateFlags);
|
|
1097
|
+
}
|
|
1098
|
+
this.error(`error: unknown option '${flag}'${suggestion}`, { code: 'commander.unknownOption' });
|
|
1099
|
+
}
|
|
1100
|
+
_excessArguments(receivedArgs) {
|
|
1101
|
+
if (this._allowExcessArguments)
|
|
1102
|
+
return;
|
|
1103
|
+
const expected = this.registeredArguments.length;
|
|
1104
|
+
const s = expected === 1 ? '' : 's';
|
|
1105
|
+
const received = receivedArgs.length;
|
|
1106
|
+
const forSubcommand = this.parent ? ` for '${this.name()}'` : '';
|
|
1107
|
+
const details = receivedArgs.join(', ');
|
|
1108
|
+
const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${received}: ${details}.`;
|
|
1109
|
+
this.error(message, { code: 'commander.excessArguments' });
|
|
1110
|
+
}
|
|
1111
|
+
unknownCommand() {
|
|
1112
|
+
const unknownName = this.args[0] ?? '';
|
|
1113
|
+
let suggestion = '';
|
|
1114
|
+
if (this._showSuggestionAfterError) {
|
|
1115
|
+
const candidateNames = [];
|
|
1116
|
+
for (const command of this.createHelp().visibleCommands(this)) {
|
|
1117
|
+
candidateNames.push(command.name());
|
|
1118
|
+
const alias = command.alias();
|
|
1119
|
+
if (alias)
|
|
1120
|
+
candidateNames.push(alias);
|
|
1121
|
+
}
|
|
1122
|
+
suggestion = suggestSimilar(unknownName, candidateNames);
|
|
1123
|
+
}
|
|
1124
|
+
this.error(`error: unknown command '${unknownName}'${suggestion}`, { code: 'commander.unknownCommand' });
|
|
1125
|
+
}
|
|
1126
|
+
version(str, flags, description) {
|
|
1127
|
+
if (str === undefined)
|
|
1128
|
+
return this._version;
|
|
1129
|
+
this._version = str;
|
|
1130
|
+
flags = flags || '-V, --version';
|
|
1131
|
+
description = description || 'output the version number';
|
|
1132
|
+
const versionOption = this.createOption(flags, description);
|
|
1133
|
+
this._versionOptionName = versionOption.attributeName();
|
|
1134
|
+
this._registerOption(versionOption);
|
|
1135
|
+
this.on(`option:${versionOption.name()}`, () => {
|
|
1136
|
+
this._outputConfiguration.writeOut(`${str}\n`);
|
|
1137
|
+
this._exit(0, 'commander.version', str);
|
|
1138
|
+
});
|
|
1139
|
+
return this;
|
|
1140
|
+
}
|
|
1141
|
+
description(str, argsDescription) {
|
|
1142
|
+
if (str === undefined && argsDescription === undefined)
|
|
1143
|
+
return this._description;
|
|
1144
|
+
this._description = str ?? '';
|
|
1145
|
+
if (argsDescription)
|
|
1146
|
+
this._argsDescription = argsDescription;
|
|
1147
|
+
return this;
|
|
1148
|
+
}
|
|
1149
|
+
summary(str) {
|
|
1150
|
+
if (str === undefined)
|
|
1151
|
+
return this._summary;
|
|
1152
|
+
this._summary = str;
|
|
1153
|
+
return this;
|
|
1154
|
+
}
|
|
1155
|
+
alias(alias) {
|
|
1156
|
+
if (alias === undefined)
|
|
1157
|
+
return this._aliases[0];
|
|
1158
|
+
let command = this;
|
|
1159
|
+
const last = this.commands[this.commands.length - 1];
|
|
1160
|
+
if (this.commands.length !== 0 && last?._executableHandler) {
|
|
1161
|
+
command = last;
|
|
1162
|
+
}
|
|
1163
|
+
if (alias === command._name)
|
|
1164
|
+
throw new Error("Command alias can't be the same as its name");
|
|
1165
|
+
const matchingCommand = this.parent?._findCommand(alias);
|
|
1166
|
+
if (matchingCommand) {
|
|
1167
|
+
const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join('|');
|
|
1168
|
+
throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`);
|
|
1169
|
+
}
|
|
1170
|
+
command._aliases.push(alias);
|
|
1171
|
+
return this;
|
|
1172
|
+
}
|
|
1173
|
+
aliases(aliases) {
|
|
1174
|
+
if (aliases === undefined)
|
|
1175
|
+
return this._aliases;
|
|
1176
|
+
for (const alias of aliases)
|
|
1177
|
+
this.alias(alias);
|
|
1178
|
+
return this;
|
|
1179
|
+
}
|
|
1180
|
+
usage(str) {
|
|
1181
|
+
if (str === undefined) {
|
|
1182
|
+
if (this._usage)
|
|
1183
|
+
return this._usage;
|
|
1184
|
+
const args = this.registeredArguments.map((arg) => humanReadableArgName(arg));
|
|
1185
|
+
return []
|
|
1186
|
+
.concat(this.options.length || this._helpOption !== null ? '[options]' : [], this.commands.length ? '[command]' : [], this.registeredArguments.length ? args : [])
|
|
1187
|
+
.join(' ');
|
|
1188
|
+
}
|
|
1189
|
+
this._usage = str;
|
|
1190
|
+
return this;
|
|
1191
|
+
}
|
|
1192
|
+
name(str) {
|
|
1193
|
+
if (str === undefined)
|
|
1194
|
+
return this._name;
|
|
1195
|
+
this._name = str;
|
|
1196
|
+
return this;
|
|
1197
|
+
}
|
|
1198
|
+
helpGroup(heading) {
|
|
1199
|
+
if (heading === undefined)
|
|
1200
|
+
return this._helpGroupHeading ?? '';
|
|
1201
|
+
this._helpGroupHeading = heading;
|
|
1202
|
+
return this;
|
|
1203
|
+
}
|
|
1204
|
+
commandsGroup(heading) {
|
|
1205
|
+
if (heading === undefined)
|
|
1206
|
+
return this._defaultCommandGroup ?? '';
|
|
1207
|
+
this._defaultCommandGroup = heading;
|
|
1208
|
+
return this;
|
|
1209
|
+
}
|
|
1210
|
+
optionsGroup(heading) {
|
|
1211
|
+
if (heading === undefined)
|
|
1212
|
+
return this._defaultOptionGroup ?? '';
|
|
1213
|
+
this._defaultOptionGroup = heading;
|
|
1214
|
+
return this;
|
|
1215
|
+
}
|
|
1216
|
+
_initOptionGroup(option) {
|
|
1217
|
+
if (this._defaultOptionGroup && !option.helpGroupHeading)
|
|
1218
|
+
option.helpGroup(this._defaultOptionGroup);
|
|
1219
|
+
}
|
|
1220
|
+
_initCommandGroup(cmd) {
|
|
1221
|
+
if (this._defaultCommandGroup && !cmd.helpGroup())
|
|
1222
|
+
cmd.helpGroup(this._defaultCommandGroup);
|
|
1223
|
+
}
|
|
1224
|
+
nameFromFilename(filename) {
|
|
1225
|
+
this._name = path.basename(filename, path.extname(filename));
|
|
1226
|
+
return this;
|
|
1227
|
+
}
|
|
1228
|
+
executableDir(dir) {
|
|
1229
|
+
if (dir === undefined)
|
|
1230
|
+
return this._executableDir;
|
|
1231
|
+
this._executableDir = dir;
|
|
1232
|
+
return this;
|
|
1233
|
+
}
|
|
1234
|
+
helpInformation(contextOptions) {
|
|
1235
|
+
const helper = this.createHelp();
|
|
1236
|
+
const context = this._getOutputContext(contextOptions);
|
|
1237
|
+
const prepared = { error: context.error };
|
|
1238
|
+
if (context.helpWidth !== undefined)
|
|
1239
|
+
prepared.helpWidth = context.helpWidth;
|
|
1240
|
+
if (context.hasColors !== undefined)
|
|
1241
|
+
prepared.outputHasColors = context.hasColors;
|
|
1242
|
+
helper.prepareContext(prepared);
|
|
1243
|
+
const text = helper.formatHelp(this, helper);
|
|
1244
|
+
if (context.hasColors)
|
|
1245
|
+
return text;
|
|
1246
|
+
return this._outputConfiguration.stripColor(text);
|
|
1247
|
+
}
|
|
1248
|
+
_getOutputContext(contextOptions) {
|
|
1249
|
+
const error = !!contextOptions?.error;
|
|
1250
|
+
let baseWrite;
|
|
1251
|
+
let hasColors;
|
|
1252
|
+
let helpWidth;
|
|
1253
|
+
if (error) {
|
|
1254
|
+
baseWrite = (str) => this._outputConfiguration.writeErr(str);
|
|
1255
|
+
hasColors = this._outputConfiguration.getErrHasColors();
|
|
1256
|
+
helpWidth = this._outputConfiguration.getErrHelpWidth();
|
|
1257
|
+
}
|
|
1258
|
+
else {
|
|
1259
|
+
baseWrite = (str) => this._outputConfiguration.writeOut(str);
|
|
1260
|
+
hasColors = this._outputConfiguration.getOutHasColors();
|
|
1261
|
+
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
1262
|
+
}
|
|
1263
|
+
const write = (str) => {
|
|
1264
|
+
if (!hasColors)
|
|
1265
|
+
str = this._outputConfiguration.stripColor(str);
|
|
1266
|
+
baseWrite(str);
|
|
1267
|
+
};
|
|
1268
|
+
return { error, write, hasColors, helpWidth };
|
|
1269
|
+
}
|
|
1270
|
+
outputHelp(contextOptions) {
|
|
1271
|
+
let deprecatedCallback;
|
|
1272
|
+
if (typeof contextOptions === 'function') {
|
|
1273
|
+
deprecatedCallback = contextOptions;
|
|
1274
|
+
contextOptions = undefined;
|
|
1275
|
+
}
|
|
1276
|
+
const outputContext = this._getOutputContext(contextOptions);
|
|
1277
|
+
const eventContext = { error: outputContext.error, write: outputContext.write, command: this };
|
|
1278
|
+
for (const command of this._getCommandAndAncestors().reverse())
|
|
1279
|
+
command.emit('beforeAllHelp', eventContext);
|
|
1280
|
+
this.emit('beforeHelp', eventContext);
|
|
1281
|
+
let helpInformation = this.helpInformation({ error: outputContext.error });
|
|
1282
|
+
if (deprecatedCallback) {
|
|
1283
|
+
helpInformation = deprecatedCallback(helpInformation);
|
|
1284
|
+
if (typeof helpInformation !== 'string' && !Buffer.isBuffer(helpInformation)) {
|
|
1285
|
+
throw new Error('outputHelp callback must return a string or a Buffer');
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
outputContext.write(String(helpInformation));
|
|
1289
|
+
const helpLong = this._getHelpOption()?.long;
|
|
1290
|
+
if (helpLong)
|
|
1291
|
+
this.emit(helpLong);
|
|
1292
|
+
this.emit('afterHelp', eventContext);
|
|
1293
|
+
for (const command of this._getCommandAndAncestors())
|
|
1294
|
+
command.emit('afterAllHelp', eventContext);
|
|
1295
|
+
}
|
|
1296
|
+
helpOption(flags, description) {
|
|
1297
|
+
if (typeof flags === 'boolean') {
|
|
1298
|
+
if (flags) {
|
|
1299
|
+
if (this._helpOption === null)
|
|
1300
|
+
this._helpOption = undefined;
|
|
1301
|
+
if (this._defaultOptionGroup) {
|
|
1302
|
+
const helpOption = this._getHelpOption();
|
|
1303
|
+
if (helpOption)
|
|
1304
|
+
this._initOptionGroup(helpOption);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
else {
|
|
1308
|
+
this._helpOption = null;
|
|
1309
|
+
}
|
|
1310
|
+
return this;
|
|
1311
|
+
}
|
|
1312
|
+
this._helpOption = this.createOption(flags ?? '-h, --help', description ?? 'display help for command');
|
|
1313
|
+
if (flags || description)
|
|
1314
|
+
this._initOptionGroup(this._helpOption);
|
|
1315
|
+
return this;
|
|
1316
|
+
}
|
|
1317
|
+
_getHelpOption() {
|
|
1318
|
+
if (this._helpOption === undefined)
|
|
1319
|
+
this.helpOption(undefined, undefined);
|
|
1320
|
+
return this._helpOption ?? null;
|
|
1321
|
+
}
|
|
1322
|
+
addHelpOption(option) {
|
|
1323
|
+
this._helpOption = option;
|
|
1324
|
+
this._initOptionGroup(option);
|
|
1325
|
+
return this;
|
|
1326
|
+
}
|
|
1327
|
+
help(contextOptions) {
|
|
1328
|
+
this.outputHelp(contextOptions);
|
|
1329
|
+
let exitCode = Number(process.exitCode ?? 0);
|
|
1330
|
+
if (exitCode === 0 && contextOptions && typeof contextOptions !== 'function' && contextOptions.error)
|
|
1331
|
+
exitCode = 1;
|
|
1332
|
+
this._exit(exitCode, 'commander.help', '(outputHelp)');
|
|
1333
|
+
}
|
|
1334
|
+
addHelpText(position, text) {
|
|
1335
|
+
if (!HELP_POSITIONS.includes(position)) {
|
|
1336
|
+
throw new Error(`Unexpected value for position to addHelpText.
|
|
1337
|
+
Expecting one of '${HELP_POSITIONS.join("', '")}'`);
|
|
1338
|
+
}
|
|
1339
|
+
this.on(`${position}Help`, (context) => {
|
|
1340
|
+
const helpStr = typeof text === 'function' ? text({ error: context.error, command: context.command }) : text;
|
|
1341
|
+
if (helpStr)
|
|
1342
|
+
context.write(`${helpStr}\n`);
|
|
1343
|
+
});
|
|
1344
|
+
return this;
|
|
1345
|
+
}
|
|
1346
|
+
_outputHelpIfRequested(args) {
|
|
1347
|
+
const helpOption = this._getHelpOption();
|
|
1348
|
+
if (helpOption && args.find((arg) => helpOption.is(arg))) {
|
|
1349
|
+
this.outputHelp();
|
|
1350
|
+
this._exit(0, 'commander.helpDisplayed', '(outputHelp)');
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
_root() {
|
|
1354
|
+
let command = this;
|
|
1355
|
+
while (command.parent)
|
|
1356
|
+
command = command.parent;
|
|
1357
|
+
return command;
|
|
1358
|
+
}
|
|
1359
|
+
get manifest() {
|
|
1360
|
+
const root = this._root();
|
|
1361
|
+
root._manifest ??= new Manifest();
|
|
1362
|
+
root._project(root._manifest);
|
|
1363
|
+
return root._manifest;
|
|
1364
|
+
}
|
|
1365
|
+
_project(manifest) {
|
|
1366
|
+
const contributed = manifest.commands.filter((c) => c.plugin !== undefined);
|
|
1367
|
+
manifest.commands.splice(0, manifest.commands.length, ...contributed);
|
|
1368
|
+
const rootName = this._name || 'program';
|
|
1369
|
+
manifest.rootPath = [rootName];
|
|
1370
|
+
if (this._version !== undefined)
|
|
1371
|
+
manifest.version = this._version;
|
|
1372
|
+
const visit = (cmd, at) => {
|
|
1373
|
+
manifest.add({
|
|
1374
|
+
path: at,
|
|
1375
|
+
...(cmd._description ? { description: cmd._description } : {}),
|
|
1376
|
+
...(cmd._summary ? { summary: cmd._summary } : {}),
|
|
1377
|
+
...(cmd._effects === undefined ? {} : { effects: cmd._effects }),
|
|
1378
|
+
...(cmd._hidden ? { hidden: true } : {}),
|
|
1379
|
+
options: cmd._optionSpecs(),
|
|
1380
|
+
arguments: cmd.registeredArguments.map((a) => ({ name: a.name(), required: a.required, variadic: a.variadic, ...(a.description ? { description: a.description } : {}) })),
|
|
1381
|
+
...(cmd._actionHandler === null ? {} : { run: () => undefined }),
|
|
1382
|
+
});
|
|
1383
|
+
for (const sub of cmd.commands)
|
|
1384
|
+
visit(sub, [...at, sub._name]);
|
|
1385
|
+
};
|
|
1386
|
+
visit(this, [rootName]);
|
|
1387
|
+
}
|
|
1388
|
+
_optionSpecs() {
|
|
1389
|
+
const specs = Object.create(null);
|
|
1390
|
+
for (const option of this.options) {
|
|
1391
|
+
const spec = { type: option.required || option.optional ? 'string' : 'boolean' };
|
|
1392
|
+
if (option.description)
|
|
1393
|
+
spec.description = option.description;
|
|
1394
|
+
if (option.mandatory)
|
|
1395
|
+
spec.required = true;
|
|
1396
|
+
if (option.short && option.long)
|
|
1397
|
+
spec.short = option.short.slice(1);
|
|
1398
|
+
if (typeof option.defaultValue === 'string' || typeof option.defaultValue === 'boolean')
|
|
1399
|
+
spec.default = option.defaultValue;
|
|
1400
|
+
if (option.envVar)
|
|
1401
|
+
spec.env = option.envVar;
|
|
1402
|
+
Object.defineProperty(specs, option.attributeName(), { value: spec, enumerable: true, writable: true, configurable: true });
|
|
1403
|
+
}
|
|
1404
|
+
return specs;
|
|
1405
|
+
}
|
|
1406
|
+
effects(value) {
|
|
1407
|
+
this._effects = value;
|
|
1408
|
+
return this;
|
|
1409
|
+
}
|
|
1410
|
+
_burgeeSurface(userArgs) {
|
|
1411
|
+
const root = this._root();
|
|
1412
|
+
const declared = (flag, at = root) => at._findOption(flag) !== undefined || at.commands.some((sub) => declared(flag, sub));
|
|
1413
|
+
const terminator = userArgs.indexOf('--');
|
|
1414
|
+
const head = terminator === -1 ? userArgs : userArgs.slice(0, terminator);
|
|
1415
|
+
if (head[0] === 'completion' && root._findCommand('completion') === undefined) {
|
|
1416
|
+
return import('./completions.js').then(({ renderCompletion, renderFigSpec, SHELLS }) => {
|
|
1417
|
+
const shell = head[1] ?? '';
|
|
1418
|
+
if (shell === 'fig') {
|
|
1419
|
+
root._outputConfiguration.writeOut(`${JSON.stringify(renderFigSpec(this.manifest), null, 2)}\n`);
|
|
1420
|
+
return true;
|
|
1421
|
+
}
|
|
1422
|
+
const known = SHELLS.find((s) => s === shell);
|
|
1423
|
+
if (known !== undefined) {
|
|
1424
|
+
root._outputConfiguration.writeOut(renderCompletion(this.manifest, known));
|
|
1425
|
+
return true;
|
|
1426
|
+
}
|
|
1427
|
+
return this._burgeeSurfaceRest(head, declared);
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
return this._burgeeSurfaceRest(head, declared);
|
|
1431
|
+
}
|
|
1432
|
+
_burgeeSurfaceRest(head, declared) {
|
|
1433
|
+
const root = this._root();
|
|
1434
|
+
if (head.includes('--schema') && !declared('--schema')) {
|
|
1435
|
+
root._outputConfiguration.writeOut(`${JSON.stringify(schemaOf(this.manifest), null, 2)}\n`);
|
|
1436
|
+
return true;
|
|
1437
|
+
}
|
|
1438
|
+
if (head[0] === '--mcp' && !declared('--mcp')) {
|
|
1439
|
+
const invoke = async (args) => {
|
|
1440
|
+
const out = [];
|
|
1441
|
+
const err = [];
|
|
1442
|
+
let code = 0;
|
|
1443
|
+
await root.parseAsync(args, { from: 'user', stdout: { write: (s) => out.push(s) }, stderr: { write: (s) => err.push(s) }, exit: (c) => void (code = c) });
|
|
1444
|
+
return { stdout: out.join(''), stderr: err.join(''), code };
|
|
1445
|
+
};
|
|
1446
|
+
return serveMcp(this.manifest, { input: process.stdin, output: { write: (s) => root._outputConfiguration.writeOut(s) }, invoke }).then(() => true);
|
|
1447
|
+
}
|
|
1448
|
+
return false;
|
|
1449
|
+
}
|
|
1450
|
+
use(plugin) {
|
|
1451
|
+
this.manifest.use(plugin);
|
|
1452
|
+
return this;
|
|
1453
|
+
}
|
|
1454
|
+
_prepareBurgee(parseOptions) {
|
|
1455
|
+
if (parseOptions === undefined)
|
|
1456
|
+
return undefined;
|
|
1457
|
+
const { stdout, stderr, exit, ...from } = parseOptions;
|
|
1458
|
+
if (stdout === undefined && stderr === undefined && exit === undefined)
|
|
1459
|
+
return from;
|
|
1460
|
+
const root = this._root();
|
|
1461
|
+
root._burgee = { exit, json: false };
|
|
1462
|
+
const output = {};
|
|
1463
|
+
if (stdout)
|
|
1464
|
+
output.writeOut = (str) => void stdout.write(str);
|
|
1465
|
+
if (stderr)
|
|
1466
|
+
output.writeErr = (str) => void stderr.write(str);
|
|
1467
|
+
const configuration = { ...root._outputConfiguration, ...output };
|
|
1468
|
+
const throwing = (err) => {
|
|
1469
|
+
throw err;
|
|
1470
|
+
};
|
|
1471
|
+
const visit = (cmd) => {
|
|
1472
|
+
cmd._outputConfiguration = configuration;
|
|
1473
|
+
cmd._exitCallback = throwing;
|
|
1474
|
+
for (const sub of cmd.commands)
|
|
1475
|
+
visit(sub);
|
|
1476
|
+
};
|
|
1477
|
+
visit(root);
|
|
1478
|
+
return from;
|
|
1479
|
+
}
|
|
1480
|
+
_runBurgee(run) {
|
|
1481
|
+
const root = this._root();
|
|
1482
|
+
const burgee = root._burgee;
|
|
1483
|
+
if (burgee === undefined)
|
|
1484
|
+
return run();
|
|
1485
|
+
const finish = (code) => {
|
|
1486
|
+
root._burgee = undefined;
|
|
1487
|
+
burgee.exit?.(code);
|
|
1488
|
+
};
|
|
1489
|
+
const fail = (err) => {
|
|
1490
|
+
if (err instanceof CommanderError) {
|
|
1491
|
+
if (burgee.json && err.code !== 'commander.helpDisplayed' && err.code !== 'commander.version') {
|
|
1492
|
+
root._outputConfiguration.writeOut(`${JSON.stringify({ ok: false, error: { code: err.code, message: err.message } })}\n`);
|
|
1493
|
+
}
|
|
1494
|
+
finish(e1(err));
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1498
|
+
if (burgee.json)
|
|
1499
|
+
root._outputConfiguration.writeOut(`${JSON.stringify({ ok: false, error: { code: 'runtime', message } })}\n`);
|
|
1500
|
+
else
|
|
1501
|
+
root._outputConfiguration.writeErr(`error: ${message}\n`);
|
|
1502
|
+
finish(ExitCode.RUNTIME);
|
|
1503
|
+
};
|
|
1504
|
+
try {
|
|
1505
|
+
const result = run();
|
|
1506
|
+
if (isThenable(result))
|
|
1507
|
+
return Promise.resolve(result).then(() => finish(ExitCode.OK), fail);
|
|
1508
|
+
finish(ExitCode.OK);
|
|
1509
|
+
return undefined;
|
|
1510
|
+
}
|
|
1511
|
+
catch (err) {
|
|
1512
|
+
fail(err);
|
|
1513
|
+
return undefined;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
_takeJson(unknown) {
|
|
1517
|
+
const terminator = unknown.indexOf('--');
|
|
1518
|
+
const index = unknown.indexOf('--json');
|
|
1519
|
+
if (index === -1 || (terminator !== -1 && index > terminator))
|
|
1520
|
+
return;
|
|
1521
|
+
if (this._getCommandAndAncestors().some((cmd) => cmd._findOption('--json')))
|
|
1522
|
+
return;
|
|
1523
|
+
unknown.splice(index, 1);
|
|
1524
|
+
const root = this._root();
|
|
1525
|
+
root._burgee ??= { exit: undefined, json: false };
|
|
1526
|
+
root._burgee.json = true;
|
|
1527
|
+
}
|
|
1528
|
+
_runAction() {
|
|
1529
|
+
const handler = this._actionHandler;
|
|
1530
|
+
if (handler === null)
|
|
1531
|
+
return undefined;
|
|
1532
|
+
const root = this._root();
|
|
1533
|
+
const manifest = root._manifest;
|
|
1534
|
+
const settle = (value) => this._emitResult(value);
|
|
1535
|
+
if (manifest === undefined || manifest.plugins.length === 0) {
|
|
1536
|
+
const result = handler(this.processedArgs);
|
|
1537
|
+
return isThenable(result) ? Promise.resolve(result).then(settle) : settle(result);
|
|
1538
|
+
}
|
|
1539
|
+
const name = this.name();
|
|
1540
|
+
const options = this.opts();
|
|
1541
|
+
return manifest
|
|
1542
|
+
.fire('preRun', name, options)
|
|
1543
|
+
.then(() => handler(this.processedArgs))
|
|
1544
|
+
.then(async (value) => {
|
|
1545
|
+
await manifest.fire('postRun', name, options);
|
|
1546
|
+
settle(value);
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
_provenance() {
|
|
1550
|
+
const out = {};
|
|
1551
|
+
const names = { cli: 'flag', env: 'env', config: 'config', default: 'default', implied: 'implied' };
|
|
1552
|
+
for (const [key, source] of Object.entries(this._optionValueSources)) {
|
|
1553
|
+
if (source !== undefined && this.getOptionValue(key) !== undefined)
|
|
1554
|
+
out[key] = { source: names[source] ?? source };
|
|
1555
|
+
}
|
|
1556
|
+
return out;
|
|
1557
|
+
}
|
|
1558
|
+
_emitResult(value) {
|
|
1559
|
+
const burgee = this._root()._burgee;
|
|
1560
|
+
if (burgee === undefined)
|
|
1561
|
+
return;
|
|
1562
|
+
if (burgee.json) {
|
|
1563
|
+
this._outputConfiguration.writeOut(`${JSON.stringify({ ok: true, data: value ?? null, meta: { provenance: this._provenance() } })}\n`);
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
const text = render(value);
|
|
1567
|
+
if (text !== '')
|
|
1568
|
+
this._outputConfiguration.writeOut(text);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
function incrementNodeInspectorPort(args) {
|
|
1572
|
+
return args.map((arg) => {
|
|
1573
|
+
if (!arg.startsWith('--inspect'))
|
|
1574
|
+
return arg;
|
|
1575
|
+
let debugOption;
|
|
1576
|
+
let debugHost = '127.0.0.1';
|
|
1577
|
+
let debugPort = '9229';
|
|
1578
|
+
let match;
|
|
1579
|
+
if ((match = /^(--inspect(-brk)?)$/.exec(arg)) !== null) {
|
|
1580
|
+
debugOption = match[1];
|
|
1581
|
+
}
|
|
1582
|
+
else if ((match = /^(--inspect(-brk|-port)?)=([^:]+)$/.exec(arg)) !== null) {
|
|
1583
|
+
debugOption = match[1];
|
|
1584
|
+
if (/^\d+$/.test(match[3] ?? ''))
|
|
1585
|
+
debugPort = match[3] ?? debugPort;
|
|
1586
|
+
else
|
|
1587
|
+
debugHost = match[3] ?? debugHost;
|
|
1588
|
+
}
|
|
1589
|
+
else if ((match = /^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/.exec(arg)) !== null) {
|
|
1590
|
+
debugOption = match[1];
|
|
1591
|
+
debugHost = match[3] ?? debugHost;
|
|
1592
|
+
debugPort = match[4] ?? debugPort;
|
|
1593
|
+
}
|
|
1594
|
+
if (debugOption && debugPort !== '0')
|
|
1595
|
+
return `${debugOption}=${debugHost}:${parseInt(debugPort, 10) + 1}`;
|
|
1596
|
+
return arg;
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
export function useColor() {
|
|
1600
|
+
if (process.env['NO_COLOR'] || process.env['FORCE_COLOR'] === '0' || process.env['FORCE_COLOR'] === 'false')
|
|
1601
|
+
return false;
|
|
1602
|
+
if (process.env['FORCE_COLOR'] || process.env['CLICOLOR_FORCE'] !== undefined)
|
|
1603
|
+
return true;
|
|
1604
|
+
return undefined;
|
|
1605
|
+
}
|