@guanghechen/commander 4.0.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/lib/cjs/index.cjs +140 -23
- package/lib/esm/index.mjs +135 -22
- package/lib/types/index.d.ts +110 -14
- package/package.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- feat(reporter): add setFlight API for flight tracking feat(commander): unify builtin config for
|
|
8
|
+
options and commands
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- Updated dependencies:
|
|
13
|
+
- @guanghechen/reporter@3.3.0
|
|
14
|
+
|
|
15
|
+
## 4.1.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- ### @guanghechen/reporter
|
|
20
|
+
- feat: add `setLevel` method for dynamic log level change
|
|
21
|
+
- refactor: split source into modular files (`level.ts`, `chalk.ts`, `types.ts`, `reporter.ts`)
|
|
22
|
+
- refactor: move `IReporter` types from `@guanghechen/types` to `@guanghechen/reporter`
|
|
23
|
+
- export: add level utilities (`LogLevelEnum`, `ILogLevel`, `LOG_LEVELS`, `LOG_LEVEL_VALUES`,
|
|
24
|
+
`isLogLevel`, `getLogLevelValue`, `resolveLogLevel`)
|
|
25
|
+
- export: add chalk utilities (`ANSI`, `formatTag`)
|
|
26
|
+
|
|
27
|
+
### @guanghechen/types
|
|
28
|
+
- refactor: remove `IReporter` and `IReporterLevel` exports (moved to `@guanghechen/reporter`)
|
|
29
|
+
|
|
30
|
+
### @guanghechen/commander
|
|
31
|
+
- feat: add predefined options `logLevelOption` and `silentOption` with `apply` callback support
|
|
32
|
+
- refactor: use `ILogLevel` from `@guanghechen/reporter` instead of `IReporterLevel`
|
|
33
|
+
|
|
34
|
+
### Dependent packages
|
|
35
|
+
- chore: bump version for packages depending on `@guanghechen/types`, `@guanghechen/reporter`, or
|
|
36
|
+
`@guanghechen/commander`
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- Updated dependencies:
|
|
41
|
+
- @guanghechen/reporter@3.2.0
|
|
42
|
+
|
|
3
43
|
## 4.0.0
|
|
4
44
|
|
|
5
45
|
### Major Changes
|
package/lib/cjs/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var reporter = require('@guanghechen/reporter');
|
|
3
4
|
var fs = require('node:fs');
|
|
4
5
|
var path = require('node:path');
|
|
5
6
|
|
|
@@ -23,6 +24,57 @@ function _interopNamespaceDefault(e) {
|
|
|
23
24
|
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
24
25
|
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
25
26
|
|
|
27
|
+
const logLevelOption = {
|
|
28
|
+
long: 'logLevel',
|
|
29
|
+
type: 'string',
|
|
30
|
+
args: 'required',
|
|
31
|
+
desc: 'Set log level',
|
|
32
|
+
default: 'info',
|
|
33
|
+
choices: reporter.LOG_LEVELS,
|
|
34
|
+
coerce: (raw) => {
|
|
35
|
+
const level = reporter.resolveLogLevel(raw);
|
|
36
|
+
if (level === undefined) {
|
|
37
|
+
throw new Error(`Invalid log level: ${raw}`);
|
|
38
|
+
}
|
|
39
|
+
return level;
|
|
40
|
+
},
|
|
41
|
+
apply: (value, ctx) => {
|
|
42
|
+
ctx.reporter.setLevel(value);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const logDateOption = {
|
|
46
|
+
long: 'logDate',
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
args: 'none',
|
|
49
|
+
desc: 'Enable log timestamp',
|
|
50
|
+
default: true,
|
|
51
|
+
apply: (value, ctx) => {
|
|
52
|
+
ctx.reporter.setFlight({ date: Boolean(value) });
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const logColorfulOption = {
|
|
56
|
+
long: 'logColorful',
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
args: 'none',
|
|
59
|
+
desc: 'Enable colorful log output',
|
|
60
|
+
default: true,
|
|
61
|
+
apply: (value, ctx) => {
|
|
62
|
+
ctx.reporter.setFlight({ color: Boolean(value) });
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const silentOption = {
|
|
66
|
+
long: 'silent',
|
|
67
|
+
type: 'boolean',
|
|
68
|
+
args: 'none',
|
|
69
|
+
desc: 'Suppress non-error output',
|
|
70
|
+
default: false,
|
|
71
|
+
apply: (value, ctx) => {
|
|
72
|
+
if (value) {
|
|
73
|
+
ctx.reporter.setLevel('error');
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
26
78
|
class CommanderError extends Error {
|
|
27
79
|
kind;
|
|
28
80
|
commandPath;
|
|
@@ -37,20 +89,6 @@ class CommanderError extends Error {
|
|
|
37
89
|
}
|
|
38
90
|
}
|
|
39
91
|
|
|
40
|
-
class DefaultReporter {
|
|
41
|
-
debug(message, ...args) {
|
|
42
|
-
console.debug(message, ...args);
|
|
43
|
-
}
|
|
44
|
-
info(message, ...args) {
|
|
45
|
-
console.info(message, ...args);
|
|
46
|
-
}
|
|
47
|
-
warn(message, ...args) {
|
|
48
|
-
console.warn(message, ...args);
|
|
49
|
-
}
|
|
50
|
-
error(message, ...args) {
|
|
51
|
-
console.error(message, ...args);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
92
|
const LONG_OPTION_REGEX = /^--[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
55
93
|
const NEGATIVE_OPTION_REGEX = /^--no-[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
56
94
|
function kebabToCamelCase(str) {
|
|
@@ -152,11 +190,70 @@ const BUILTIN_VERSION_OPTION = {
|
|
|
152
190
|
args: 'none',
|
|
153
191
|
desc: 'Show version number',
|
|
154
192
|
};
|
|
193
|
+
function normalizeBuiltinConfig(builtin) {
|
|
194
|
+
const resolved = {
|
|
195
|
+
option: {
|
|
196
|
+
logLevel: true,
|
|
197
|
+
silent: true,
|
|
198
|
+
logDate: true,
|
|
199
|
+
logColorful: true,
|
|
200
|
+
},
|
|
201
|
+
command: {
|
|
202
|
+
help: false,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
if (builtin === undefined) {
|
|
206
|
+
return resolved;
|
|
207
|
+
}
|
|
208
|
+
if (builtin === true) {
|
|
209
|
+
return {
|
|
210
|
+
option: { logLevel: true, silent: true, logDate: true, logColorful: true },
|
|
211
|
+
command: { help: true },
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (builtin === false) {
|
|
215
|
+
return {
|
|
216
|
+
option: { logLevel: false, silent: false, logDate: false, logColorful: false },
|
|
217
|
+
command: { help: false },
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (builtin.option !== undefined) {
|
|
221
|
+
if (builtin.option === false) {
|
|
222
|
+
resolved.option = { logLevel: false, silent: false, logDate: false, logColorful: false };
|
|
223
|
+
}
|
|
224
|
+
else if (builtin.option === true) {
|
|
225
|
+
resolved.option = { logLevel: true, silent: true, logDate: true, logColorful: true };
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
if (builtin.option.logLevel !== undefined)
|
|
229
|
+
resolved.option.logLevel = builtin.option.logLevel;
|
|
230
|
+
if (builtin.option.silent !== undefined)
|
|
231
|
+
resolved.option.silent = builtin.option.silent;
|
|
232
|
+
if (builtin.option.logDate !== undefined)
|
|
233
|
+
resolved.option.logDate = builtin.option.logDate;
|
|
234
|
+
if (builtin.option.logColorful !== undefined) {
|
|
235
|
+
resolved.option.logColorful = builtin.option.logColorful;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (builtin.command !== undefined) {
|
|
240
|
+
if (builtin.command === false) {
|
|
241
|
+
resolved.command = { help: false };
|
|
242
|
+
}
|
|
243
|
+
else if (builtin.command === true) {
|
|
244
|
+
resolved.command = { help: true };
|
|
245
|
+
}
|
|
246
|
+
else if (builtin.command.help !== undefined) {
|
|
247
|
+
resolved.command.help = builtin.command.help;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return resolved;
|
|
251
|
+
}
|
|
155
252
|
class Command {
|
|
156
253
|
#name;
|
|
157
254
|
#desc;
|
|
158
255
|
#version;
|
|
159
|
-
#
|
|
256
|
+
#builtin;
|
|
160
257
|
#reporter;
|
|
161
258
|
#parent;
|
|
162
259
|
#options = [];
|
|
@@ -168,7 +265,7 @@ class Command {
|
|
|
168
265
|
this.#name = config.name ?? '';
|
|
169
266
|
this.#desc = config.desc;
|
|
170
267
|
this.#version = config.version;
|
|
171
|
-
this.#
|
|
268
|
+
this.#builtin = normalizeBuiltinConfig(config.builtin);
|
|
172
269
|
this.#reporter = config.reporter;
|
|
173
270
|
}
|
|
174
271
|
get name() {
|
|
@@ -208,7 +305,7 @@ class Command {
|
|
|
208
305
|
return this;
|
|
209
306
|
}
|
|
210
307
|
subcommand(name, cmd) {
|
|
211
|
-
if (this.#
|
|
308
|
+
if (this.#builtin.command.help && name === 'help') {
|
|
212
309
|
throw new CommanderError('ConfigurationError', '"help" is a reserved subcommand name when help subcommand is enabled', this.#getCommandPath());
|
|
213
310
|
}
|
|
214
311
|
if (cmd.#parent && cmd.#parent !== this) {
|
|
@@ -228,7 +325,7 @@ class Command {
|
|
|
228
325
|
return this;
|
|
229
326
|
}
|
|
230
327
|
async run(params) {
|
|
231
|
-
const { argv, envs, reporter } = params;
|
|
328
|
+
const { argv, envs, reporter: reporter$1 } = params;
|
|
232
329
|
try {
|
|
233
330
|
const processedArgv = this.#processHelpSubcommand(argv);
|
|
234
331
|
const routeResult = this.#route(processedArgv);
|
|
@@ -253,7 +350,7 @@ class Command {
|
|
|
253
350
|
const ctx = {
|
|
254
351
|
cmd: leafCommand,
|
|
255
352
|
envs,
|
|
256
|
-
reporter: reporter ?? this.#reporter ?? new
|
|
353
|
+
reporter: reporter$1 ?? this.#reporter ?? new reporter.Reporter(),
|
|
257
354
|
argv,
|
|
258
355
|
};
|
|
259
356
|
const parseResult = this.#parse(chain, resolveResult, ctx, restArgs);
|
|
@@ -283,7 +380,7 @@ class Command {
|
|
|
283
380
|
}
|
|
284
381
|
}
|
|
285
382
|
parse(params) {
|
|
286
|
-
const { argv, envs, reporter } = params;
|
|
383
|
+
const { argv, envs, reporter: reporter$1 } = params;
|
|
287
384
|
const processedArgv = this.#processHelpSubcommand(argv);
|
|
288
385
|
const routeResult = this.#route(processedArgv);
|
|
289
386
|
const { chain, remaining } = routeResult;
|
|
@@ -294,7 +391,7 @@ class Command {
|
|
|
294
391
|
const ctx = {
|
|
295
392
|
cmd: leafCommand,
|
|
296
393
|
envs,
|
|
297
|
-
reporter: reporter ?? this.#reporter ?? new
|
|
394
|
+
reporter: reporter$1 ?? this.#reporter ?? new reporter.Reporter(),
|
|
298
395
|
argv,
|
|
299
396
|
};
|
|
300
397
|
return this.#parse(chain, resolveResult, ctx, restArgs);
|
|
@@ -355,7 +452,7 @@ class Command {
|
|
|
355
452
|
}
|
|
356
453
|
lines.push('');
|
|
357
454
|
}
|
|
358
|
-
const showHelpSubcommand = this.#
|
|
455
|
+
const showHelpSubcommand = this.#builtin.command.help && this.#subcommandsList.length > 0;
|
|
359
456
|
if (this.#subcommandsList.length > 0) {
|
|
360
457
|
lines.push('Commands:');
|
|
361
458
|
const cmdLines = [];
|
|
@@ -406,7 +503,7 @@ class Command {
|
|
|
406
503
|
};
|
|
407
504
|
}
|
|
408
505
|
#processHelpSubcommand(argv) {
|
|
409
|
-
if (!this.#
|
|
506
|
+
if (!this.#builtin.command.help)
|
|
410
507
|
return argv;
|
|
411
508
|
if (argv.length < 1 || argv[0] !== 'help')
|
|
412
509
|
return argv;
|
|
@@ -735,12 +832,28 @@ class Command {
|
|
|
735
832
|
const optionMap = new Map();
|
|
736
833
|
const hasUserHelp = this.#options.some(o => o.long === 'help');
|
|
737
834
|
const hasUserVersion = this.#options.some(o => o.long === 'version');
|
|
835
|
+
const hasUserLogLevel = this.#options.some(o => o.long === 'logLevel');
|
|
836
|
+
const hasUserSilent = this.#options.some(o => o.long === 'silent');
|
|
837
|
+
const hasUserLogDate = this.#options.some(o => o.long === 'logDate');
|
|
838
|
+
const hasUserLogColorful = this.#options.some(o => o.long === 'logColorful');
|
|
738
839
|
if (!hasUserHelp) {
|
|
739
840
|
optionMap.set('help', BUILTIN_HELP_OPTION);
|
|
740
841
|
}
|
|
741
842
|
if (!hasUserVersion && includeVersion) {
|
|
742
843
|
optionMap.set('version', BUILTIN_VERSION_OPTION);
|
|
743
844
|
}
|
|
845
|
+
if (this.#builtin.option.logLevel && !hasUserLogLevel) {
|
|
846
|
+
optionMap.set('logLevel', logLevelOption);
|
|
847
|
+
}
|
|
848
|
+
if (this.#builtin.option.silent && !hasUserSilent) {
|
|
849
|
+
optionMap.set('silent', silentOption);
|
|
850
|
+
}
|
|
851
|
+
if (this.#builtin.option.logDate && !hasUserLogDate) {
|
|
852
|
+
optionMap.set('logDate', logDateOption);
|
|
853
|
+
}
|
|
854
|
+
if (this.#builtin.option.logColorful && !hasUserLogColorful) {
|
|
855
|
+
optionMap.set('logColorful', logColorfulOption);
|
|
856
|
+
}
|
|
744
857
|
for (const opt of this.#options) {
|
|
745
858
|
optionMap.set(opt.long, opt);
|
|
746
859
|
}
|
|
@@ -1220,3 +1333,7 @@ exports.CommanderError = CommanderError;
|
|
|
1220
1333
|
exports.CompletionCommand = CompletionCommand;
|
|
1221
1334
|
exports.FishCompletion = FishCompletion;
|
|
1222
1335
|
exports.PwshCompletion = PwshCompletion;
|
|
1336
|
+
exports.logColorfulOption = logColorfulOption;
|
|
1337
|
+
exports.logDateOption = logDateOption;
|
|
1338
|
+
exports.logLevelOption = logLevelOption;
|
|
1339
|
+
exports.silentOption = silentOption;
|
package/lib/esm/index.mjs
CHANGED
|
@@ -1,6 +1,58 @@
|
|
|
1
|
+
import { LOG_LEVELS, resolveLogLevel, Reporter } from '@guanghechen/reporter';
|
|
1
2
|
import * as fs from 'node:fs';
|
|
2
3
|
import * as path from 'node:path';
|
|
3
4
|
|
|
5
|
+
const logLevelOption = {
|
|
6
|
+
long: 'logLevel',
|
|
7
|
+
type: 'string',
|
|
8
|
+
args: 'required',
|
|
9
|
+
desc: 'Set log level',
|
|
10
|
+
default: 'info',
|
|
11
|
+
choices: LOG_LEVELS,
|
|
12
|
+
coerce: (raw) => {
|
|
13
|
+
const level = resolveLogLevel(raw);
|
|
14
|
+
if (level === undefined) {
|
|
15
|
+
throw new Error(`Invalid log level: ${raw}`);
|
|
16
|
+
}
|
|
17
|
+
return level;
|
|
18
|
+
},
|
|
19
|
+
apply: (value, ctx) => {
|
|
20
|
+
ctx.reporter.setLevel(value);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const logDateOption = {
|
|
24
|
+
long: 'logDate',
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
args: 'none',
|
|
27
|
+
desc: 'Enable log timestamp',
|
|
28
|
+
default: true,
|
|
29
|
+
apply: (value, ctx) => {
|
|
30
|
+
ctx.reporter.setFlight({ date: Boolean(value) });
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const logColorfulOption = {
|
|
34
|
+
long: 'logColorful',
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
args: 'none',
|
|
37
|
+
desc: 'Enable colorful log output',
|
|
38
|
+
default: true,
|
|
39
|
+
apply: (value, ctx) => {
|
|
40
|
+
ctx.reporter.setFlight({ color: Boolean(value) });
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
const silentOption = {
|
|
44
|
+
long: 'silent',
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
args: 'none',
|
|
47
|
+
desc: 'Suppress non-error output',
|
|
48
|
+
default: false,
|
|
49
|
+
apply: (value, ctx) => {
|
|
50
|
+
if (value) {
|
|
51
|
+
ctx.reporter.setLevel('error');
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
4
56
|
class CommanderError extends Error {
|
|
5
57
|
kind;
|
|
6
58
|
commandPath;
|
|
@@ -15,20 +67,6 @@ class CommanderError extends Error {
|
|
|
15
67
|
}
|
|
16
68
|
}
|
|
17
69
|
|
|
18
|
-
class DefaultReporter {
|
|
19
|
-
debug(message, ...args) {
|
|
20
|
-
console.debug(message, ...args);
|
|
21
|
-
}
|
|
22
|
-
info(message, ...args) {
|
|
23
|
-
console.info(message, ...args);
|
|
24
|
-
}
|
|
25
|
-
warn(message, ...args) {
|
|
26
|
-
console.warn(message, ...args);
|
|
27
|
-
}
|
|
28
|
-
error(message, ...args) {
|
|
29
|
-
console.error(message, ...args);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
70
|
const LONG_OPTION_REGEX = /^--[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
33
71
|
const NEGATIVE_OPTION_REGEX = /^--no-[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
34
72
|
function kebabToCamelCase(str) {
|
|
@@ -130,11 +168,70 @@ const BUILTIN_VERSION_OPTION = {
|
|
|
130
168
|
args: 'none',
|
|
131
169
|
desc: 'Show version number',
|
|
132
170
|
};
|
|
171
|
+
function normalizeBuiltinConfig(builtin) {
|
|
172
|
+
const resolved = {
|
|
173
|
+
option: {
|
|
174
|
+
logLevel: true,
|
|
175
|
+
silent: true,
|
|
176
|
+
logDate: true,
|
|
177
|
+
logColorful: true,
|
|
178
|
+
},
|
|
179
|
+
command: {
|
|
180
|
+
help: false,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
if (builtin === undefined) {
|
|
184
|
+
return resolved;
|
|
185
|
+
}
|
|
186
|
+
if (builtin === true) {
|
|
187
|
+
return {
|
|
188
|
+
option: { logLevel: true, silent: true, logDate: true, logColorful: true },
|
|
189
|
+
command: { help: true },
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (builtin === false) {
|
|
193
|
+
return {
|
|
194
|
+
option: { logLevel: false, silent: false, logDate: false, logColorful: false },
|
|
195
|
+
command: { help: false },
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (builtin.option !== undefined) {
|
|
199
|
+
if (builtin.option === false) {
|
|
200
|
+
resolved.option = { logLevel: false, silent: false, logDate: false, logColorful: false };
|
|
201
|
+
}
|
|
202
|
+
else if (builtin.option === true) {
|
|
203
|
+
resolved.option = { logLevel: true, silent: true, logDate: true, logColorful: true };
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
if (builtin.option.logLevel !== undefined)
|
|
207
|
+
resolved.option.logLevel = builtin.option.logLevel;
|
|
208
|
+
if (builtin.option.silent !== undefined)
|
|
209
|
+
resolved.option.silent = builtin.option.silent;
|
|
210
|
+
if (builtin.option.logDate !== undefined)
|
|
211
|
+
resolved.option.logDate = builtin.option.logDate;
|
|
212
|
+
if (builtin.option.logColorful !== undefined) {
|
|
213
|
+
resolved.option.logColorful = builtin.option.logColorful;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (builtin.command !== undefined) {
|
|
218
|
+
if (builtin.command === false) {
|
|
219
|
+
resolved.command = { help: false };
|
|
220
|
+
}
|
|
221
|
+
else if (builtin.command === true) {
|
|
222
|
+
resolved.command = { help: true };
|
|
223
|
+
}
|
|
224
|
+
else if (builtin.command.help !== undefined) {
|
|
225
|
+
resolved.command.help = builtin.command.help;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return resolved;
|
|
229
|
+
}
|
|
133
230
|
class Command {
|
|
134
231
|
#name;
|
|
135
232
|
#desc;
|
|
136
233
|
#version;
|
|
137
|
-
#
|
|
234
|
+
#builtin;
|
|
138
235
|
#reporter;
|
|
139
236
|
#parent;
|
|
140
237
|
#options = [];
|
|
@@ -146,7 +243,7 @@ class Command {
|
|
|
146
243
|
this.#name = config.name ?? '';
|
|
147
244
|
this.#desc = config.desc;
|
|
148
245
|
this.#version = config.version;
|
|
149
|
-
this.#
|
|
246
|
+
this.#builtin = normalizeBuiltinConfig(config.builtin);
|
|
150
247
|
this.#reporter = config.reporter;
|
|
151
248
|
}
|
|
152
249
|
get name() {
|
|
@@ -186,7 +283,7 @@ class Command {
|
|
|
186
283
|
return this;
|
|
187
284
|
}
|
|
188
285
|
subcommand(name, cmd) {
|
|
189
|
-
if (this.#
|
|
286
|
+
if (this.#builtin.command.help && name === 'help') {
|
|
190
287
|
throw new CommanderError('ConfigurationError', '"help" is a reserved subcommand name when help subcommand is enabled', this.#getCommandPath());
|
|
191
288
|
}
|
|
192
289
|
if (cmd.#parent && cmd.#parent !== this) {
|
|
@@ -231,7 +328,7 @@ class Command {
|
|
|
231
328
|
const ctx = {
|
|
232
329
|
cmd: leafCommand,
|
|
233
330
|
envs,
|
|
234
|
-
reporter: reporter ?? this.#reporter ?? new
|
|
331
|
+
reporter: reporter ?? this.#reporter ?? new Reporter(),
|
|
235
332
|
argv,
|
|
236
333
|
};
|
|
237
334
|
const parseResult = this.#parse(chain, resolveResult, ctx, restArgs);
|
|
@@ -272,7 +369,7 @@ class Command {
|
|
|
272
369
|
const ctx = {
|
|
273
370
|
cmd: leafCommand,
|
|
274
371
|
envs,
|
|
275
|
-
reporter: reporter ?? this.#reporter ?? new
|
|
372
|
+
reporter: reporter ?? this.#reporter ?? new Reporter(),
|
|
276
373
|
argv,
|
|
277
374
|
};
|
|
278
375
|
return this.#parse(chain, resolveResult, ctx, restArgs);
|
|
@@ -333,7 +430,7 @@ class Command {
|
|
|
333
430
|
}
|
|
334
431
|
lines.push('');
|
|
335
432
|
}
|
|
336
|
-
const showHelpSubcommand = this.#
|
|
433
|
+
const showHelpSubcommand = this.#builtin.command.help && this.#subcommandsList.length > 0;
|
|
337
434
|
if (this.#subcommandsList.length > 0) {
|
|
338
435
|
lines.push('Commands:');
|
|
339
436
|
const cmdLines = [];
|
|
@@ -384,7 +481,7 @@ class Command {
|
|
|
384
481
|
};
|
|
385
482
|
}
|
|
386
483
|
#processHelpSubcommand(argv) {
|
|
387
|
-
if (!this.#
|
|
484
|
+
if (!this.#builtin.command.help)
|
|
388
485
|
return argv;
|
|
389
486
|
if (argv.length < 1 || argv[0] !== 'help')
|
|
390
487
|
return argv;
|
|
@@ -713,12 +810,28 @@ class Command {
|
|
|
713
810
|
const optionMap = new Map();
|
|
714
811
|
const hasUserHelp = this.#options.some(o => o.long === 'help');
|
|
715
812
|
const hasUserVersion = this.#options.some(o => o.long === 'version');
|
|
813
|
+
const hasUserLogLevel = this.#options.some(o => o.long === 'logLevel');
|
|
814
|
+
const hasUserSilent = this.#options.some(o => o.long === 'silent');
|
|
815
|
+
const hasUserLogDate = this.#options.some(o => o.long === 'logDate');
|
|
816
|
+
const hasUserLogColorful = this.#options.some(o => o.long === 'logColorful');
|
|
716
817
|
if (!hasUserHelp) {
|
|
717
818
|
optionMap.set('help', BUILTIN_HELP_OPTION);
|
|
718
819
|
}
|
|
719
820
|
if (!hasUserVersion && includeVersion) {
|
|
720
821
|
optionMap.set('version', BUILTIN_VERSION_OPTION);
|
|
721
822
|
}
|
|
823
|
+
if (this.#builtin.option.logLevel && !hasUserLogLevel) {
|
|
824
|
+
optionMap.set('logLevel', logLevelOption);
|
|
825
|
+
}
|
|
826
|
+
if (this.#builtin.option.silent && !hasUserSilent) {
|
|
827
|
+
optionMap.set('silent', silentOption);
|
|
828
|
+
}
|
|
829
|
+
if (this.#builtin.option.logDate && !hasUserLogDate) {
|
|
830
|
+
optionMap.set('logDate', logDateOption);
|
|
831
|
+
}
|
|
832
|
+
if (this.#builtin.option.logColorful && !hasUserLogColorful) {
|
|
833
|
+
optionMap.set('logColorful', logColorfulOption);
|
|
834
|
+
}
|
|
722
835
|
for (const opt of this.#options) {
|
|
723
836
|
optionMap.set(opt.long, opt);
|
|
724
837
|
}
|
|
@@ -1192,4 +1305,4 @@ class PwshCompletion {
|
|
|
1192
1305
|
}
|
|
1193
1306
|
}
|
|
1194
1307
|
|
|
1195
|
-
export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion };
|
|
1308
|
+
export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
+
import { IReporter } from '@guanghechen/reporter';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Type definitions for @guanghechen/commander
|
|
3
5
|
*
|
|
4
6
|
* @module @guanghechen/commander
|
|
5
7
|
*/
|
|
6
|
-
|
|
7
|
-
* Reporter interface for logging.
|
|
8
|
-
* Provided by @guanghechen/reporter or user implementation.
|
|
9
|
-
*/
|
|
10
|
-
interface IReporter {
|
|
11
|
-
debug(message: string, ...args: unknown[]): void;
|
|
12
|
-
info(message: string, ...args: unknown[]): void;
|
|
13
|
-
warn(message: string, ...args: unknown[]): void;
|
|
14
|
-
error(message: string, ...args: unknown[]): void;
|
|
15
|
-
}
|
|
8
|
+
|
|
16
9
|
/** Token type: long option, short option, or positional */
|
|
17
10
|
type ICommandTokenType = 'long' | 'short' | 'none';
|
|
18
11
|
/**
|
|
@@ -99,6 +92,26 @@ interface ICommandArgumentConfig<T = unknown> {
|
|
|
99
92
|
/** Custom value transformation (takes precedence over type conversion) */
|
|
100
93
|
coerce?: (rawValue: string) => T;
|
|
101
94
|
}
|
|
95
|
+
interface ICommandBuiltinOptionConfig {
|
|
96
|
+
/** Enable built-in --log-level option */
|
|
97
|
+
logLevel?: boolean;
|
|
98
|
+
/** Enable built-in --silent option */
|
|
99
|
+
silent?: boolean;
|
|
100
|
+
/** Enable built-in --log-date/--no-log-date option */
|
|
101
|
+
logDate?: boolean;
|
|
102
|
+
/** Enable built-in --log-colorful/--no-log-colorful option */
|
|
103
|
+
logColorful?: boolean;
|
|
104
|
+
}
|
|
105
|
+
interface ICommandBuiltinCommandConfig {
|
|
106
|
+
/** Enable built-in help subcommand */
|
|
107
|
+
help?: boolean;
|
|
108
|
+
}
|
|
109
|
+
interface ICommandBuiltinConfig {
|
|
110
|
+
/** Built-in options configuration */
|
|
111
|
+
option?: boolean | ICommandBuiltinOptionConfig;
|
|
112
|
+
/** Built-in command configuration */
|
|
113
|
+
command?: boolean | ICommandBuiltinCommandConfig;
|
|
114
|
+
}
|
|
102
115
|
/** Command configuration */
|
|
103
116
|
interface ICommandConfig {
|
|
104
117
|
/** Command name (only for root command) */
|
|
@@ -107,8 +120,8 @@ interface ICommandConfig {
|
|
|
107
120
|
desc: string;
|
|
108
121
|
/** Version (for root --version) */
|
|
109
122
|
version?: string;
|
|
110
|
-
/**
|
|
111
|
-
|
|
123
|
+
/** Built-in features configuration */
|
|
124
|
+
builtin?: boolean | ICommandBuiltinConfig;
|
|
112
125
|
/** Default reporter for this command */
|
|
113
126
|
reporter?: IReporter;
|
|
114
127
|
}
|
|
@@ -326,5 +339,88 @@ declare class PwshCompletion {
|
|
|
326
339
|
generate(): string;
|
|
327
340
|
}
|
|
328
341
|
|
|
329
|
-
|
|
330
|
-
|
|
342
|
+
/**
|
|
343
|
+
* Pre-defined common options for @guanghechen/commander
|
|
344
|
+
*
|
|
345
|
+
* @module @guanghechen/commander/options
|
|
346
|
+
*/
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Pre-defined --log-level option for setting log verbosity.
|
|
350
|
+
*
|
|
351
|
+
* Supports: debug | info | hint | warn | error (case-insensitive)
|
|
352
|
+
*
|
|
353
|
+
* | Property | Value |
|
|
354
|
+
* | --------- | ---------------------------------- |
|
|
355
|
+
* | long | 'logLevel' |
|
|
356
|
+
* | type | 'string' |
|
|
357
|
+
* | args | 'required' |
|
|
358
|
+
* | default | 'info' |
|
|
359
|
+
* | choices | LOG_LEVELS |
|
|
360
|
+
* | coerce | resolveLogLevel (case-insensitive) |
|
|
361
|
+
* | apply | ctx.reporter.setLevel(value) |
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```typescript
|
|
365
|
+
* import { logLevelOption } from '@guanghechen/commander'
|
|
366
|
+
*
|
|
367
|
+
* const cmd = new Command('app')
|
|
368
|
+
* .option(logLevelOption)
|
|
369
|
+
* .action(({ opts }) => {
|
|
370
|
+
* console.log(opts.logLevel) // 'debug' | 'info' | 'hint' | 'warn' | 'error'
|
|
371
|
+
* })
|
|
372
|
+
*
|
|
373
|
+
* // Override with spread syntax
|
|
374
|
+
* .option({ ...logLevelOption, default: 'warn' })
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
declare const logLevelOption: ICommandOptionConfig<string>;
|
|
378
|
+
/**
|
|
379
|
+
* Pre-defined --log-date option for controlling timestamp output.
|
|
380
|
+
*
|
|
381
|
+
* | Property | Value |
|
|
382
|
+
* | --------- | --------- |
|
|
383
|
+
* | long | 'logDate' |
|
|
384
|
+
* | type | 'boolean' |
|
|
385
|
+
* | args | 'none' |
|
|
386
|
+
* | default | true |
|
|
387
|
+
*/
|
|
388
|
+
declare const logDateOption: ICommandOptionConfig<boolean>;
|
|
389
|
+
/**
|
|
390
|
+
* Pre-defined --log-colorful option for controlling colorful output.
|
|
391
|
+
*
|
|
392
|
+
* | Property | Value |
|
|
393
|
+
* | --------- | ------------- |
|
|
394
|
+
* | long | 'logColorful' |
|
|
395
|
+
* | type | 'boolean' |
|
|
396
|
+
* | args | 'none' |
|
|
397
|
+
* | default | true |
|
|
398
|
+
*/
|
|
399
|
+
declare const logColorfulOption: ICommandOptionConfig<boolean>;
|
|
400
|
+
/**
|
|
401
|
+
* Pre-defined --silent option for suppressing non-error output.
|
|
402
|
+
*
|
|
403
|
+
* | Property | Value |
|
|
404
|
+
* | --------- | --------- |
|
|
405
|
+
* | long | 'silent' |
|
|
406
|
+
* | type | 'boolean' |
|
|
407
|
+
* | args | 'none' |
|
|
408
|
+
* | default | false |
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* ```typescript
|
|
412
|
+
* import { silentOption } from '@guanghechen/commander'
|
|
413
|
+
*
|
|
414
|
+
* const cmd = new Command('app')
|
|
415
|
+
* .option(silentOption)
|
|
416
|
+
* .action(({ opts }) => {
|
|
417
|
+
* if (!opts.silent) {
|
|
418
|
+
* console.log('Processing...')
|
|
419
|
+
* }
|
|
420
|
+
* })
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
declare const silentOption: ICommandOptionConfig<boolean>;
|
|
424
|
+
|
|
425
|
+
export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
|
|
426
|
+
export type { ICommand, ICommandAction, ICommandActionParams, ICommandArgumentConfig, ICommandArgumentKind, ICommandArgumentType, ICommandBuiltinCommandConfig, ICommandBuiltinConfig, ICommandBuiltinOptionConfig, ICommandConfig, ICommandContext, 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.2.0",
|
|
4
4
|
"description": "A minimal, type-safe command-line interface builder with fluent API",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "guanghechen",
|
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
"LICENSE",
|
|
41
41
|
"README.md"
|
|
42
42
|
],
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@guanghechen/reporter": "^3.3.0"
|
|
45
|
+
},
|
|
43
46
|
"scripts": {
|
|
44
47
|
"build": "rollup -c ../../rollup.config.mjs",
|
|
45
48
|
"clean": "rimraf lib",
|