@guanghechen/commander 4.1.0 → 4.3.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/CHANGELOG.md +18 -0
- package/README.md +23 -0
- package/lib/cjs/index.cjs +346 -79
- package/lib/esm/index.mjs +346 -81
- package/lib/types/index.d.ts +60 -4
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- feat: add fluent help examples and styled help renderer
|
|
8
|
+
|
|
9
|
+
## 4.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- feat(reporter): add setFlight API for flight tracking feat(commander): unify builtin config for
|
|
14
|
+
options and commands
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies:
|
|
19
|
+
- @guanghechen/reporter@3.3.0
|
|
20
|
+
|
|
3
21
|
## 4.1.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -202,6 +202,29 @@ new Command({ name: 'example', description: 'Option types demo' })
|
|
|
202
202
|
})
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
+
### Help Examples
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import { Command } from '@guanghechen/commander'
|
|
209
|
+
|
|
210
|
+
const cli = new Command({ name: 'mycli', desc: 'My CLI tool' })
|
|
211
|
+
|
|
212
|
+
cli
|
|
213
|
+
.example('Initialize Project', 'init my-app', 'Create project scaffold')
|
|
214
|
+
.example('Watch Build', 'build --watch', 'Rebuild on file changes')
|
|
215
|
+
.action(() => {})
|
|
216
|
+
|
|
217
|
+
await cli.run({ argv: ['--help'], envs: process.env })
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`usage` 是相对当前 command path 的片段,help 中会自动补齐前缀,例如 `mycli build --watch`。
|
|
221
|
+
|
|
222
|
+
`--color` / `--no-color` 仅控制 help 文本的终端着色;
|
|
223
|
+
`--log-colorful` / `--no-log-colorful` 控制 `Reporter` 的日志着色。
|
|
224
|
+
|
|
225
|
+
当环境变量 `NO_COLOR` 存在时,help 渲染默认视为 `--no-color`;
|
|
226
|
+
显式传入 `--color` 可以覆盖这个默认值。
|
|
227
|
+
|
|
205
228
|
## Reference
|
|
206
229
|
|
|
207
230
|
- [homepage][homepage]
|
package/lib/cjs/index.cjs
CHANGED
|
@@ -24,6 +24,69 @@ function _interopNamespaceDefault(e) {
|
|
|
24
24
|
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
25
25
|
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
26
26
|
|
|
27
|
+
const TERMINAL_STYLE = {
|
|
28
|
+
bold: '\x1b[1m',
|
|
29
|
+
italic: '\x1b[3m',
|
|
30
|
+
underline: '\x1b[4m',
|
|
31
|
+
cyan: '\x1b[36m',
|
|
32
|
+
dim: '\x1b[2m',
|
|
33
|
+
reset: '\x1b[0m',
|
|
34
|
+
};
|
|
35
|
+
function styleText(text, ...styles) {
|
|
36
|
+
return `${styles.join('')}${text}${TERMINAL_STYLE.reset}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const logLevelOption = {
|
|
40
|
+
long: 'logLevel',
|
|
41
|
+
type: 'string',
|
|
42
|
+
args: 'required',
|
|
43
|
+
desc: 'Set log level',
|
|
44
|
+
default: 'info',
|
|
45
|
+
choices: reporter.LOG_LEVELS,
|
|
46
|
+
coerce: (raw) => {
|
|
47
|
+
const level = reporter.resolveLogLevel(raw);
|
|
48
|
+
if (level === undefined) {
|
|
49
|
+
throw new Error(`Invalid log level: ${raw}`);
|
|
50
|
+
}
|
|
51
|
+
return level;
|
|
52
|
+
},
|
|
53
|
+
apply: (value, ctx) => {
|
|
54
|
+
ctx.reporter.setLevel(value);
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
const logDateOption = {
|
|
58
|
+
long: 'logDate',
|
|
59
|
+
type: 'boolean',
|
|
60
|
+
args: 'none',
|
|
61
|
+
desc: 'Enable log timestamp',
|
|
62
|
+
default: true,
|
|
63
|
+
apply: (value, ctx) => {
|
|
64
|
+
ctx.reporter.setFlight({ date: Boolean(value) });
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
const logColorfulOption = {
|
|
68
|
+
long: 'logColorful',
|
|
69
|
+
type: 'boolean',
|
|
70
|
+
args: 'none',
|
|
71
|
+
desc: 'Enable colorful log output',
|
|
72
|
+
default: true,
|
|
73
|
+
apply: (value, ctx) => {
|
|
74
|
+
ctx.reporter.setFlight({ color: Boolean(value) });
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
const silentOption = {
|
|
78
|
+
long: 'silent',
|
|
79
|
+
type: 'boolean',
|
|
80
|
+
args: 'none',
|
|
81
|
+
desc: 'Suppress non-error output',
|
|
82
|
+
default: false,
|
|
83
|
+
apply: (value, ctx) => {
|
|
84
|
+
if (value) {
|
|
85
|
+
ctx.reporter.setLevel('error');
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
27
90
|
class CommanderError extends Error {
|
|
28
91
|
kind;
|
|
29
92
|
commandPath;
|
|
@@ -139,15 +202,92 @@ const BUILTIN_VERSION_OPTION = {
|
|
|
139
202
|
args: 'none',
|
|
140
203
|
desc: 'Show version number',
|
|
141
204
|
};
|
|
205
|
+
const BUILTIN_COLOR_OPTION = {
|
|
206
|
+
long: 'color',
|
|
207
|
+
type: 'boolean',
|
|
208
|
+
args: 'none',
|
|
209
|
+
desc: 'Enable colored help output',
|
|
210
|
+
default: true,
|
|
211
|
+
};
|
|
212
|
+
function createBuiltinOptionState(enabled) {
|
|
213
|
+
return {
|
|
214
|
+
color: enabled,
|
|
215
|
+
logLevel: enabled,
|
|
216
|
+
silent: enabled,
|
|
217
|
+
logDate: enabled,
|
|
218
|
+
logColorful: enabled,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function isNoColorEnabled(envs) {
|
|
222
|
+
return envs['NO_COLOR'] !== undefined;
|
|
223
|
+
}
|
|
224
|
+
function normalizeBuiltinConfig(builtin) {
|
|
225
|
+
const resolved = {
|
|
226
|
+
option: createBuiltinOptionState(true),
|
|
227
|
+
command: {
|
|
228
|
+
help: false,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
if (builtin === undefined) {
|
|
232
|
+
return resolved;
|
|
233
|
+
}
|
|
234
|
+
if (builtin === true) {
|
|
235
|
+
return {
|
|
236
|
+
option: createBuiltinOptionState(true),
|
|
237
|
+
command: { help: true },
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
if (builtin === false) {
|
|
241
|
+
return {
|
|
242
|
+
option: createBuiltinOptionState(false),
|
|
243
|
+
command: { help: false },
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
if (builtin.option !== undefined) {
|
|
247
|
+
if (builtin.option === false) {
|
|
248
|
+
resolved.option = createBuiltinOptionState(false);
|
|
249
|
+
}
|
|
250
|
+
else if (builtin.option === true) {
|
|
251
|
+
resolved.option = createBuiltinOptionState(true);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
if (builtin.option.color !== undefined)
|
|
255
|
+
resolved.option.color = builtin.option.color;
|
|
256
|
+
if (builtin.option.logLevel !== undefined) {
|
|
257
|
+
resolved.option.logLevel = builtin.option.logLevel;
|
|
258
|
+
}
|
|
259
|
+
if (builtin.option.silent !== undefined)
|
|
260
|
+
resolved.option.silent = builtin.option.silent;
|
|
261
|
+
if (builtin.option.logDate !== undefined)
|
|
262
|
+
resolved.option.logDate = builtin.option.logDate;
|
|
263
|
+
if (builtin.option.logColorful !== undefined) {
|
|
264
|
+
resolved.option.logColorful = builtin.option.logColorful;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (builtin.command !== undefined) {
|
|
269
|
+
if (builtin.command === false) {
|
|
270
|
+
resolved.command = { help: false };
|
|
271
|
+
}
|
|
272
|
+
else if (builtin.command === true) {
|
|
273
|
+
resolved.command = { help: true };
|
|
274
|
+
}
|
|
275
|
+
else if (builtin.command.help !== undefined) {
|
|
276
|
+
resolved.command.help = builtin.command.help;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return resolved;
|
|
280
|
+
}
|
|
142
281
|
class Command {
|
|
143
282
|
#name;
|
|
144
283
|
#desc;
|
|
145
284
|
#version;
|
|
146
|
-
#
|
|
285
|
+
#builtin;
|
|
147
286
|
#reporter;
|
|
148
287
|
#parent;
|
|
149
288
|
#options = [];
|
|
150
289
|
#arguments = [];
|
|
290
|
+
#examples = [];
|
|
151
291
|
#subcommandsList = [];
|
|
152
292
|
#subcommandsMap = new Map();
|
|
153
293
|
#action = undefined;
|
|
@@ -155,7 +295,7 @@ class Command {
|
|
|
155
295
|
this.#name = config.name ?? '';
|
|
156
296
|
this.#desc = config.desc;
|
|
157
297
|
this.#version = config.version;
|
|
158
|
-
this.#
|
|
298
|
+
this.#builtin = normalizeBuiltinConfig(config.builtin);
|
|
159
299
|
this.#reporter = config.reporter;
|
|
160
300
|
}
|
|
161
301
|
get name() {
|
|
@@ -176,6 +316,9 @@ class Command {
|
|
|
176
316
|
get arguments() {
|
|
177
317
|
return [...this.#arguments];
|
|
178
318
|
}
|
|
319
|
+
get examples() {
|
|
320
|
+
return this.#examples.map(example => ({ ...example }));
|
|
321
|
+
}
|
|
179
322
|
get subcommands() {
|
|
180
323
|
return new Map(this.#subcommandsMap);
|
|
181
324
|
}
|
|
@@ -194,8 +337,12 @@ class Command {
|
|
|
194
337
|
this.#action = fn;
|
|
195
338
|
return this;
|
|
196
339
|
}
|
|
340
|
+
example(title, usage, desc) {
|
|
341
|
+
this.#examples.push(this.#normalizeExample({ title, usage, desc }));
|
|
342
|
+
return this;
|
|
343
|
+
}
|
|
197
344
|
subcommand(name, cmd) {
|
|
198
|
-
if (this.#
|
|
345
|
+
if (this.#builtin.command.help && name === 'help') {
|
|
199
346
|
throw new CommanderError('ConfigurationError', '"help" is a reserved subcommand name when help subcommand is enabled', this.#getCommandPath());
|
|
200
347
|
}
|
|
201
348
|
if (cmd.#parent && cmd.#parent !== this) {
|
|
@@ -227,7 +374,8 @@ class Command {
|
|
|
227
374
|
const hasUserHelp = leafCommand.#options.some(o => o.long === 'help');
|
|
228
375
|
const hasUserVersion = leafCommand.#options.some(o => o.long === 'version');
|
|
229
376
|
if (!hasUserHelp && this.#hasFlag(optionTokens, 'help', 'h')) {
|
|
230
|
-
|
|
377
|
+
const helpColor = leafCommand.#resolveHelpColorOption(optionTokens, envs);
|
|
378
|
+
console.log(leafCommand.#formatHelpForDisplay({ color: helpColor }));
|
|
231
379
|
return;
|
|
232
380
|
}
|
|
233
381
|
if (!hasUserVersion && leafCommand === rootCommand && leafCommand.#version) {
|
|
@@ -254,7 +402,8 @@ class Command {
|
|
|
254
402
|
await leafCommand.#runAction(actionParams);
|
|
255
403
|
}
|
|
256
404
|
else if (leafCommand.#subcommandsList.length > 0) {
|
|
257
|
-
|
|
405
|
+
const helpColor = leafCommand.#resolveHelpColorOption(optionTokens, envs);
|
|
406
|
+
console.log(leafCommand.#formatHelpForDisplay({ color: helpColor }));
|
|
258
407
|
}
|
|
259
408
|
else {
|
|
260
409
|
throw new CommanderError('ConfigurationError', `no action defined for command "${leafCommand.#getCommandPath()}"`, leafCommand.#getCommandPath());
|
|
@@ -287,10 +436,21 @@ class Command {
|
|
|
287
436
|
return this.#parse(chain, resolveResult, ctx, restArgs);
|
|
288
437
|
}
|
|
289
438
|
formatHelp() {
|
|
290
|
-
|
|
439
|
+
return this.#renderHelpPlain(this.#buildHelpData());
|
|
440
|
+
}
|
|
441
|
+
#formatHelpForDisplay(params = {}) {
|
|
442
|
+
const { color = true } = params;
|
|
443
|
+
const helpData = this.#buildHelpData();
|
|
444
|
+
if (!this.#shouldRenderStyledHelp(color)) {
|
|
445
|
+
return this.#renderHelpPlain(helpData);
|
|
446
|
+
}
|
|
447
|
+
return this.#renderHelpTerminal(helpData);
|
|
448
|
+
}
|
|
449
|
+
#shouldRenderStyledHelp(color) {
|
|
450
|
+
return color && process.stdout.isTTY === true;
|
|
451
|
+
}
|
|
452
|
+
#buildHelpData() {
|
|
291
453
|
const allOptions = this.#getMergedOptions();
|
|
292
|
-
lines.push(this.#desc);
|
|
293
|
-
lines.push('');
|
|
294
454
|
const commandPath = this.#getCommandPath();
|
|
295
455
|
let usage = `Usage: ${commandPath}`;
|
|
296
456
|
if (allOptions.length > 0)
|
|
@@ -308,61 +468,122 @@ class Command {
|
|
|
308
468
|
usage += ` [${arg.name}...]`;
|
|
309
469
|
}
|
|
310
470
|
}
|
|
311
|
-
|
|
471
|
+
const options = [];
|
|
472
|
+
for (const opt of allOptions) {
|
|
473
|
+
const kebabLong = camelToKebabCase$1(opt.long);
|
|
474
|
+
let sig = opt.short ? `-${opt.short}, ` : ' ';
|
|
475
|
+
sig += `--${kebabLong}`;
|
|
476
|
+
if (opt.args !== 'none') {
|
|
477
|
+
sig += ' <value>';
|
|
478
|
+
}
|
|
479
|
+
let desc = opt.desc;
|
|
480
|
+
if (opt.default !== undefined && opt.type !== 'boolean') {
|
|
481
|
+
desc += ` (default: ${JSON.stringify(opt.default)})`;
|
|
482
|
+
}
|
|
483
|
+
if (opt.choices) {
|
|
484
|
+
desc += ` [choices: ${opt.choices.join(', ')}]`;
|
|
485
|
+
}
|
|
486
|
+
options.push({ sig, desc });
|
|
487
|
+
if (opt.type === 'boolean' && opt.args === 'none') {
|
|
488
|
+
options.push({
|
|
489
|
+
sig: ` --no-${kebabLong}`,
|
|
490
|
+
desc: `Negate --${kebabLong}`,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const commands = [];
|
|
495
|
+
const showHelpSubcommand = this.#builtin.command.help && this.#subcommandsList.length > 0;
|
|
496
|
+
if (showHelpSubcommand) {
|
|
497
|
+
commands.push({ name: 'help', desc: 'Show help for a command' });
|
|
498
|
+
}
|
|
499
|
+
for (const entry of this.#subcommandsList) {
|
|
500
|
+
let name = entry.name;
|
|
501
|
+
if (entry.aliases.length > 0) {
|
|
502
|
+
name += `, ${entry.aliases.join(', ')}`;
|
|
503
|
+
}
|
|
504
|
+
commands.push({ name, desc: entry.command.#desc });
|
|
505
|
+
}
|
|
506
|
+
const examples = this.#examples.map(example => ({
|
|
507
|
+
title: example.title,
|
|
508
|
+
usage: commandPath ? `${commandPath} ${example.usage}` : example.usage,
|
|
509
|
+
desc: example.desc,
|
|
510
|
+
}));
|
|
511
|
+
return {
|
|
512
|
+
desc: this.#desc,
|
|
513
|
+
usage,
|
|
514
|
+
options,
|
|
515
|
+
commands,
|
|
516
|
+
examples,
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
#renderHelpPlain(helpData) {
|
|
520
|
+
const lines = [];
|
|
521
|
+
lines.push(helpData.desc);
|
|
312
522
|
lines.push('');
|
|
313
|
-
|
|
523
|
+
lines.push(helpData.usage);
|
|
524
|
+
lines.push('');
|
|
525
|
+
if (helpData.options.length > 0) {
|
|
314
526
|
lines.push('Options:');
|
|
315
|
-
const
|
|
316
|
-
for (const
|
|
317
|
-
const kebabLong = camelToKebabCase$1(opt.long);
|
|
318
|
-
let sig = opt.short ? `-${opt.short}, ` : ' ';
|
|
319
|
-
sig += `--${kebabLong}`;
|
|
320
|
-
if (opt.args !== 'none') {
|
|
321
|
-
sig += ' <value>';
|
|
322
|
-
}
|
|
323
|
-
let desc = opt.desc;
|
|
324
|
-
if (opt.default !== undefined && opt.type !== 'boolean') {
|
|
325
|
-
desc += ` (default: ${JSON.stringify(opt.default)})`;
|
|
326
|
-
}
|
|
327
|
-
if (opt.choices) {
|
|
328
|
-
desc += ` [choices: ${opt.choices.join(', ')}]`;
|
|
329
|
-
}
|
|
330
|
-
optLines.push({ sig, desc });
|
|
331
|
-
if (opt.type === 'boolean' && opt.args === 'none') {
|
|
332
|
-
optLines.push({
|
|
333
|
-
sig: ` --no-${kebabLong}`,
|
|
334
|
-
desc: `Negate --${kebabLong}`,
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
const maxSigLen = Math.max(...optLines.map(l => l.sig.length));
|
|
339
|
-
for (const { sig, desc } of optLines) {
|
|
527
|
+
const maxSigLen = Math.max(...helpData.options.map(line => line.sig.length));
|
|
528
|
+
for (const { sig, desc } of helpData.options) {
|
|
340
529
|
const padding = ' '.repeat(maxSigLen - sig.length + 2);
|
|
341
530
|
lines.push(` ${sig}${padding}${desc}`);
|
|
342
531
|
}
|
|
343
532
|
lines.push('');
|
|
344
533
|
}
|
|
345
|
-
|
|
346
|
-
if (this.#subcommandsList.length > 0) {
|
|
534
|
+
if (helpData.commands.length > 0) {
|
|
347
535
|
lines.push('Commands:');
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
cmdLines.push({ name: 'help', desc: 'Show help for a command' });
|
|
351
|
-
}
|
|
352
|
-
for (const entry of this.#subcommandsList) {
|
|
353
|
-
let name = entry.name;
|
|
354
|
-
if (entry.aliases.length > 0) {
|
|
355
|
-
name += `, ${entry.aliases.join(', ')}`;
|
|
356
|
-
}
|
|
357
|
-
cmdLines.push({ name, desc: entry.command.#desc });
|
|
358
|
-
}
|
|
359
|
-
const maxNameLen = Math.max(...cmdLines.map(l => l.name.length));
|
|
360
|
-
for (const { name, desc } of cmdLines) {
|
|
536
|
+
const maxNameLen = Math.max(...helpData.commands.map(line => line.name.length));
|
|
537
|
+
for (const { name, desc } of helpData.commands) {
|
|
361
538
|
const padding = ' '.repeat(maxNameLen - name.length + 2);
|
|
362
539
|
lines.push(` ${name}${padding}${desc}`);
|
|
363
540
|
}
|
|
364
541
|
lines.push('');
|
|
365
542
|
}
|
|
543
|
+
if (helpData.examples.length > 0) {
|
|
544
|
+
lines.push('Examples:');
|
|
545
|
+
for (const example of helpData.examples) {
|
|
546
|
+
lines.push(` - ${example.title}`);
|
|
547
|
+
lines.push(` ${example.usage}`);
|
|
548
|
+
lines.push(` ${example.desc}`);
|
|
549
|
+
lines.push('');
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return lines.join('\n');
|
|
553
|
+
}
|
|
554
|
+
#renderHelpTerminal(helpData) {
|
|
555
|
+
const lines = [];
|
|
556
|
+
lines.push(helpData.desc);
|
|
557
|
+
lines.push('');
|
|
558
|
+
lines.push(styleText(helpData.usage, TERMINAL_STYLE.bold));
|
|
559
|
+
lines.push('');
|
|
560
|
+
if (helpData.options.length > 0) {
|
|
561
|
+
lines.push(styleText('Options:', TERMINAL_STYLE.bold, TERMINAL_STYLE.underline));
|
|
562
|
+
const maxSigLen = Math.max(...helpData.options.map(line => line.sig.length));
|
|
563
|
+
for (const { sig, desc } of helpData.options) {
|
|
564
|
+
const padding = ' '.repeat(maxSigLen - sig.length + 2);
|
|
565
|
+
lines.push(` ${styleText(sig, TERMINAL_STYLE.cyan)}${padding}${desc}`);
|
|
566
|
+
}
|
|
567
|
+
lines.push('');
|
|
568
|
+
}
|
|
569
|
+
if (helpData.commands.length > 0) {
|
|
570
|
+
lines.push(styleText('Commands:', TERMINAL_STYLE.bold, TERMINAL_STYLE.underline));
|
|
571
|
+
const maxNameLen = Math.max(...helpData.commands.map(line => line.name.length));
|
|
572
|
+
for (const { name, desc } of helpData.commands) {
|
|
573
|
+
const padding = ' '.repeat(maxNameLen - name.length + 2);
|
|
574
|
+
lines.push(` ${styleText(name, TERMINAL_STYLE.cyan)}${padding}${desc}`);
|
|
575
|
+
}
|
|
576
|
+
lines.push('');
|
|
577
|
+
}
|
|
578
|
+
if (helpData.examples.length > 0) {
|
|
579
|
+
lines.push(styleText('Examples:', TERMINAL_STYLE.bold, TERMINAL_STYLE.underline));
|
|
580
|
+
for (const example of helpData.examples) {
|
|
581
|
+
lines.push(` - ${styleText(example.title, TERMINAL_STYLE.bold)}`);
|
|
582
|
+
lines.push(` ${styleText(example.usage, TERMINAL_STYLE.cyan)}`);
|
|
583
|
+
lines.push(` ${styleText(example.desc, TERMINAL_STYLE.italic, TERMINAL_STYLE.dim)}`);
|
|
584
|
+
lines.push('');
|
|
585
|
+
}
|
|
586
|
+
}
|
|
366
587
|
return lines.join('\n');
|
|
367
588
|
}
|
|
368
589
|
getCompletionMeta() {
|
|
@@ -393,7 +614,7 @@ class Command {
|
|
|
393
614
|
};
|
|
394
615
|
}
|
|
395
616
|
#processHelpSubcommand(argv) {
|
|
396
|
-
if (!this.#
|
|
617
|
+
if (!this.#builtin.command.help)
|
|
397
618
|
return argv;
|
|
398
619
|
if (argv.length < 1 || argv[0] !== 'help')
|
|
399
620
|
return argv;
|
|
@@ -526,7 +747,7 @@ class Command {
|
|
|
526
747
|
const cmd = chain[i];
|
|
527
748
|
const includeVersion = i === 0;
|
|
528
749
|
const tokens = consumedTokens.get(cmd) ?? [];
|
|
529
|
-
const opts = cmd.#parseOptions(tokens, includeVersion);
|
|
750
|
+
const opts = cmd.#parseOptions(tokens, includeVersion, ctx.envs);
|
|
530
751
|
optsMap.set(cmd, opts);
|
|
531
752
|
for (const opt of cmd.#getMergedOptions(includeVersion)) {
|
|
532
753
|
if (opt.apply && opts[opt.long] !== undefined) {
|
|
@@ -542,9 +763,10 @@ class Command {
|
|
|
542
763
|
const { args, rawArgs } = leafCommand.#parseArguments(rawArgStrings);
|
|
543
764
|
return { ctx, opts: mergedOpts, args, rawArgs };
|
|
544
765
|
}
|
|
545
|
-
#parseOptions(tokens, includeVersion) {
|
|
766
|
+
#parseOptions(tokens, includeVersion, envs) {
|
|
546
767
|
const allOptions = this.#getMergedOptions(includeVersion);
|
|
547
768
|
const opts = {};
|
|
769
|
+
let sawColorToken = false;
|
|
548
770
|
for (const opt of allOptions) {
|
|
549
771
|
if (opt.default !== undefined) {
|
|
550
772
|
opts[opt.long] = opt.default;
|
|
@@ -572,6 +794,9 @@ class Command {
|
|
|
572
794
|
i += 1;
|
|
573
795
|
continue;
|
|
574
796
|
}
|
|
797
|
+
if (opt.long === 'color') {
|
|
798
|
+
sawColorToken = true;
|
|
799
|
+
}
|
|
575
800
|
const isNegativeToken = token.original.toLowerCase().startsWith('--no-');
|
|
576
801
|
if (isNegativeToken && !(opt.type === 'boolean' && opt.args === 'none')) {
|
|
577
802
|
throw new CommanderError('NegativeOptionType', `"--no-${camelToKebabCase$1(opt.long)}" can only be used with boolean options`, this.#getCommandPath());
|
|
@@ -648,6 +873,9 @@ class Command {
|
|
|
648
873
|
}
|
|
649
874
|
}
|
|
650
875
|
}
|
|
876
|
+
if (isNoColorEnabled(envs) && !sawColorToken && opts['color'] === true) {
|
|
877
|
+
opts['color'] = false;
|
|
878
|
+
}
|
|
651
879
|
return opts;
|
|
652
880
|
}
|
|
653
881
|
#convertValue(opt, rawValue) {
|
|
@@ -720,14 +948,34 @@ class Command {
|
|
|
720
948
|
}
|
|
721
949
|
#getMergedOptions(includeVersion = !this.#parent) {
|
|
722
950
|
const optionMap = new Map();
|
|
951
|
+
const hasUserColor = this.#options.some(o => o.long === 'color');
|
|
723
952
|
const hasUserHelp = this.#options.some(o => o.long === 'help');
|
|
724
953
|
const hasUserVersion = this.#options.some(o => o.long === 'version');
|
|
954
|
+
const hasUserLogLevel = this.#options.some(o => o.long === 'logLevel');
|
|
955
|
+
const hasUserSilent = this.#options.some(o => o.long === 'silent');
|
|
956
|
+
const hasUserLogDate = this.#options.some(o => o.long === 'logDate');
|
|
957
|
+
const hasUserLogColorful = this.#options.some(o => o.long === 'logColorful');
|
|
958
|
+
if (this.#builtin.option.color && !hasUserColor) {
|
|
959
|
+
optionMap.set('color', BUILTIN_COLOR_OPTION);
|
|
960
|
+
}
|
|
725
961
|
if (!hasUserHelp) {
|
|
726
962
|
optionMap.set('help', BUILTIN_HELP_OPTION);
|
|
727
963
|
}
|
|
728
964
|
if (!hasUserVersion && includeVersion) {
|
|
729
965
|
optionMap.set('version', BUILTIN_VERSION_OPTION);
|
|
730
966
|
}
|
|
967
|
+
if (this.#builtin.option.logLevel && !hasUserLogLevel) {
|
|
968
|
+
optionMap.set('logLevel', logLevelOption);
|
|
969
|
+
}
|
|
970
|
+
if (this.#builtin.option.silent && !hasUserSilent) {
|
|
971
|
+
optionMap.set('silent', silentOption);
|
|
972
|
+
}
|
|
973
|
+
if (this.#builtin.option.logDate && !hasUserLogDate) {
|
|
974
|
+
optionMap.set('logDate', logDateOption);
|
|
975
|
+
}
|
|
976
|
+
if (this.#builtin.option.logColorful && !hasUserLogColorful) {
|
|
977
|
+
optionMap.set('logColorful', logColorfulOption);
|
|
978
|
+
}
|
|
731
979
|
for (const opt of this.#options) {
|
|
732
980
|
optionMap.set(opt.long, opt);
|
|
733
981
|
}
|
|
@@ -803,6 +1051,21 @@ class Command {
|
|
|
803
1051
|
}
|
|
804
1052
|
}
|
|
805
1053
|
}
|
|
1054
|
+
#normalizeExample(example) {
|
|
1055
|
+
const title = example.title.trim();
|
|
1056
|
+
const usage = example.usage.trim();
|
|
1057
|
+
const desc = example.desc.trim();
|
|
1058
|
+
if (!title) {
|
|
1059
|
+
throw new CommanderError('ConfigurationError', 'example title cannot be empty', this.#getCommandPath());
|
|
1060
|
+
}
|
|
1061
|
+
if (!usage) {
|
|
1062
|
+
throw new CommanderError('ConfigurationError', 'example usage cannot be empty', this.#getCommandPath());
|
|
1063
|
+
}
|
|
1064
|
+
if (!desc) {
|
|
1065
|
+
throw new CommanderError('ConfigurationError', 'example description cannot be empty', this.#getCommandPath());
|
|
1066
|
+
}
|
|
1067
|
+
return { title, usage, desc };
|
|
1068
|
+
}
|
|
806
1069
|
async #runAction(params) {
|
|
807
1070
|
if (!this.#action)
|
|
808
1071
|
return;
|
|
@@ -819,6 +1082,34 @@ class Command {
|
|
|
819
1082
|
process.exit(1);
|
|
820
1083
|
}
|
|
821
1084
|
}
|
|
1085
|
+
#resolveHelpColorOption(tokens, envs) {
|
|
1086
|
+
const colorOption = this.#getMergedOptions().find(opt => opt.long === 'color');
|
|
1087
|
+
let color = !isNoColorEnabled(envs);
|
|
1088
|
+
if (!colorOption || colorOption.type !== 'boolean' || colorOption.args !== 'none') {
|
|
1089
|
+
return color;
|
|
1090
|
+
}
|
|
1091
|
+
for (const token of tokens) {
|
|
1092
|
+
if (token.type !== 'long' || token.name !== 'color') {
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
const eqIdx = token.resolved.indexOf('=');
|
|
1096
|
+
if (eqIdx === -1) {
|
|
1097
|
+
color = true;
|
|
1098
|
+
continue;
|
|
1099
|
+
}
|
|
1100
|
+
const value = token.resolved.slice(eqIdx + 1);
|
|
1101
|
+
if (value === 'true') {
|
|
1102
|
+
color = true;
|
|
1103
|
+
}
|
|
1104
|
+
else if (value === 'false') {
|
|
1105
|
+
color = false;
|
|
1106
|
+
}
|
|
1107
|
+
else {
|
|
1108
|
+
throw new CommanderError('InvalidBooleanValue', `invalid value "${value}" for boolean option "--color". Use "true" or "false"`, this.#getCommandPath());
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return color;
|
|
1112
|
+
}
|
|
822
1113
|
#hasFlag(tokens, longName, shortName) {
|
|
823
1114
|
for (const token of tokens) {
|
|
824
1115
|
if (token.type === 'long' && token.name === longName) {
|
|
@@ -1201,37 +1492,13 @@ class PwshCompletion {
|
|
|
1201
1492
|
}
|
|
1202
1493
|
}
|
|
1203
1494
|
|
|
1204
|
-
const logLevelOption = {
|
|
1205
|
-
long: 'logLevel',
|
|
1206
|
-
type: 'string',
|
|
1207
|
-
args: 'required',
|
|
1208
|
-
desc: 'Set log level',
|
|
1209
|
-
default: 'info',
|
|
1210
|
-
choices: reporter.LOG_LEVELS,
|
|
1211
|
-
coerce: (raw) => {
|
|
1212
|
-
const level = reporter.resolveLogLevel(raw);
|
|
1213
|
-
if (level === undefined) {
|
|
1214
|
-
throw new Error(`Invalid log level: ${raw}`);
|
|
1215
|
-
}
|
|
1216
|
-
return level;
|
|
1217
|
-
},
|
|
1218
|
-
apply: (value, ctx) => {
|
|
1219
|
-
ctx.reporter.setLevel(value);
|
|
1220
|
-
},
|
|
1221
|
-
};
|
|
1222
|
-
const silentOption = {
|
|
1223
|
-
long: 'silent',
|
|
1224
|
-
type: 'boolean',
|
|
1225
|
-
args: 'none',
|
|
1226
|
-
desc: 'Suppress non-error output',
|
|
1227
|
-
default: false,
|
|
1228
|
-
};
|
|
1229
|
-
|
|
1230
1495
|
exports.BashCompletion = BashCompletion;
|
|
1231
1496
|
exports.Command = Command;
|
|
1232
1497
|
exports.CommanderError = CommanderError;
|
|
1233
1498
|
exports.CompletionCommand = CompletionCommand;
|
|
1234
1499
|
exports.FishCompletion = FishCompletion;
|
|
1235
1500
|
exports.PwshCompletion = PwshCompletion;
|
|
1501
|
+
exports.logColorfulOption = logColorfulOption;
|
|
1502
|
+
exports.logDateOption = logDateOption;
|
|
1236
1503
|
exports.logLevelOption = logLevelOption;
|
|
1237
1504
|
exports.silentOption = silentOption;
|
package/lib/esm/index.mjs
CHANGED
|
@@ -1,7 +1,70 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LOG_LEVELS, resolveLogLevel, Reporter } from '@guanghechen/reporter';
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
|
|
5
|
+
const TERMINAL_STYLE = {
|
|
6
|
+
bold: '\x1b[1m',
|
|
7
|
+
italic: '\x1b[3m',
|
|
8
|
+
underline: '\x1b[4m',
|
|
9
|
+
cyan: '\x1b[36m',
|
|
10
|
+
dim: '\x1b[2m',
|
|
11
|
+
reset: '\x1b[0m',
|
|
12
|
+
};
|
|
13
|
+
function styleText(text, ...styles) {
|
|
14
|
+
return `${styles.join('')}${text}${TERMINAL_STYLE.reset}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const logLevelOption = {
|
|
18
|
+
long: 'logLevel',
|
|
19
|
+
type: 'string',
|
|
20
|
+
args: 'required',
|
|
21
|
+
desc: 'Set log level',
|
|
22
|
+
default: 'info',
|
|
23
|
+
choices: LOG_LEVELS,
|
|
24
|
+
coerce: (raw) => {
|
|
25
|
+
const level = resolveLogLevel(raw);
|
|
26
|
+
if (level === undefined) {
|
|
27
|
+
throw new Error(`Invalid log level: ${raw}`);
|
|
28
|
+
}
|
|
29
|
+
return level;
|
|
30
|
+
},
|
|
31
|
+
apply: (value, ctx) => {
|
|
32
|
+
ctx.reporter.setLevel(value);
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
const logDateOption = {
|
|
36
|
+
long: 'logDate',
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
args: 'none',
|
|
39
|
+
desc: 'Enable log timestamp',
|
|
40
|
+
default: true,
|
|
41
|
+
apply: (value, ctx) => {
|
|
42
|
+
ctx.reporter.setFlight({ date: Boolean(value) });
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const logColorfulOption = {
|
|
46
|
+
long: 'logColorful',
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
args: 'none',
|
|
49
|
+
desc: 'Enable colorful log output',
|
|
50
|
+
default: true,
|
|
51
|
+
apply: (value, ctx) => {
|
|
52
|
+
ctx.reporter.setFlight({ color: Boolean(value) });
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const silentOption = {
|
|
56
|
+
long: 'silent',
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
args: 'none',
|
|
59
|
+
desc: 'Suppress non-error output',
|
|
60
|
+
default: false,
|
|
61
|
+
apply: (value, ctx) => {
|
|
62
|
+
if (value) {
|
|
63
|
+
ctx.reporter.setLevel('error');
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
5
68
|
class CommanderError extends Error {
|
|
6
69
|
kind;
|
|
7
70
|
commandPath;
|
|
@@ -117,15 +180,92 @@ const BUILTIN_VERSION_OPTION = {
|
|
|
117
180
|
args: 'none',
|
|
118
181
|
desc: 'Show version number',
|
|
119
182
|
};
|
|
183
|
+
const BUILTIN_COLOR_OPTION = {
|
|
184
|
+
long: 'color',
|
|
185
|
+
type: 'boolean',
|
|
186
|
+
args: 'none',
|
|
187
|
+
desc: 'Enable colored help output',
|
|
188
|
+
default: true,
|
|
189
|
+
};
|
|
190
|
+
function createBuiltinOptionState(enabled) {
|
|
191
|
+
return {
|
|
192
|
+
color: enabled,
|
|
193
|
+
logLevel: enabled,
|
|
194
|
+
silent: enabled,
|
|
195
|
+
logDate: enabled,
|
|
196
|
+
logColorful: enabled,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function isNoColorEnabled(envs) {
|
|
200
|
+
return envs['NO_COLOR'] !== undefined;
|
|
201
|
+
}
|
|
202
|
+
function normalizeBuiltinConfig(builtin) {
|
|
203
|
+
const resolved = {
|
|
204
|
+
option: createBuiltinOptionState(true),
|
|
205
|
+
command: {
|
|
206
|
+
help: false,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
if (builtin === undefined) {
|
|
210
|
+
return resolved;
|
|
211
|
+
}
|
|
212
|
+
if (builtin === true) {
|
|
213
|
+
return {
|
|
214
|
+
option: createBuiltinOptionState(true),
|
|
215
|
+
command: { help: true },
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
if (builtin === false) {
|
|
219
|
+
return {
|
|
220
|
+
option: createBuiltinOptionState(false),
|
|
221
|
+
command: { help: false },
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (builtin.option !== undefined) {
|
|
225
|
+
if (builtin.option === false) {
|
|
226
|
+
resolved.option = createBuiltinOptionState(false);
|
|
227
|
+
}
|
|
228
|
+
else if (builtin.option === true) {
|
|
229
|
+
resolved.option = createBuiltinOptionState(true);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
if (builtin.option.color !== undefined)
|
|
233
|
+
resolved.option.color = builtin.option.color;
|
|
234
|
+
if (builtin.option.logLevel !== undefined) {
|
|
235
|
+
resolved.option.logLevel = builtin.option.logLevel;
|
|
236
|
+
}
|
|
237
|
+
if (builtin.option.silent !== undefined)
|
|
238
|
+
resolved.option.silent = builtin.option.silent;
|
|
239
|
+
if (builtin.option.logDate !== undefined)
|
|
240
|
+
resolved.option.logDate = builtin.option.logDate;
|
|
241
|
+
if (builtin.option.logColorful !== undefined) {
|
|
242
|
+
resolved.option.logColorful = builtin.option.logColorful;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (builtin.command !== undefined) {
|
|
247
|
+
if (builtin.command === false) {
|
|
248
|
+
resolved.command = { help: false };
|
|
249
|
+
}
|
|
250
|
+
else if (builtin.command === true) {
|
|
251
|
+
resolved.command = { help: true };
|
|
252
|
+
}
|
|
253
|
+
else if (builtin.command.help !== undefined) {
|
|
254
|
+
resolved.command.help = builtin.command.help;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return resolved;
|
|
258
|
+
}
|
|
120
259
|
class Command {
|
|
121
260
|
#name;
|
|
122
261
|
#desc;
|
|
123
262
|
#version;
|
|
124
|
-
#
|
|
263
|
+
#builtin;
|
|
125
264
|
#reporter;
|
|
126
265
|
#parent;
|
|
127
266
|
#options = [];
|
|
128
267
|
#arguments = [];
|
|
268
|
+
#examples = [];
|
|
129
269
|
#subcommandsList = [];
|
|
130
270
|
#subcommandsMap = new Map();
|
|
131
271
|
#action = undefined;
|
|
@@ -133,7 +273,7 @@ class Command {
|
|
|
133
273
|
this.#name = config.name ?? '';
|
|
134
274
|
this.#desc = config.desc;
|
|
135
275
|
this.#version = config.version;
|
|
136
|
-
this.#
|
|
276
|
+
this.#builtin = normalizeBuiltinConfig(config.builtin);
|
|
137
277
|
this.#reporter = config.reporter;
|
|
138
278
|
}
|
|
139
279
|
get name() {
|
|
@@ -154,6 +294,9 @@ class Command {
|
|
|
154
294
|
get arguments() {
|
|
155
295
|
return [...this.#arguments];
|
|
156
296
|
}
|
|
297
|
+
get examples() {
|
|
298
|
+
return this.#examples.map(example => ({ ...example }));
|
|
299
|
+
}
|
|
157
300
|
get subcommands() {
|
|
158
301
|
return new Map(this.#subcommandsMap);
|
|
159
302
|
}
|
|
@@ -172,8 +315,12 @@ class Command {
|
|
|
172
315
|
this.#action = fn;
|
|
173
316
|
return this;
|
|
174
317
|
}
|
|
318
|
+
example(title, usage, desc) {
|
|
319
|
+
this.#examples.push(this.#normalizeExample({ title, usage, desc }));
|
|
320
|
+
return this;
|
|
321
|
+
}
|
|
175
322
|
subcommand(name, cmd) {
|
|
176
|
-
if (this.#
|
|
323
|
+
if (this.#builtin.command.help && name === 'help') {
|
|
177
324
|
throw new CommanderError('ConfigurationError', '"help" is a reserved subcommand name when help subcommand is enabled', this.#getCommandPath());
|
|
178
325
|
}
|
|
179
326
|
if (cmd.#parent && cmd.#parent !== this) {
|
|
@@ -205,7 +352,8 @@ class Command {
|
|
|
205
352
|
const hasUserHelp = leafCommand.#options.some(o => o.long === 'help');
|
|
206
353
|
const hasUserVersion = leafCommand.#options.some(o => o.long === 'version');
|
|
207
354
|
if (!hasUserHelp && this.#hasFlag(optionTokens, 'help', 'h')) {
|
|
208
|
-
|
|
355
|
+
const helpColor = leafCommand.#resolveHelpColorOption(optionTokens, envs);
|
|
356
|
+
console.log(leafCommand.#formatHelpForDisplay({ color: helpColor }));
|
|
209
357
|
return;
|
|
210
358
|
}
|
|
211
359
|
if (!hasUserVersion && leafCommand === rootCommand && leafCommand.#version) {
|
|
@@ -232,7 +380,8 @@ class Command {
|
|
|
232
380
|
await leafCommand.#runAction(actionParams);
|
|
233
381
|
}
|
|
234
382
|
else if (leafCommand.#subcommandsList.length > 0) {
|
|
235
|
-
|
|
383
|
+
const helpColor = leafCommand.#resolveHelpColorOption(optionTokens, envs);
|
|
384
|
+
console.log(leafCommand.#formatHelpForDisplay({ color: helpColor }));
|
|
236
385
|
}
|
|
237
386
|
else {
|
|
238
387
|
throw new CommanderError('ConfigurationError', `no action defined for command "${leafCommand.#getCommandPath()}"`, leafCommand.#getCommandPath());
|
|
@@ -265,10 +414,21 @@ class Command {
|
|
|
265
414
|
return this.#parse(chain, resolveResult, ctx, restArgs);
|
|
266
415
|
}
|
|
267
416
|
formatHelp() {
|
|
268
|
-
|
|
417
|
+
return this.#renderHelpPlain(this.#buildHelpData());
|
|
418
|
+
}
|
|
419
|
+
#formatHelpForDisplay(params = {}) {
|
|
420
|
+
const { color = true } = params;
|
|
421
|
+
const helpData = this.#buildHelpData();
|
|
422
|
+
if (!this.#shouldRenderStyledHelp(color)) {
|
|
423
|
+
return this.#renderHelpPlain(helpData);
|
|
424
|
+
}
|
|
425
|
+
return this.#renderHelpTerminal(helpData);
|
|
426
|
+
}
|
|
427
|
+
#shouldRenderStyledHelp(color) {
|
|
428
|
+
return color && process.stdout.isTTY === true;
|
|
429
|
+
}
|
|
430
|
+
#buildHelpData() {
|
|
269
431
|
const allOptions = this.#getMergedOptions();
|
|
270
|
-
lines.push(this.#desc);
|
|
271
|
-
lines.push('');
|
|
272
432
|
const commandPath = this.#getCommandPath();
|
|
273
433
|
let usage = `Usage: ${commandPath}`;
|
|
274
434
|
if (allOptions.length > 0)
|
|
@@ -286,61 +446,122 @@ class Command {
|
|
|
286
446
|
usage += ` [${arg.name}...]`;
|
|
287
447
|
}
|
|
288
448
|
}
|
|
289
|
-
|
|
449
|
+
const options = [];
|
|
450
|
+
for (const opt of allOptions) {
|
|
451
|
+
const kebabLong = camelToKebabCase$1(opt.long);
|
|
452
|
+
let sig = opt.short ? `-${opt.short}, ` : ' ';
|
|
453
|
+
sig += `--${kebabLong}`;
|
|
454
|
+
if (opt.args !== 'none') {
|
|
455
|
+
sig += ' <value>';
|
|
456
|
+
}
|
|
457
|
+
let desc = opt.desc;
|
|
458
|
+
if (opt.default !== undefined && opt.type !== 'boolean') {
|
|
459
|
+
desc += ` (default: ${JSON.stringify(opt.default)})`;
|
|
460
|
+
}
|
|
461
|
+
if (opt.choices) {
|
|
462
|
+
desc += ` [choices: ${opt.choices.join(', ')}]`;
|
|
463
|
+
}
|
|
464
|
+
options.push({ sig, desc });
|
|
465
|
+
if (opt.type === 'boolean' && opt.args === 'none') {
|
|
466
|
+
options.push({
|
|
467
|
+
sig: ` --no-${kebabLong}`,
|
|
468
|
+
desc: `Negate --${kebabLong}`,
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const commands = [];
|
|
473
|
+
const showHelpSubcommand = this.#builtin.command.help && this.#subcommandsList.length > 0;
|
|
474
|
+
if (showHelpSubcommand) {
|
|
475
|
+
commands.push({ name: 'help', desc: 'Show help for a command' });
|
|
476
|
+
}
|
|
477
|
+
for (const entry of this.#subcommandsList) {
|
|
478
|
+
let name = entry.name;
|
|
479
|
+
if (entry.aliases.length > 0) {
|
|
480
|
+
name += `, ${entry.aliases.join(', ')}`;
|
|
481
|
+
}
|
|
482
|
+
commands.push({ name, desc: entry.command.#desc });
|
|
483
|
+
}
|
|
484
|
+
const examples = this.#examples.map(example => ({
|
|
485
|
+
title: example.title,
|
|
486
|
+
usage: commandPath ? `${commandPath} ${example.usage}` : example.usage,
|
|
487
|
+
desc: example.desc,
|
|
488
|
+
}));
|
|
489
|
+
return {
|
|
490
|
+
desc: this.#desc,
|
|
491
|
+
usage,
|
|
492
|
+
options,
|
|
493
|
+
commands,
|
|
494
|
+
examples,
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
#renderHelpPlain(helpData) {
|
|
498
|
+
const lines = [];
|
|
499
|
+
lines.push(helpData.desc);
|
|
290
500
|
lines.push('');
|
|
291
|
-
|
|
501
|
+
lines.push(helpData.usage);
|
|
502
|
+
lines.push('');
|
|
503
|
+
if (helpData.options.length > 0) {
|
|
292
504
|
lines.push('Options:');
|
|
293
|
-
const
|
|
294
|
-
for (const
|
|
295
|
-
const kebabLong = camelToKebabCase$1(opt.long);
|
|
296
|
-
let sig = opt.short ? `-${opt.short}, ` : ' ';
|
|
297
|
-
sig += `--${kebabLong}`;
|
|
298
|
-
if (opt.args !== 'none') {
|
|
299
|
-
sig += ' <value>';
|
|
300
|
-
}
|
|
301
|
-
let desc = opt.desc;
|
|
302
|
-
if (opt.default !== undefined && opt.type !== 'boolean') {
|
|
303
|
-
desc += ` (default: ${JSON.stringify(opt.default)})`;
|
|
304
|
-
}
|
|
305
|
-
if (opt.choices) {
|
|
306
|
-
desc += ` [choices: ${opt.choices.join(', ')}]`;
|
|
307
|
-
}
|
|
308
|
-
optLines.push({ sig, desc });
|
|
309
|
-
if (opt.type === 'boolean' && opt.args === 'none') {
|
|
310
|
-
optLines.push({
|
|
311
|
-
sig: ` --no-${kebabLong}`,
|
|
312
|
-
desc: `Negate --${kebabLong}`,
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
const maxSigLen = Math.max(...optLines.map(l => l.sig.length));
|
|
317
|
-
for (const { sig, desc } of optLines) {
|
|
505
|
+
const maxSigLen = Math.max(...helpData.options.map(line => line.sig.length));
|
|
506
|
+
for (const { sig, desc } of helpData.options) {
|
|
318
507
|
const padding = ' '.repeat(maxSigLen - sig.length + 2);
|
|
319
508
|
lines.push(` ${sig}${padding}${desc}`);
|
|
320
509
|
}
|
|
321
510
|
lines.push('');
|
|
322
511
|
}
|
|
323
|
-
|
|
324
|
-
if (this.#subcommandsList.length > 0) {
|
|
512
|
+
if (helpData.commands.length > 0) {
|
|
325
513
|
lines.push('Commands:');
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
cmdLines.push({ name: 'help', desc: 'Show help for a command' });
|
|
329
|
-
}
|
|
330
|
-
for (const entry of this.#subcommandsList) {
|
|
331
|
-
let name = entry.name;
|
|
332
|
-
if (entry.aliases.length > 0) {
|
|
333
|
-
name += `, ${entry.aliases.join(', ')}`;
|
|
334
|
-
}
|
|
335
|
-
cmdLines.push({ name, desc: entry.command.#desc });
|
|
336
|
-
}
|
|
337
|
-
const maxNameLen = Math.max(...cmdLines.map(l => l.name.length));
|
|
338
|
-
for (const { name, desc } of cmdLines) {
|
|
514
|
+
const maxNameLen = Math.max(...helpData.commands.map(line => line.name.length));
|
|
515
|
+
for (const { name, desc } of helpData.commands) {
|
|
339
516
|
const padding = ' '.repeat(maxNameLen - name.length + 2);
|
|
340
517
|
lines.push(` ${name}${padding}${desc}`);
|
|
341
518
|
}
|
|
342
519
|
lines.push('');
|
|
343
520
|
}
|
|
521
|
+
if (helpData.examples.length > 0) {
|
|
522
|
+
lines.push('Examples:');
|
|
523
|
+
for (const example of helpData.examples) {
|
|
524
|
+
lines.push(` - ${example.title}`);
|
|
525
|
+
lines.push(` ${example.usage}`);
|
|
526
|
+
lines.push(` ${example.desc}`);
|
|
527
|
+
lines.push('');
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return lines.join('\n');
|
|
531
|
+
}
|
|
532
|
+
#renderHelpTerminal(helpData) {
|
|
533
|
+
const lines = [];
|
|
534
|
+
lines.push(helpData.desc);
|
|
535
|
+
lines.push('');
|
|
536
|
+
lines.push(styleText(helpData.usage, TERMINAL_STYLE.bold));
|
|
537
|
+
lines.push('');
|
|
538
|
+
if (helpData.options.length > 0) {
|
|
539
|
+
lines.push(styleText('Options:', TERMINAL_STYLE.bold, TERMINAL_STYLE.underline));
|
|
540
|
+
const maxSigLen = Math.max(...helpData.options.map(line => line.sig.length));
|
|
541
|
+
for (const { sig, desc } of helpData.options) {
|
|
542
|
+
const padding = ' '.repeat(maxSigLen - sig.length + 2);
|
|
543
|
+
lines.push(` ${styleText(sig, TERMINAL_STYLE.cyan)}${padding}${desc}`);
|
|
544
|
+
}
|
|
545
|
+
lines.push('');
|
|
546
|
+
}
|
|
547
|
+
if (helpData.commands.length > 0) {
|
|
548
|
+
lines.push(styleText('Commands:', TERMINAL_STYLE.bold, TERMINAL_STYLE.underline));
|
|
549
|
+
const maxNameLen = Math.max(...helpData.commands.map(line => line.name.length));
|
|
550
|
+
for (const { name, desc } of helpData.commands) {
|
|
551
|
+
const padding = ' '.repeat(maxNameLen - name.length + 2);
|
|
552
|
+
lines.push(` ${styleText(name, TERMINAL_STYLE.cyan)}${padding}${desc}`);
|
|
553
|
+
}
|
|
554
|
+
lines.push('');
|
|
555
|
+
}
|
|
556
|
+
if (helpData.examples.length > 0) {
|
|
557
|
+
lines.push(styleText('Examples:', TERMINAL_STYLE.bold, TERMINAL_STYLE.underline));
|
|
558
|
+
for (const example of helpData.examples) {
|
|
559
|
+
lines.push(` - ${styleText(example.title, TERMINAL_STYLE.bold)}`);
|
|
560
|
+
lines.push(` ${styleText(example.usage, TERMINAL_STYLE.cyan)}`);
|
|
561
|
+
lines.push(` ${styleText(example.desc, TERMINAL_STYLE.italic, TERMINAL_STYLE.dim)}`);
|
|
562
|
+
lines.push('');
|
|
563
|
+
}
|
|
564
|
+
}
|
|
344
565
|
return lines.join('\n');
|
|
345
566
|
}
|
|
346
567
|
getCompletionMeta() {
|
|
@@ -371,7 +592,7 @@ class Command {
|
|
|
371
592
|
};
|
|
372
593
|
}
|
|
373
594
|
#processHelpSubcommand(argv) {
|
|
374
|
-
if (!this.#
|
|
595
|
+
if (!this.#builtin.command.help)
|
|
375
596
|
return argv;
|
|
376
597
|
if (argv.length < 1 || argv[0] !== 'help')
|
|
377
598
|
return argv;
|
|
@@ -504,7 +725,7 @@ class Command {
|
|
|
504
725
|
const cmd = chain[i];
|
|
505
726
|
const includeVersion = i === 0;
|
|
506
727
|
const tokens = consumedTokens.get(cmd) ?? [];
|
|
507
|
-
const opts = cmd.#parseOptions(tokens, includeVersion);
|
|
728
|
+
const opts = cmd.#parseOptions(tokens, includeVersion, ctx.envs);
|
|
508
729
|
optsMap.set(cmd, opts);
|
|
509
730
|
for (const opt of cmd.#getMergedOptions(includeVersion)) {
|
|
510
731
|
if (opt.apply && opts[opt.long] !== undefined) {
|
|
@@ -520,9 +741,10 @@ class Command {
|
|
|
520
741
|
const { args, rawArgs } = leafCommand.#parseArguments(rawArgStrings);
|
|
521
742
|
return { ctx, opts: mergedOpts, args, rawArgs };
|
|
522
743
|
}
|
|
523
|
-
#parseOptions(tokens, includeVersion) {
|
|
744
|
+
#parseOptions(tokens, includeVersion, envs) {
|
|
524
745
|
const allOptions = this.#getMergedOptions(includeVersion);
|
|
525
746
|
const opts = {};
|
|
747
|
+
let sawColorToken = false;
|
|
526
748
|
for (const opt of allOptions) {
|
|
527
749
|
if (opt.default !== undefined) {
|
|
528
750
|
opts[opt.long] = opt.default;
|
|
@@ -550,6 +772,9 @@ class Command {
|
|
|
550
772
|
i += 1;
|
|
551
773
|
continue;
|
|
552
774
|
}
|
|
775
|
+
if (opt.long === 'color') {
|
|
776
|
+
sawColorToken = true;
|
|
777
|
+
}
|
|
553
778
|
const isNegativeToken = token.original.toLowerCase().startsWith('--no-');
|
|
554
779
|
if (isNegativeToken && !(opt.type === 'boolean' && opt.args === 'none')) {
|
|
555
780
|
throw new CommanderError('NegativeOptionType', `"--no-${camelToKebabCase$1(opt.long)}" can only be used with boolean options`, this.#getCommandPath());
|
|
@@ -626,6 +851,9 @@ class Command {
|
|
|
626
851
|
}
|
|
627
852
|
}
|
|
628
853
|
}
|
|
854
|
+
if (isNoColorEnabled(envs) && !sawColorToken && opts['color'] === true) {
|
|
855
|
+
opts['color'] = false;
|
|
856
|
+
}
|
|
629
857
|
return opts;
|
|
630
858
|
}
|
|
631
859
|
#convertValue(opt, rawValue) {
|
|
@@ -698,14 +926,34 @@ class Command {
|
|
|
698
926
|
}
|
|
699
927
|
#getMergedOptions(includeVersion = !this.#parent) {
|
|
700
928
|
const optionMap = new Map();
|
|
929
|
+
const hasUserColor = this.#options.some(o => o.long === 'color');
|
|
701
930
|
const hasUserHelp = this.#options.some(o => o.long === 'help');
|
|
702
931
|
const hasUserVersion = this.#options.some(o => o.long === 'version');
|
|
932
|
+
const hasUserLogLevel = this.#options.some(o => o.long === 'logLevel');
|
|
933
|
+
const hasUserSilent = this.#options.some(o => o.long === 'silent');
|
|
934
|
+
const hasUserLogDate = this.#options.some(o => o.long === 'logDate');
|
|
935
|
+
const hasUserLogColorful = this.#options.some(o => o.long === 'logColorful');
|
|
936
|
+
if (this.#builtin.option.color && !hasUserColor) {
|
|
937
|
+
optionMap.set('color', BUILTIN_COLOR_OPTION);
|
|
938
|
+
}
|
|
703
939
|
if (!hasUserHelp) {
|
|
704
940
|
optionMap.set('help', BUILTIN_HELP_OPTION);
|
|
705
941
|
}
|
|
706
942
|
if (!hasUserVersion && includeVersion) {
|
|
707
943
|
optionMap.set('version', BUILTIN_VERSION_OPTION);
|
|
708
944
|
}
|
|
945
|
+
if (this.#builtin.option.logLevel && !hasUserLogLevel) {
|
|
946
|
+
optionMap.set('logLevel', logLevelOption);
|
|
947
|
+
}
|
|
948
|
+
if (this.#builtin.option.silent && !hasUserSilent) {
|
|
949
|
+
optionMap.set('silent', silentOption);
|
|
950
|
+
}
|
|
951
|
+
if (this.#builtin.option.logDate && !hasUserLogDate) {
|
|
952
|
+
optionMap.set('logDate', logDateOption);
|
|
953
|
+
}
|
|
954
|
+
if (this.#builtin.option.logColorful && !hasUserLogColorful) {
|
|
955
|
+
optionMap.set('logColorful', logColorfulOption);
|
|
956
|
+
}
|
|
709
957
|
for (const opt of this.#options) {
|
|
710
958
|
optionMap.set(opt.long, opt);
|
|
711
959
|
}
|
|
@@ -781,6 +1029,21 @@ class Command {
|
|
|
781
1029
|
}
|
|
782
1030
|
}
|
|
783
1031
|
}
|
|
1032
|
+
#normalizeExample(example) {
|
|
1033
|
+
const title = example.title.trim();
|
|
1034
|
+
const usage = example.usage.trim();
|
|
1035
|
+
const desc = example.desc.trim();
|
|
1036
|
+
if (!title) {
|
|
1037
|
+
throw new CommanderError('ConfigurationError', 'example title cannot be empty', this.#getCommandPath());
|
|
1038
|
+
}
|
|
1039
|
+
if (!usage) {
|
|
1040
|
+
throw new CommanderError('ConfigurationError', 'example usage cannot be empty', this.#getCommandPath());
|
|
1041
|
+
}
|
|
1042
|
+
if (!desc) {
|
|
1043
|
+
throw new CommanderError('ConfigurationError', 'example description cannot be empty', this.#getCommandPath());
|
|
1044
|
+
}
|
|
1045
|
+
return { title, usage, desc };
|
|
1046
|
+
}
|
|
784
1047
|
async #runAction(params) {
|
|
785
1048
|
if (!this.#action)
|
|
786
1049
|
return;
|
|
@@ -797,6 +1060,34 @@ class Command {
|
|
|
797
1060
|
process.exit(1);
|
|
798
1061
|
}
|
|
799
1062
|
}
|
|
1063
|
+
#resolveHelpColorOption(tokens, envs) {
|
|
1064
|
+
const colorOption = this.#getMergedOptions().find(opt => opt.long === 'color');
|
|
1065
|
+
let color = !isNoColorEnabled(envs);
|
|
1066
|
+
if (!colorOption || colorOption.type !== 'boolean' || colorOption.args !== 'none') {
|
|
1067
|
+
return color;
|
|
1068
|
+
}
|
|
1069
|
+
for (const token of tokens) {
|
|
1070
|
+
if (token.type !== 'long' || token.name !== 'color') {
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
const eqIdx = token.resolved.indexOf('=');
|
|
1074
|
+
if (eqIdx === -1) {
|
|
1075
|
+
color = true;
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
const value = token.resolved.slice(eqIdx + 1);
|
|
1079
|
+
if (value === 'true') {
|
|
1080
|
+
color = true;
|
|
1081
|
+
}
|
|
1082
|
+
else if (value === 'false') {
|
|
1083
|
+
color = false;
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
throw new CommanderError('InvalidBooleanValue', `invalid value "${value}" for boolean option "--color". Use "true" or "false"`, this.#getCommandPath());
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
return color;
|
|
1090
|
+
}
|
|
800
1091
|
#hasFlag(tokens, longName, shortName) {
|
|
801
1092
|
for (const token of tokens) {
|
|
802
1093
|
if (token.type === 'long' && token.name === longName) {
|
|
@@ -1179,30 +1470,4 @@ class PwshCompletion {
|
|
|
1179
1470
|
}
|
|
1180
1471
|
}
|
|
1181
1472
|
|
|
1182
|
-
|
|
1183
|
-
long: 'logLevel',
|
|
1184
|
-
type: 'string',
|
|
1185
|
-
args: 'required',
|
|
1186
|
-
desc: 'Set log level',
|
|
1187
|
-
default: 'info',
|
|
1188
|
-
choices: LOG_LEVELS,
|
|
1189
|
-
coerce: (raw) => {
|
|
1190
|
-
const level = resolveLogLevel(raw);
|
|
1191
|
-
if (level === undefined) {
|
|
1192
|
-
throw new Error(`Invalid log level: ${raw}`);
|
|
1193
|
-
}
|
|
1194
|
-
return level;
|
|
1195
|
-
},
|
|
1196
|
-
apply: (value, ctx) => {
|
|
1197
|
-
ctx.reporter.setLevel(value);
|
|
1198
|
-
},
|
|
1199
|
-
};
|
|
1200
|
-
const silentOption = {
|
|
1201
|
-
long: 'silent',
|
|
1202
|
-
type: 'boolean',
|
|
1203
|
-
args: 'none',
|
|
1204
|
-
desc: 'Suppress non-error output',
|
|
1205
|
-
default: false,
|
|
1206
|
-
};
|
|
1207
|
-
|
|
1208
|
-
export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logLevelOption, silentOption };
|
|
1473
|
+
export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -92,6 +92,37 @@ interface ICommandArgumentConfig<T = unknown> {
|
|
|
92
92
|
/** Custom value transformation (takes precedence over type conversion) */
|
|
93
93
|
coerce?: (rawValue: string) => T;
|
|
94
94
|
}
|
|
95
|
+
interface ICommandBuiltinOptionConfig {
|
|
96
|
+
/** Enable built-in --color/--no-color option for help rendering (defaults respect NO_COLOR) */
|
|
97
|
+
color?: boolean;
|
|
98
|
+
/** Enable built-in --log-level option */
|
|
99
|
+
logLevel?: boolean;
|
|
100
|
+
/** Enable built-in --silent option */
|
|
101
|
+
silent?: boolean;
|
|
102
|
+
/** Enable built-in --log-date/--no-log-date option */
|
|
103
|
+
logDate?: boolean;
|
|
104
|
+
/** Enable built-in --log-colorful/--no-log-colorful option */
|
|
105
|
+
logColorful?: boolean;
|
|
106
|
+
}
|
|
107
|
+
interface ICommandBuiltinCommandConfig {
|
|
108
|
+
/** Enable built-in help subcommand */
|
|
109
|
+
help?: boolean;
|
|
110
|
+
}
|
|
111
|
+
interface ICommandBuiltinConfig {
|
|
112
|
+
/** Built-in options configuration */
|
|
113
|
+
option?: boolean | ICommandBuiltinOptionConfig;
|
|
114
|
+
/** Built-in command configuration */
|
|
115
|
+
command?: boolean | ICommandBuiltinCommandConfig;
|
|
116
|
+
}
|
|
117
|
+
/** Command example configuration */
|
|
118
|
+
interface ICommandExample {
|
|
119
|
+
/** Example title */
|
|
120
|
+
title: string;
|
|
121
|
+
/** Usage fragment relative to command path */
|
|
122
|
+
usage: string;
|
|
123
|
+
/** Example description */
|
|
124
|
+
desc: string;
|
|
125
|
+
}
|
|
95
126
|
/** Command configuration */
|
|
96
127
|
interface ICommandConfig {
|
|
97
128
|
/** Command name (only for root command) */
|
|
@@ -100,8 +131,8 @@ interface ICommandConfig {
|
|
|
100
131
|
desc: string;
|
|
101
132
|
/** Version (for root --version) */
|
|
102
133
|
version?: string;
|
|
103
|
-
/**
|
|
104
|
-
|
|
134
|
+
/** Built-in features configuration */
|
|
135
|
+
builtin?: boolean | ICommandBuiltinConfig;
|
|
105
136
|
/** Default reporter for this command */
|
|
106
137
|
reporter?: IReporter;
|
|
107
138
|
}
|
|
@@ -113,6 +144,7 @@ interface ICommand {
|
|
|
113
144
|
readonly parent: ICommand | undefined;
|
|
114
145
|
readonly options: ICommandOptionConfig[];
|
|
115
146
|
readonly arguments: ICommandArgumentConfig[];
|
|
147
|
+
readonly examples: ICommandExample[];
|
|
116
148
|
readonly subcommands: Map<string, ICommand>;
|
|
117
149
|
}
|
|
118
150
|
/** Execution context */
|
|
@@ -263,10 +295,12 @@ declare class Command implements ICommand {
|
|
|
263
295
|
get parent(): Command | undefined;
|
|
264
296
|
get options(): ICommandOptionConfig[];
|
|
265
297
|
get arguments(): ICommandArgumentConfig[];
|
|
298
|
+
get examples(): ICommandExample[];
|
|
266
299
|
get subcommands(): Map<string, ICommand>;
|
|
267
300
|
option<T>(opt: ICommandOptionConfig<T>): this;
|
|
268
301
|
argument<T>(arg: ICommandArgumentConfig<T>): this;
|
|
269
302
|
action(fn: ICommandAction): this;
|
|
303
|
+
example(title: string, usage: string, desc: string): this;
|
|
270
304
|
subcommand(name: string, cmd: Command): this;
|
|
271
305
|
run(params: ICommandRunParams): Promise<void>;
|
|
272
306
|
parse(params: ICommandRunParams): ICommandParseResult;
|
|
@@ -355,6 +389,28 @@ declare class PwshCompletion {
|
|
|
355
389
|
* ```
|
|
356
390
|
*/
|
|
357
391
|
declare const logLevelOption: ICommandOptionConfig<string>;
|
|
392
|
+
/**
|
|
393
|
+
* Pre-defined --log-date option for controlling timestamp output.
|
|
394
|
+
*
|
|
395
|
+
* | Property | Value |
|
|
396
|
+
* | --------- | --------- |
|
|
397
|
+
* | long | 'logDate' |
|
|
398
|
+
* | type | 'boolean' |
|
|
399
|
+
* | args | 'none' |
|
|
400
|
+
* | default | true |
|
|
401
|
+
*/
|
|
402
|
+
declare const logDateOption: ICommandOptionConfig<boolean>;
|
|
403
|
+
/**
|
|
404
|
+
* Pre-defined --log-colorful option for controlling colorful output.
|
|
405
|
+
*
|
|
406
|
+
* | Property | Value |
|
|
407
|
+
* | --------- | ------------- |
|
|
408
|
+
* | long | 'logColorful' |
|
|
409
|
+
* | type | 'boolean' |
|
|
410
|
+
* | args | 'none' |
|
|
411
|
+
* | default | true |
|
|
412
|
+
*/
|
|
413
|
+
declare const logColorfulOption: ICommandOptionConfig<boolean>;
|
|
358
414
|
/**
|
|
359
415
|
* Pre-defined --silent option for suppressing non-error output.
|
|
360
416
|
*
|
|
@@ -380,5 +436,5 @@ declare const logLevelOption: ICommandOptionConfig<string>;
|
|
|
380
436
|
*/
|
|
381
437
|
declare const silentOption: ICommandOptionConfig<boolean>;
|
|
382
438
|
|
|
383
|
-
export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logLevelOption, silentOption };
|
|
384
|
-
export type { ICommand, ICommandAction, ICommandActionParams, ICommandArgumentConfig, ICommandArgumentKind, ICommandArgumentType, ICommandConfig, ICommandContext, ICommandOptionArgs, ICommandOptionConfig, ICommandOptionType, ICommandParseResult, ICommandParsedArgs, ICommandParsedOpts, ICommandResolveResult, ICommandRouteResult, ICommandRunParams, ICommandShiftResult, ICommandToken, ICommandTokenType, ICommandTokenizeResult, ICommanderErrorKind, ICompletionCommandConfig, ICompletionMeta, ICompletionOptionMeta, ICompletionPaths, ICompletionShellType };
|
|
439
|
+
export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
|
|
440
|
+
export type { ICommand, ICommandAction, ICommandActionParams, ICommandArgumentConfig, ICommandArgumentKind, ICommandArgumentType, ICommandBuiltinCommandConfig, ICommandBuiltinConfig, ICommandBuiltinOptionConfig, ICommandConfig, ICommandContext, ICommandExample, ICommandOptionArgs, ICommandOptionConfig, ICommandOptionType, ICommandParseResult, ICommandParsedArgs, ICommandParsedOpts, ICommandResolveResult, ICommandRouteResult, ICommandRunParams, ICommandShiftResult, ICommandToken, ICommandTokenType, ICommandTokenizeResult, ICommanderErrorKind, ICompletionCommandConfig, ICompletionMeta, ICompletionOptionMeta, ICompletionPaths, ICompletionShellType };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guanghechen/commander",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "A minimal, type-safe command-line interface builder with fluent API",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "guanghechen",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"README.md"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@guanghechen/reporter": "^3.
|
|
44
|
+
"@guanghechen/reporter": "^3.3.0"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "rollup -c ../../rollup.config.mjs",
|