commander 12.1.0 → 13.0.0-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 +5 -21
- package/lib/command.js +110 -34
- package/lib/help.js +268 -79
- package/lib/option.js +31 -13
- package/package.json +6 -8
- package/typings/index.d.ts +70 -10
package/Readme.md
CHANGED
|
@@ -79,7 +79,8 @@ const { program } = require('commander');
|
|
|
79
79
|
|
|
80
80
|
program
|
|
81
81
|
.option('--first')
|
|
82
|
-
.option('-s, --separator <char>')
|
|
82
|
+
.option('-s, --separator <char>')
|
|
83
|
+
.argument('<string>');
|
|
83
84
|
|
|
84
85
|
program.parse();
|
|
85
86
|
|
|
@@ -678,8 +679,7 @@ async function main() {
|
|
|
678
679
|
}
|
|
679
680
|
```
|
|
680
681
|
|
|
681
|
-
A command's options and arguments on the command line are validated when the command is used. Any unknown options or missing arguments will be reported as an error. You can suppress the unknown option
|
|
682
|
-
pass more arguments than declared, but you can make this an error with `.allowExcessArguments(false)`.
|
|
682
|
+
A command's options and arguments on the command line are validated when the command is used. Any unknown options or missing arguments or excess arguments will be reported as an error. You can suppress the unknown option check with `.allowUnknownOption()`. You can suppress the excess arguments check with `.allowExcessArguments()`.
|
|
683
683
|
|
|
684
684
|
### Stand-alone executable (sub)commands
|
|
685
685
|
|
|
@@ -696,7 +696,7 @@ Example file: [pm](./examples/pm)
|
|
|
696
696
|
program
|
|
697
697
|
.name('pm')
|
|
698
698
|
.version('0.1.0')
|
|
699
|
-
.command('install [
|
|
699
|
+
.command('install [package-names...]', 'install one or more packages')
|
|
700
700
|
.command('search [query]', 'search with optional query')
|
|
701
701
|
.command('update', 'update installed packages', { executableFile: 'myUpdateSubCommand' })
|
|
702
702
|
.command('list', 'list packages installed', { isDefault: true });
|
|
@@ -923,23 +923,7 @@ program.helpCommand('assist [command]', 'show assistance');
|
|
|
923
923
|
The built-in help is formatted using the Help class.
|
|
924
924
|
You can configure the Help behaviour by modifying data properties and methods using `.configureHelp()`, or by subclassing using `.createHelp()` if you prefer.
|
|
925
925
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
- `helpWidth`: specify the wrap width, useful for unit tests
|
|
929
|
-
- `sortSubcommands`: sort the subcommands alphabetically
|
|
930
|
-
- `sortOptions`: sort the options alphabetically
|
|
931
|
-
- `showGlobalOptions`: show a section with the global options from the parent command(s)
|
|
932
|
-
|
|
933
|
-
You can override any method on the [Help](./lib/help.js) class. There are methods getting the visible lists of arguments, options, and subcommands. There are methods for formatting the items in the lists, with each item having a _term_ and _description_. Take a look at `.formatHelp()` to see how they are used.
|
|
934
|
-
|
|
935
|
-
Example file: [configure-help.js](./examples/configure-help.js)
|
|
936
|
-
|
|
937
|
-
```js
|
|
938
|
-
program.configureHelp({
|
|
939
|
-
sortSubcommands: true,
|
|
940
|
-
subcommandTerm: (cmd) => cmd.name() // Just show the name, instead of short usage.
|
|
941
|
-
});
|
|
942
|
-
```
|
|
926
|
+
For more detail see (./docs/help-in-depth.md)
|
|
943
927
|
|
|
944
928
|
## Custom event listeners
|
|
945
929
|
|
package/lib/command.js
CHANGED
|
@@ -6,7 +6,7 @@ const process = require('node:process');
|
|
|
6
6
|
|
|
7
7
|
const { Argument, humanReadableArgName } = require('./argument.js');
|
|
8
8
|
const { CommanderError } = require('./error.js');
|
|
9
|
-
const { Help } = require('./help.js');
|
|
9
|
+
const { Help, stripColor } = require('./help.js');
|
|
10
10
|
const { Option, DualOptions } = require('./option.js');
|
|
11
11
|
const { suggestSimilar } = require('./suggestSimilar');
|
|
12
12
|
|
|
@@ -25,7 +25,7 @@ class Command extends EventEmitter {
|
|
|
25
25
|
this.options = [];
|
|
26
26
|
this.parent = null;
|
|
27
27
|
this._allowUnknownOption = false;
|
|
28
|
-
this._allowExcessArguments =
|
|
28
|
+
this._allowExcessArguments = false;
|
|
29
29
|
/** @type {Argument[]} */
|
|
30
30
|
this.registeredArguments = [];
|
|
31
31
|
this._args = this.registeredArguments; // deprecated old name
|
|
@@ -56,15 +56,20 @@ class Command extends EventEmitter {
|
|
|
56
56
|
this._showHelpAfterError = false;
|
|
57
57
|
this._showSuggestionAfterError = true;
|
|
58
58
|
|
|
59
|
-
// see
|
|
59
|
+
// see configureOutput() for docs
|
|
60
60
|
this._outputConfiguration = {
|
|
61
61
|
writeOut: (str) => process.stdout.write(str),
|
|
62
62
|
writeErr: (str) => process.stderr.write(str),
|
|
63
|
+
outputError: (str, write) => write(str),
|
|
63
64
|
getOutHelpWidth: () =>
|
|
64
65
|
process.stdout.isTTY ? process.stdout.columns : undefined,
|
|
65
66
|
getErrHelpWidth: () =>
|
|
66
67
|
process.stderr.isTTY ? process.stderr.columns : undefined,
|
|
67
|
-
|
|
68
|
+
getOutHasColors: () =>
|
|
69
|
+
useColor() ?? (process.stdout.isTTY && process.stdout.hasColors?.()),
|
|
70
|
+
getErrHasColors: () =>
|
|
71
|
+
useColor() ?? (process.stderr.isTTY && process.stderr.hasColors?.()),
|
|
72
|
+
stripColor: (str) => stripColor(str),
|
|
68
73
|
};
|
|
69
74
|
|
|
70
75
|
this._hidden = false;
|
|
@@ -213,14 +218,18 @@ class Command extends EventEmitter {
|
|
|
213
218
|
*
|
|
214
219
|
* The configuration properties are all functions:
|
|
215
220
|
*
|
|
216
|
-
* //
|
|
221
|
+
* // change how output being written, defaults to stdout and stderr
|
|
217
222
|
* writeOut(str)
|
|
218
223
|
* writeErr(str)
|
|
219
|
-
* //
|
|
224
|
+
* // change how output being written for errors, defaults to writeErr
|
|
225
|
+
* outputError(str, write) // used for displaying errors and not used for displaying help
|
|
226
|
+
* // specify width for wrapping help
|
|
220
227
|
* getOutHelpWidth()
|
|
221
228
|
* getErrHelpWidth()
|
|
222
|
-
* //
|
|
223
|
-
*
|
|
229
|
+
* // color support, currently only used with Help
|
|
230
|
+
* getOutHasColors()
|
|
231
|
+
* getErrHasColors()
|
|
232
|
+
* stripColor() // used to remove ANSI escape codes if output does not have colors
|
|
224
233
|
*
|
|
225
234
|
* @param {object} [configuration] - configuration options
|
|
226
235
|
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
@@ -1134,7 +1143,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1134
1143
|
let resolvedScriptPath; // resolve possible symlink for installed npm binary
|
|
1135
1144
|
try {
|
|
1136
1145
|
resolvedScriptPath = fs.realpathSync(this._scriptPath);
|
|
1137
|
-
} catch
|
|
1146
|
+
} catch {
|
|
1138
1147
|
resolvedScriptPath = this._scriptPath;
|
|
1139
1148
|
}
|
|
1140
1149
|
executableDir = path.resolve(
|
|
@@ -2254,31 +2263,49 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2254
2263
|
|
|
2255
2264
|
helpInformation(contextOptions) {
|
|
2256
2265
|
const helper = this.createHelp();
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
}
|
|
2263
|
-
|
|
2266
|
+
const context = this._getOutputContext(contextOptions);
|
|
2267
|
+
helper.prepareContext({
|
|
2268
|
+
error: context.error,
|
|
2269
|
+
helpWidth: context.helpWidth,
|
|
2270
|
+
outputHasColors: context.hasColors,
|
|
2271
|
+
});
|
|
2272
|
+
const text = helper.formatHelp(this, helper);
|
|
2273
|
+
if (context.hasColors) return text;
|
|
2274
|
+
return this._outputConfiguration.stripColor(text);
|
|
2264
2275
|
}
|
|
2265
2276
|
|
|
2266
2277
|
/**
|
|
2278
|
+
* @typedef HelpContext
|
|
2279
|
+
* @type {object}
|
|
2280
|
+
* @property {boolean} error
|
|
2281
|
+
* @property {number} helpWidth
|
|
2282
|
+
* @property {boolean} hasColors
|
|
2283
|
+
* @property {function} write - includes stripColor if needed
|
|
2284
|
+
*
|
|
2285
|
+
* @returns {HelpContext}
|
|
2267
2286
|
* @private
|
|
2268
2287
|
*/
|
|
2269
2288
|
|
|
2270
|
-
|
|
2289
|
+
_getOutputContext(contextOptions) {
|
|
2271
2290
|
contextOptions = contextOptions || {};
|
|
2272
|
-
const
|
|
2273
|
-
let
|
|
2274
|
-
|
|
2275
|
-
|
|
2291
|
+
const error = !!contextOptions.error;
|
|
2292
|
+
let baseWrite;
|
|
2293
|
+
let hasColors;
|
|
2294
|
+
let helpWidth;
|
|
2295
|
+
if (error) {
|
|
2296
|
+
baseWrite = (str) => this._outputConfiguration.writeErr(str);
|
|
2297
|
+
hasColors = this._outputConfiguration.getErrHasColors();
|
|
2298
|
+
helpWidth = this._outputConfiguration.getErrHelpWidth();
|
|
2276
2299
|
} else {
|
|
2277
|
-
|
|
2300
|
+
baseWrite = (str) => this._outputConfiguration.writeOut(str);
|
|
2301
|
+
hasColors = this._outputConfiguration.getOutHasColors();
|
|
2302
|
+
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
2278
2303
|
}
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2304
|
+
const write = (str) => {
|
|
2305
|
+
if (!hasColors) str = this._outputConfiguration.stripColor(str);
|
|
2306
|
+
return baseWrite(str);
|
|
2307
|
+
};
|
|
2308
|
+
return { error, write, hasColors, helpWidth };
|
|
2282
2309
|
}
|
|
2283
2310
|
|
|
2284
2311
|
/**
|
|
@@ -2295,14 +2322,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2295
2322
|
deprecatedCallback = contextOptions;
|
|
2296
2323
|
contextOptions = undefined;
|
|
2297
2324
|
}
|
|
2298
|
-
|
|
2325
|
+
|
|
2326
|
+
const outputContext = this._getOutputContext(contextOptions);
|
|
2327
|
+
/** @type {HelpTextEventContext} */
|
|
2328
|
+
const eventContext = {
|
|
2329
|
+
error: outputContext.error,
|
|
2330
|
+
write: outputContext.write,
|
|
2331
|
+
command: this,
|
|
2332
|
+
};
|
|
2299
2333
|
|
|
2300
2334
|
this._getCommandAndAncestors()
|
|
2301
2335
|
.reverse()
|
|
2302
|
-
.forEach((command) => command.emit('beforeAllHelp',
|
|
2303
|
-
this.emit('beforeHelp',
|
|
2336
|
+
.forEach((command) => command.emit('beforeAllHelp', eventContext));
|
|
2337
|
+
this.emit('beforeHelp', eventContext);
|
|
2304
2338
|
|
|
2305
|
-
let helpInformation = this.helpInformation(
|
|
2339
|
+
let helpInformation = this.helpInformation({ error: outputContext.error });
|
|
2306
2340
|
if (deprecatedCallback) {
|
|
2307
2341
|
helpInformation = deprecatedCallback(helpInformation);
|
|
2308
2342
|
if (
|
|
@@ -2312,14 +2346,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2312
2346
|
throw new Error('outputHelp callback must return a string or a Buffer');
|
|
2313
2347
|
}
|
|
2314
2348
|
}
|
|
2315
|
-
|
|
2349
|
+
outputContext.write(helpInformation);
|
|
2316
2350
|
|
|
2317
2351
|
if (this._getHelpOption()?.long) {
|
|
2318
2352
|
this.emit(this._getHelpOption().long); // deprecated
|
|
2319
2353
|
}
|
|
2320
|
-
this.emit('afterHelp',
|
|
2354
|
+
this.emit('afterHelp', eventContext);
|
|
2321
2355
|
this._getCommandAndAncestors().forEach((command) =>
|
|
2322
|
-
command.emit('afterAllHelp',
|
|
2356
|
+
command.emit('afterAllHelp', eventContext),
|
|
2323
2357
|
);
|
|
2324
2358
|
}
|
|
2325
2359
|
|
|
@@ -2339,6 +2373,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2339
2373
|
helpOption(flags, description) {
|
|
2340
2374
|
// Support disabling built-in help option.
|
|
2341
2375
|
if (typeof flags === 'boolean') {
|
|
2376
|
+
// true is not an expected value. Do something sensible but no unit-test.
|
|
2377
|
+
// istanbul ignore if
|
|
2342
2378
|
if (flags) {
|
|
2343
2379
|
this._helpOption = this._helpOption ?? undefined; // preserve existing option
|
|
2344
2380
|
} else {
|
|
@@ -2392,7 +2428,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2392
2428
|
|
|
2393
2429
|
help(contextOptions) {
|
|
2394
2430
|
this.outputHelp(contextOptions);
|
|
2395
|
-
let exitCode = process.exitCode
|
|
2431
|
+
let exitCode = Number(process.exitCode ?? 0); // process.exitCode does allow a string or an integer, but we prefer just a number
|
|
2396
2432
|
if (
|
|
2397
2433
|
exitCode === 0 &&
|
|
2398
2434
|
contextOptions &&
|
|
@@ -2405,6 +2441,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2405
2441
|
this._exit(exitCode, 'commander.help', '(outputHelp)');
|
|
2406
2442
|
}
|
|
2407
2443
|
|
|
2444
|
+
/**
|
|
2445
|
+
* // Do a little typing to coordinate emit and listener for the help text events.
|
|
2446
|
+
* @typedef HelpTextEventContext
|
|
2447
|
+
* @type {object}
|
|
2448
|
+
* @property {boolean} error
|
|
2449
|
+
* @property {Command} command
|
|
2450
|
+
* @property {function} write
|
|
2451
|
+
*/
|
|
2452
|
+
|
|
2408
2453
|
/**
|
|
2409
2454
|
* Add additional text to be displayed with the built-in help.
|
|
2410
2455
|
*
|
|
@@ -2415,14 +2460,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2415
2460
|
* @param {(string | Function)} text - string to add, or a function returning a string
|
|
2416
2461
|
* @return {Command} `this` command for chaining
|
|
2417
2462
|
*/
|
|
2463
|
+
|
|
2418
2464
|
addHelpText(position, text) {
|
|
2419
2465
|
const allowedValues = ['beforeAll', 'before', 'after', 'afterAll'];
|
|
2420
2466
|
if (!allowedValues.includes(position)) {
|
|
2421
2467
|
throw new Error(`Unexpected value for position to addHelpText.
|
|
2422
2468
|
Expecting one of '${allowedValues.join("', '")}'`);
|
|
2423
2469
|
}
|
|
2470
|
+
|
|
2424
2471
|
const helpEvent = `${position}Help`;
|
|
2425
|
-
this.on(helpEvent, (context) => {
|
|
2472
|
+
this.on(helpEvent, (/** @type {HelpTextEventContext} */ context) => {
|
|
2426
2473
|
let helpStr;
|
|
2427
2474
|
if (typeof text === 'function') {
|
|
2428
2475
|
helpStr = text({ error: context.error, command: context.command });
|
|
@@ -2506,4 +2553,33 @@ function incrementNodeInspectorPort(args) {
|
|
|
2506
2553
|
});
|
|
2507
2554
|
}
|
|
2508
2555
|
|
|
2556
|
+
/**
|
|
2557
|
+
* @returns {boolean | undefined}
|
|
2558
|
+
* @package
|
|
2559
|
+
*/
|
|
2560
|
+
function useColor() {
|
|
2561
|
+
// Test for common conventions.
|
|
2562
|
+
// NB: the observed behaviour is in combination with how author adds color! For example:
|
|
2563
|
+
// - we do not test NODE_DISABLE_COLORS, but util:styletext does
|
|
2564
|
+
// - we do test NO_COLOR, but Chalk does not
|
|
2565
|
+
//
|
|
2566
|
+
// References:
|
|
2567
|
+
// https://no-color.org
|
|
2568
|
+
// https://bixense.com/clicolors/
|
|
2569
|
+
// https://github.com/nodejs/node/blob/0a00217a5f67ef4a22384cfc80eb6dd9a917fdc1/lib/internal/tty.js#L109
|
|
2570
|
+
// https://github.com/chalk/supports-color/blob/c214314a14bcb174b12b3014b2b0a8de375029ae/index.js#L33
|
|
2571
|
+
// (https://force-color.org recent web page from 2023, does not match major javascript implementations)
|
|
2572
|
+
|
|
2573
|
+
if (
|
|
2574
|
+
process.env.NO_COLOR ||
|
|
2575
|
+
process.env.FORCE_COLOR === '0' ||
|
|
2576
|
+
process.env.FORCE_COLOR === 'false'
|
|
2577
|
+
)
|
|
2578
|
+
return false;
|
|
2579
|
+
if (process.env.FORCE_COLOR || process.env.CLICOLOR_FORCE !== undefined)
|
|
2580
|
+
return true;
|
|
2581
|
+
return undefined;
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2509
2584
|
exports.Command = Command;
|
|
2585
|
+
exports.useColor = useColor; // exporting for tests
|
package/lib/help.js
CHANGED
|
@@ -12,11 +12,24 @@ const { humanReadableArgName } = require('./argument.js');
|
|
|
12
12
|
class Help {
|
|
13
13
|
constructor() {
|
|
14
14
|
this.helpWidth = undefined;
|
|
15
|
+
this.minWidthToWrap = 40;
|
|
15
16
|
this.sortSubcommands = false;
|
|
16
17
|
this.sortOptions = false;
|
|
17
18
|
this.showGlobalOptions = false;
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* prepareContext is called by Commander after applying overrides from `Command.configureHelp()`
|
|
23
|
+
* and just before calling `formatHelp()`.
|
|
24
|
+
*
|
|
25
|
+
* Commander just uses the helpWidth and the rest is provided for optional use by more complex subclasses.
|
|
26
|
+
*
|
|
27
|
+
* @param {{ error?: boolean, helpWidth?: number, outputHasColors?: boolean }} contextOptions
|
|
28
|
+
*/
|
|
29
|
+
prepareContext(contextOptions) {
|
|
30
|
+
this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
/**
|
|
21
34
|
* Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
|
|
22
35
|
*
|
|
@@ -191,7 +204,12 @@ class Help {
|
|
|
191
204
|
|
|
192
205
|
longestSubcommandTermLength(cmd, helper) {
|
|
193
206
|
return helper.visibleCommands(cmd).reduce((max, command) => {
|
|
194
|
-
return Math.max(
|
|
207
|
+
return Math.max(
|
|
208
|
+
max,
|
|
209
|
+
this.displayWidth(
|
|
210
|
+
helper.styleSubcommandTerm(helper.subcommandTerm(command)),
|
|
211
|
+
),
|
|
212
|
+
);
|
|
195
213
|
}, 0);
|
|
196
214
|
}
|
|
197
215
|
|
|
@@ -205,7 +223,10 @@ class Help {
|
|
|
205
223
|
|
|
206
224
|
longestOptionTermLength(cmd, helper) {
|
|
207
225
|
return helper.visibleOptions(cmd).reduce((max, option) => {
|
|
208
|
-
return Math.max(
|
|
226
|
+
return Math.max(
|
|
227
|
+
max,
|
|
228
|
+
this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))),
|
|
229
|
+
);
|
|
209
230
|
}, 0);
|
|
210
231
|
}
|
|
211
232
|
|
|
@@ -219,7 +240,10 @@ class Help {
|
|
|
219
240
|
|
|
220
241
|
longestGlobalOptionTermLength(cmd, helper) {
|
|
221
242
|
return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
|
|
222
|
-
return Math.max(
|
|
243
|
+
return Math.max(
|
|
244
|
+
max,
|
|
245
|
+
this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))),
|
|
246
|
+
);
|
|
223
247
|
}, 0);
|
|
224
248
|
}
|
|
225
249
|
|
|
@@ -233,7 +257,12 @@ class Help {
|
|
|
233
257
|
|
|
234
258
|
longestArgumentTermLength(cmd, helper) {
|
|
235
259
|
return helper.visibleArguments(cmd).reduce((max, argument) => {
|
|
236
|
-
return Math.max(
|
|
260
|
+
return Math.max(
|
|
261
|
+
max,
|
|
262
|
+
this.displayWidth(
|
|
263
|
+
helper.styleArgumentTerm(helper.argumentTerm(argument)),
|
|
264
|
+
),
|
|
265
|
+
);
|
|
237
266
|
}, 0);
|
|
238
267
|
}
|
|
239
268
|
|
|
@@ -350,11 +379,11 @@ class Help {
|
|
|
350
379
|
);
|
|
351
380
|
}
|
|
352
381
|
if (extraInfo.length > 0) {
|
|
353
|
-
const
|
|
382
|
+
const extraDescription = `(${extraInfo.join(', ')})`;
|
|
354
383
|
if (argument.description) {
|
|
355
|
-
return `${argument.description} ${
|
|
384
|
+
return `${argument.description} ${extraDescription}`;
|
|
356
385
|
}
|
|
357
|
-
return
|
|
386
|
+
return extraDescription;
|
|
358
387
|
}
|
|
359
388
|
return argument.description;
|
|
360
389
|
}
|
|
@@ -369,71 +398,73 @@ class Help {
|
|
|
369
398
|
|
|
370
399
|
formatHelp(cmd, helper) {
|
|
371
400
|
const termWidth = helper.padWidth(cmd, helper);
|
|
372
|
-
const helpWidth = helper.helpWidth
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if (description) {
|
|
377
|
-
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
|
378
|
-
return helper.wrap(
|
|
379
|
-
fullText,
|
|
380
|
-
helpWidth - itemIndentWidth,
|
|
381
|
-
termWidth + itemSeparatorWidth,
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
return term;
|
|
385
|
-
}
|
|
386
|
-
function formatList(textArray) {
|
|
387
|
-
return textArray.join('\n').replace(/^/gm, ' '.repeat(itemIndentWidth));
|
|
401
|
+
const helpWidth = helper.helpWidth ?? 80; // in case prepareContext() was not called
|
|
402
|
+
|
|
403
|
+
function callFormatItem(term, description) {
|
|
404
|
+
return helper.formatItem(term, termWidth, description, helper);
|
|
388
405
|
}
|
|
389
406
|
|
|
390
407
|
// Usage
|
|
391
|
-
let output = [
|
|
408
|
+
let output = [
|
|
409
|
+
`${helper.styleTitle('Usage:')} ${helper.styleUsage(helper.commandUsage(cmd))}`,
|
|
410
|
+
'',
|
|
411
|
+
];
|
|
392
412
|
|
|
393
413
|
// Description
|
|
394
414
|
const commandDescription = helper.commandDescription(cmd);
|
|
395
415
|
if (commandDescription.length > 0) {
|
|
396
416
|
output = output.concat([
|
|
397
|
-
helper.
|
|
417
|
+
helper.boxWrap(
|
|
418
|
+
helper.styleCommandDescription(commandDescription),
|
|
419
|
+
helpWidth,
|
|
420
|
+
),
|
|
398
421
|
'',
|
|
399
422
|
]);
|
|
400
423
|
}
|
|
401
424
|
|
|
402
425
|
// Arguments
|
|
403
426
|
const argumentList = helper.visibleArguments(cmd).map((argument) => {
|
|
404
|
-
return
|
|
405
|
-
helper.argumentTerm(argument),
|
|
406
|
-
helper.argumentDescription(argument),
|
|
427
|
+
return callFormatItem(
|
|
428
|
+
helper.styleArgumentTerm(helper.argumentTerm(argument)),
|
|
429
|
+
helper.styleArgumentDescription(helper.argumentDescription(argument)),
|
|
407
430
|
);
|
|
408
431
|
});
|
|
409
432
|
if (argumentList.length > 0) {
|
|
410
|
-
output = output.concat([
|
|
433
|
+
output = output.concat([
|
|
434
|
+
helper.styleTitle('Arguments:'),
|
|
435
|
+
...argumentList,
|
|
436
|
+
'',
|
|
437
|
+
]);
|
|
411
438
|
}
|
|
412
439
|
|
|
413
440
|
// Options
|
|
414
441
|
const optionList = helper.visibleOptions(cmd).map((option) => {
|
|
415
|
-
return
|
|
416
|
-
helper.optionTerm(option),
|
|
417
|
-
helper.optionDescription(option),
|
|
442
|
+
return callFormatItem(
|
|
443
|
+
helper.styleOptionTerm(helper.optionTerm(option)),
|
|
444
|
+
helper.styleOptionDescription(helper.optionDescription(option)),
|
|
418
445
|
);
|
|
419
446
|
});
|
|
420
447
|
if (optionList.length > 0) {
|
|
421
|
-
output = output.concat([
|
|
448
|
+
output = output.concat([
|
|
449
|
+
helper.styleTitle('Options:'),
|
|
450
|
+
...optionList,
|
|
451
|
+
'',
|
|
452
|
+
]);
|
|
422
453
|
}
|
|
423
454
|
|
|
424
|
-
if (
|
|
455
|
+
if (helper.showGlobalOptions) {
|
|
425
456
|
const globalOptionList = helper
|
|
426
457
|
.visibleGlobalOptions(cmd)
|
|
427
458
|
.map((option) => {
|
|
428
|
-
return
|
|
429
|
-
helper.optionTerm(option),
|
|
430
|
-
helper.optionDescription(option),
|
|
459
|
+
return callFormatItem(
|
|
460
|
+
helper.styleOptionTerm(helper.optionTerm(option)),
|
|
461
|
+
helper.styleOptionDescription(helper.optionDescription(option)),
|
|
431
462
|
);
|
|
432
463
|
});
|
|
433
464
|
if (globalOptionList.length > 0) {
|
|
434
465
|
output = output.concat([
|
|
435
|
-
'Global Options:',
|
|
436
|
-
|
|
466
|
+
helper.styleTitle('Global Options:'),
|
|
467
|
+
...globalOptionList,
|
|
437
468
|
'',
|
|
438
469
|
]);
|
|
439
470
|
}
|
|
@@ -441,18 +472,103 @@ class Help {
|
|
|
441
472
|
|
|
442
473
|
// Commands
|
|
443
474
|
const commandList = helper.visibleCommands(cmd).map((cmd) => {
|
|
444
|
-
return
|
|
445
|
-
helper.subcommandTerm(cmd),
|
|
446
|
-
helper.subcommandDescription(cmd),
|
|
475
|
+
return callFormatItem(
|
|
476
|
+
helper.styleSubcommandTerm(helper.subcommandTerm(cmd)),
|
|
477
|
+
helper.styleSubcommandDescription(helper.subcommandDescription(cmd)),
|
|
447
478
|
);
|
|
448
479
|
});
|
|
449
480
|
if (commandList.length > 0) {
|
|
450
|
-
output = output.concat([
|
|
481
|
+
output = output.concat([
|
|
482
|
+
helper.styleTitle('Commands:'),
|
|
483
|
+
...commandList,
|
|
484
|
+
'',
|
|
485
|
+
]);
|
|
451
486
|
}
|
|
452
487
|
|
|
453
488
|
return output.join('\n');
|
|
454
489
|
}
|
|
455
490
|
|
|
491
|
+
/**
|
|
492
|
+
* Return display width of string, ignoring ANSI escape sequences. Used in padding and wrapping calculations.
|
|
493
|
+
*
|
|
494
|
+
* @param {string} str
|
|
495
|
+
* @returns {number}
|
|
496
|
+
*/
|
|
497
|
+
displayWidth(str) {
|
|
498
|
+
return stripColor(str).length;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Style the title for displaying in the help. Called with 'Usage:', 'Options:', etc.
|
|
503
|
+
*
|
|
504
|
+
* @param {string} str
|
|
505
|
+
* @returns {string}
|
|
506
|
+
*/
|
|
507
|
+
styleTitle(str) {
|
|
508
|
+
return str;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
styleUsage(str) {
|
|
512
|
+
// Usage has lots of parts the user might like to color separately! Assume default usage string which is formed like:
|
|
513
|
+
// command subcommand [options] [command] <foo> [bar]
|
|
514
|
+
return str
|
|
515
|
+
.split(' ')
|
|
516
|
+
.map((word) => {
|
|
517
|
+
if (word === '[options]') return this.styleOptionText(word);
|
|
518
|
+
if (word === '[command]') return this.styleSubcommandText(word);
|
|
519
|
+
if (word[0] === '[' || word[0] === '<')
|
|
520
|
+
return this.styleArgumentText(word);
|
|
521
|
+
return this.styleCommandText(word); // Restrict to initial words?
|
|
522
|
+
})
|
|
523
|
+
.join(' ');
|
|
524
|
+
}
|
|
525
|
+
styleCommandDescription(str) {
|
|
526
|
+
return this.styleDescriptionText(str);
|
|
527
|
+
}
|
|
528
|
+
styleOptionDescription(str) {
|
|
529
|
+
return this.styleDescriptionText(str);
|
|
530
|
+
}
|
|
531
|
+
styleSubcommandDescription(str) {
|
|
532
|
+
return this.styleDescriptionText(str);
|
|
533
|
+
}
|
|
534
|
+
styleArgumentDescription(str) {
|
|
535
|
+
return this.styleDescriptionText(str);
|
|
536
|
+
}
|
|
537
|
+
styleDescriptionText(str) {
|
|
538
|
+
return str;
|
|
539
|
+
}
|
|
540
|
+
styleOptionTerm(str) {
|
|
541
|
+
return this.styleOptionText(str);
|
|
542
|
+
}
|
|
543
|
+
styleSubcommandTerm(str) {
|
|
544
|
+
// This is very like usage with lots of parts! Assume default string which is formed like:
|
|
545
|
+
// subcommand [options] <foo> [bar]
|
|
546
|
+
return str
|
|
547
|
+
.split(' ')
|
|
548
|
+
.map((word) => {
|
|
549
|
+
if (word === '[options]') return this.styleOptionText(word);
|
|
550
|
+
if (word[0] === '[' || word[0] === '<')
|
|
551
|
+
return this.styleArgumentText(word);
|
|
552
|
+
return this.styleSubcommandText(word); // Restrict to initial words?
|
|
553
|
+
})
|
|
554
|
+
.join(' ');
|
|
555
|
+
}
|
|
556
|
+
styleArgumentTerm(str) {
|
|
557
|
+
return this.styleArgumentText(str);
|
|
558
|
+
}
|
|
559
|
+
styleOptionText(str) {
|
|
560
|
+
return str;
|
|
561
|
+
}
|
|
562
|
+
styleArgumentText(str) {
|
|
563
|
+
return str;
|
|
564
|
+
}
|
|
565
|
+
styleSubcommandText(str) {
|
|
566
|
+
return str;
|
|
567
|
+
}
|
|
568
|
+
styleCommandText(str) {
|
|
569
|
+
return str;
|
|
570
|
+
}
|
|
571
|
+
|
|
456
572
|
/**
|
|
457
573
|
* Calculate the pad width from the maximum term length.
|
|
458
574
|
*
|
|
@@ -471,50 +587,123 @@ class Help {
|
|
|
471
587
|
}
|
|
472
588
|
|
|
473
589
|
/**
|
|
474
|
-
*
|
|
475
|
-
* Do not wrap if insufficient room for wrapping (minColumnWidth), or string is manually formatted.
|
|
590
|
+
* Detect manually wrapped and indented strings by checking for line break followed by whitespace.
|
|
476
591
|
*
|
|
477
592
|
* @param {string} str
|
|
478
|
-
* @
|
|
479
|
-
* @param {number} indent
|
|
480
|
-
* @param {number} [minColumnWidth=40]
|
|
481
|
-
* @return {string}
|
|
482
|
-
*
|
|
593
|
+
* @returns {boolean}
|
|
483
594
|
*/
|
|
595
|
+
preformatted(str) {
|
|
596
|
+
return /\n[^\S\r\n]/.test(str);
|
|
597
|
+
}
|
|
484
598
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
const
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
599
|
+
/**
|
|
600
|
+
* Format the "item", which consists of a term and description. Pad the term and wrap the description, indenting the following lines.
|
|
601
|
+
*
|
|
602
|
+
* So "TTT", 5, "DDD DDDD DD DDD" might be formatted for this.helpWidth=17 like so:
|
|
603
|
+
* TTT DDD DDDD
|
|
604
|
+
* DD DDD
|
|
605
|
+
*
|
|
606
|
+
* @param {string} term
|
|
607
|
+
* @param {number} termWidth
|
|
608
|
+
* @param {string} description
|
|
609
|
+
* @param {Help} helper
|
|
610
|
+
* @returns {string}
|
|
611
|
+
*/
|
|
612
|
+
formatItem(term, termWidth, description, helper) {
|
|
613
|
+
const itemIndent = 2;
|
|
614
|
+
const itemIndentStr = ' '.repeat(itemIndent);
|
|
615
|
+
if (!description) return itemIndentStr + term;
|
|
616
|
+
|
|
617
|
+
// Pad the term out to a consistent width, so descriptions are aligned.
|
|
618
|
+
const paddedTerm = term.padEnd(
|
|
619
|
+
termWidth + term.length - helper.displayWidth(term),
|
|
506
620
|
);
|
|
507
|
-
|
|
621
|
+
|
|
622
|
+
// Format the description.
|
|
623
|
+
const spacerWidth = 2; // between term and description
|
|
624
|
+
const helpWidth = this.helpWidth ?? 80; // in case prepareContext() was not called
|
|
625
|
+
const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent;
|
|
626
|
+
let formattedDescription;
|
|
627
|
+
if (
|
|
628
|
+
remainingWidth < this.minWidthToWrap ||
|
|
629
|
+
helper.preformatted(description)
|
|
630
|
+
) {
|
|
631
|
+
formattedDescription = description;
|
|
632
|
+
} else {
|
|
633
|
+
const wrappedDescription = helper.boxWrap(description, remainingWidth);
|
|
634
|
+
formattedDescription = wrappedDescription.replace(
|
|
635
|
+
/\n/g,
|
|
636
|
+
'\n' + ' '.repeat(termWidth + spacerWidth),
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Construct and overall indent.
|
|
508
641
|
return (
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
return (i > 0 ? indentString : '') + line.trimEnd();
|
|
514
|
-
})
|
|
515
|
-
.join('\n')
|
|
642
|
+
itemIndentStr +
|
|
643
|
+
paddedTerm +
|
|
644
|
+
' '.repeat(spacerWidth) +
|
|
645
|
+
formattedDescription.replace(/\n/g, `\n${itemIndentStr}`)
|
|
516
646
|
);
|
|
517
647
|
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Wrap a string at whitespace, preserving existing line breaks.
|
|
651
|
+
* Wrapping is skipped if the width is less than `minWidthToWrap`.
|
|
652
|
+
*
|
|
653
|
+
* @param {string} str
|
|
654
|
+
* @param {number} width
|
|
655
|
+
* @returns {string}
|
|
656
|
+
*/
|
|
657
|
+
boxWrap(str, width) {
|
|
658
|
+
if (width < this.minWidthToWrap) return str;
|
|
659
|
+
|
|
660
|
+
const rawLines = str.split(/\r\n|\n/);
|
|
661
|
+
// split up text by whitespace
|
|
662
|
+
const chunkPattern = /[\s]*[^\s]+/g;
|
|
663
|
+
const wrappedLines = [];
|
|
664
|
+
rawLines.forEach((line) => {
|
|
665
|
+
const chunks = line.match(chunkPattern);
|
|
666
|
+
if (chunks === null) {
|
|
667
|
+
wrappedLines.push('');
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
let sumChunks = [chunks.shift()];
|
|
672
|
+
let sumWidth = this.displayWidth(sumChunks[0]);
|
|
673
|
+
chunks.forEach((chunk) => {
|
|
674
|
+
const visibleWidth = this.displayWidth(chunk);
|
|
675
|
+
// Accumulate chunks while they fit into width.
|
|
676
|
+
if (sumWidth + visibleWidth <= width) {
|
|
677
|
+
sumChunks.push(chunk);
|
|
678
|
+
sumWidth += visibleWidth;
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
wrappedLines.push(sumChunks.join(''));
|
|
682
|
+
|
|
683
|
+
const nextChunk = chunk.trimStart(); // trim space at line break
|
|
684
|
+
sumChunks = [nextChunk];
|
|
685
|
+
sumWidth = this.displayWidth(nextChunk);
|
|
686
|
+
});
|
|
687
|
+
wrappedLines.push(sumChunks.join(''));
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
return wrappedLines.join('\n');
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Strip style ANSI escape sequences from the string. In particular, SGR (Select Graphic Rendition) codes.
|
|
696
|
+
*
|
|
697
|
+
* @param {string} str
|
|
698
|
+
* @returns {string}
|
|
699
|
+
* @package
|
|
700
|
+
*/
|
|
701
|
+
|
|
702
|
+
function stripColor(str) {
|
|
703
|
+
// eslint-disable-next-line no-control-regex
|
|
704
|
+
const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
|
|
705
|
+
return str.replace(sgrPattern, '');
|
|
518
706
|
}
|
|
519
707
|
|
|
520
708
|
exports.Help = Help;
|
|
709
|
+
exports.stripColor = stripColor;
|
package/lib/option.js
CHANGED
|
@@ -207,13 +207,16 @@ class Option {
|
|
|
207
207
|
|
|
208
208
|
/**
|
|
209
209
|
* Return option name, in a camelcase format that can be used
|
|
210
|
-
* as
|
|
210
|
+
* as an object attribute key.
|
|
211
211
|
*
|
|
212
212
|
* @return {string}
|
|
213
213
|
*/
|
|
214
214
|
|
|
215
215
|
attributeName() {
|
|
216
|
-
|
|
216
|
+
if (this.negate) {
|
|
217
|
+
return camelcase(this.name().replace(/^no-/, ''));
|
|
218
|
+
}
|
|
219
|
+
return camelcase(this.name());
|
|
217
220
|
}
|
|
218
221
|
|
|
219
222
|
/**
|
|
@@ -312,17 +315,32 @@ function camelcase(str) {
|
|
|
312
315
|
function splitOptionFlags(flags) {
|
|
313
316
|
let shortFlag;
|
|
314
317
|
let longFlag;
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
318
|
+
// short flag, single dash and single character
|
|
319
|
+
const shortFlagExp = /^-[^-]$/;
|
|
320
|
+
// long flag, double dash and at least one character
|
|
321
|
+
const longFlagExp = /^--[^-]/;
|
|
322
|
+
|
|
323
|
+
const flagParts = flags.split(/[ |,]+/).concat('guard');
|
|
324
|
+
if (shortFlagExp.test(flagParts[0])) shortFlag = flagParts.shift();
|
|
325
|
+
if (longFlagExp.test(flagParts[0])) longFlag = flagParts.shift();
|
|
326
|
+
|
|
327
|
+
// Check for some unsupported flags that people try.
|
|
328
|
+
if (/^-[^-][^-]/.test(flagParts[0]))
|
|
329
|
+
throw new Error(
|
|
330
|
+
`invalid Option flags, short option is dash and single character: '${flags}'`,
|
|
331
|
+
);
|
|
332
|
+
if (shortFlag && shortFlagExp.test(flagParts[0]))
|
|
333
|
+
throw new Error(
|
|
334
|
+
`invalid Option flags, more than one short flag: '${flags}'`,
|
|
335
|
+
);
|
|
336
|
+
if (longFlag && longFlagExp.test(flagParts[0]))
|
|
337
|
+
throw new Error(
|
|
338
|
+
`invalid Option flags, more than one long flag: '${flags}'`,
|
|
339
|
+
);
|
|
340
|
+
// Generic error if failed to find a flag or an unexpected flag left over.
|
|
341
|
+
if (!(shortFlag || longFlag) || flagParts[0].startsWith('-'))
|
|
342
|
+
throw new Error(`invalid Option flags: '${flags}'`);
|
|
343
|
+
|
|
326
344
|
return { shortFlag, longFlag };
|
|
327
345
|
}
|
|
328
346
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "commander",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0-0",
|
|
4
4
|
"description": "the complete solution for node.js command-line programs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"commander",
|
|
@@ -60,21 +60,19 @@
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@eslint/js": "^
|
|
63
|
+
"@eslint/js": "^9.4.0",
|
|
64
64
|
"@types/jest": "^29.2.4",
|
|
65
|
-
"@types/node": "^
|
|
66
|
-
"eslint": "^8.
|
|
65
|
+
"@types/node": "^22.7.4",
|
|
66
|
+
"eslint": "^8.57.1",
|
|
67
67
|
"eslint-config-prettier": "^9.1.0",
|
|
68
68
|
"eslint-plugin-jest": "^28.3.0",
|
|
69
|
-
"
|
|
70
|
-
"globals": "^13.24.0",
|
|
69
|
+
"globals": "^15.7.0",
|
|
71
70
|
"jest": "^29.3.1",
|
|
72
71
|
"prettier": "^3.2.5",
|
|
73
|
-
"prettier-plugin-jsdoc": "^1.3.0",
|
|
74
72
|
"ts-jest": "^29.0.3",
|
|
75
73
|
"tsd": "^0.31.0",
|
|
76
74
|
"typescript": "^5.0.4",
|
|
77
|
-
"typescript-eslint": "^
|
|
75
|
+
"typescript-eslint": "^8.12.2"
|
|
78
76
|
},
|
|
79
77
|
"types": "typings/index.d.ts",
|
|
80
78
|
"engines": {
|
package/typings/index.d.ts
CHANGED
|
@@ -190,7 +190,7 @@ export class Option {
|
|
|
190
190
|
|
|
191
191
|
/**
|
|
192
192
|
* Return option name, in a camelcase format that can be used
|
|
193
|
-
* as
|
|
193
|
+
* as an object attribute key.
|
|
194
194
|
*/
|
|
195
195
|
attributeName(): string;
|
|
196
196
|
|
|
@@ -205,12 +205,25 @@ export class Option {
|
|
|
205
205
|
export class Help {
|
|
206
206
|
/** output helpWidth, long lines are wrapped to fit */
|
|
207
207
|
helpWidth?: number;
|
|
208
|
+
minWidthToWrap: number;
|
|
208
209
|
sortSubcommands: boolean;
|
|
209
210
|
sortOptions: boolean;
|
|
210
211
|
showGlobalOptions: boolean;
|
|
211
212
|
|
|
212
213
|
constructor();
|
|
213
214
|
|
|
215
|
+
/*
|
|
216
|
+
* prepareContext is called by Commander after applying overrides from `Command.configureHelp()`
|
|
217
|
+
* and just before calling `formatHelp()`.
|
|
218
|
+
*
|
|
219
|
+
* Commander just uses the helpWidth and the others are provided for subclasses.
|
|
220
|
+
*/
|
|
221
|
+
prepareContext(contextOptions: {
|
|
222
|
+
error?: boolean;
|
|
223
|
+
helpWidth?: number;
|
|
224
|
+
outputHasColors?: boolean;
|
|
225
|
+
}): void;
|
|
226
|
+
|
|
214
227
|
/** Get the command term to show in the list of subcommands. */
|
|
215
228
|
subcommandTerm(cmd: Command): string;
|
|
216
229
|
/** Get the command summary to show in the list of subcommands. */
|
|
@@ -246,18 +259,60 @@ export class Help {
|
|
|
246
259
|
longestGlobalOptionTermLength(cmd: Command, helper: Help): number;
|
|
247
260
|
/** Get the longest argument term length. */
|
|
248
261
|
longestArgumentTermLength(cmd: Command, helper: Help): number;
|
|
262
|
+
|
|
263
|
+
/** Return display width of string, ignoring ANSI escape sequences. Used in padding and wrapping calculations. */
|
|
264
|
+
displayWidth(str: string): number;
|
|
265
|
+
|
|
266
|
+
/** Style the titles. Called with 'Usage:', 'Options:', etc. */
|
|
267
|
+
styleTitle(title: string): string;
|
|
268
|
+
|
|
269
|
+
/** Usage: <str> */
|
|
270
|
+
styleUsage(str: string): string;
|
|
271
|
+
/** Style for command name in usage string. */
|
|
272
|
+
styleCommandText(str: string): string;
|
|
273
|
+
|
|
274
|
+
styleCommandDescription(str: string): string;
|
|
275
|
+
styleOptionDescription(str: string): string;
|
|
276
|
+
styleSubcommandDescription(str: string): string;
|
|
277
|
+
styleArgumentDescription(str: string): string;
|
|
278
|
+
/** Base style used by descriptions. */
|
|
279
|
+
styleDescriptionText(str: string): string;
|
|
280
|
+
|
|
281
|
+
styleOptionTerm(str: string): string;
|
|
282
|
+
styleSubcommandTerm(str: string): string;
|
|
283
|
+
styleArgumentTerm(str: string): string;
|
|
284
|
+
|
|
285
|
+
/** Base style used in terms and usage for options. */
|
|
286
|
+
styleOptionText(str: string): string;
|
|
287
|
+
/** Base style used in terms and usage for subcommands. */
|
|
288
|
+
styleSubcommandText(str: string): string;
|
|
289
|
+
/** Base style used in terms and usage for arguments. */
|
|
290
|
+
styleArgumentText(str: string): string;
|
|
291
|
+
|
|
249
292
|
/** Calculate the pad width from the maximum term length. */
|
|
250
293
|
padWidth(cmd: Command, helper: Help): number;
|
|
251
294
|
|
|
252
295
|
/**
|
|
253
|
-
* Wrap
|
|
254
|
-
*
|
|
296
|
+
* Wrap a string at whitespace, preserving existing line breaks.
|
|
297
|
+
* Wrapping is skipped if the width is less than `minWidthToWrap`.
|
|
255
298
|
*/
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
299
|
+
boxWrap(str: string, width: number): string;
|
|
300
|
+
|
|
301
|
+
/** Detect manually wrapped and indented strings by checking for line break followed by whitespace. */
|
|
302
|
+
preformatted(str: string): boolean;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Format the "item", which consists of a term and description. Pad the term and wrap the description, indenting the following lines.
|
|
306
|
+
*
|
|
307
|
+
* So "TTT", 5, "DDD DDDD DD DDD" might be formatted for this.helpWidth=17 like so:
|
|
308
|
+
* TTT DDD DDDD
|
|
309
|
+
* DD DDD
|
|
310
|
+
*/
|
|
311
|
+
formatItem(
|
|
312
|
+
term: string,
|
|
313
|
+
termWidth: number,
|
|
314
|
+
description: string,
|
|
315
|
+
helper: Help,
|
|
261
316
|
): string;
|
|
262
317
|
|
|
263
318
|
/** Generate the built-in help text. */
|
|
@@ -280,9 +335,14 @@ export interface AddHelpTextContext {
|
|
|
280
335
|
export interface OutputConfiguration {
|
|
281
336
|
writeOut?(str: string): void;
|
|
282
337
|
writeErr?(str: string): void;
|
|
338
|
+
outputError?(str: string, write: (str: string) => void): void;
|
|
339
|
+
|
|
283
340
|
getOutHelpWidth?(): number;
|
|
284
341
|
getErrHelpWidth?(): number;
|
|
285
|
-
|
|
342
|
+
|
|
343
|
+
getOutHasColors?(): boolean;
|
|
344
|
+
getErrHasColors?(): boolean;
|
|
345
|
+
stripColor?(str: string): string;
|
|
286
346
|
}
|
|
287
347
|
|
|
288
348
|
export type AddHelpTextPosition = 'beforeAll' | 'before' | 'after' | 'afterAll';
|
|
@@ -544,7 +604,7 @@ export class Command {
|
|
|
544
604
|
*
|
|
545
605
|
* @returns `this` command for chaining
|
|
546
606
|
*/
|
|
547
|
-
action(fn: (...args: any[]) => void | Promise<void>): this;
|
|
607
|
+
action(fn: (this: this, ...args: any[]) => void | Promise<void>): this;
|
|
548
608
|
|
|
549
609
|
/**
|
|
550
610
|
* Define option with `flags`, `description`, and optional argument parsing function or `defaultValue` or both.
|