@guanghechen/commander 4.1.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 CHANGED
@@ -1,5 +1,17 @@
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
+
3
15
  ## 4.1.0
4
16
 
5
17
  ### Minor Changes
package/lib/cjs/index.cjs CHANGED
@@ -24,6 +24,57 @@ function _interopNamespaceDefault(e) {
24
24
  var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
25
25
  var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
26
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
+
27
78
  class CommanderError extends Error {
28
79
  kind;
29
80
  commandPath;
@@ -139,11 +190,70 @@ const BUILTIN_VERSION_OPTION = {
139
190
  args: 'none',
140
191
  desc: 'Show version number',
141
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
+ }
142
252
  class Command {
143
253
  #name;
144
254
  #desc;
145
255
  #version;
146
- #helpSubcommandEnabled;
256
+ #builtin;
147
257
  #reporter;
148
258
  #parent;
149
259
  #options = [];
@@ -155,7 +265,7 @@ class Command {
155
265
  this.#name = config.name ?? '';
156
266
  this.#desc = config.desc;
157
267
  this.#version = config.version;
158
- this.#helpSubcommandEnabled = config.help ?? false;
268
+ this.#builtin = normalizeBuiltinConfig(config.builtin);
159
269
  this.#reporter = config.reporter;
160
270
  }
161
271
  get name() {
@@ -195,7 +305,7 @@ class Command {
195
305
  return this;
196
306
  }
197
307
  subcommand(name, cmd) {
198
- if (this.#helpSubcommandEnabled && name === 'help') {
308
+ if (this.#builtin.command.help && name === 'help') {
199
309
  throw new CommanderError('ConfigurationError', '"help" is a reserved subcommand name when help subcommand is enabled', this.#getCommandPath());
200
310
  }
201
311
  if (cmd.#parent && cmd.#parent !== this) {
@@ -342,7 +452,7 @@ class Command {
342
452
  }
343
453
  lines.push('');
344
454
  }
345
- const showHelpSubcommand = this.#helpSubcommandEnabled && this.#subcommandsList.length > 0;
455
+ const showHelpSubcommand = this.#builtin.command.help && this.#subcommandsList.length > 0;
346
456
  if (this.#subcommandsList.length > 0) {
347
457
  lines.push('Commands:');
348
458
  const cmdLines = [];
@@ -393,7 +503,7 @@ class Command {
393
503
  };
394
504
  }
395
505
  #processHelpSubcommand(argv) {
396
- if (!this.#helpSubcommandEnabled)
506
+ if (!this.#builtin.command.help)
397
507
  return argv;
398
508
  if (argv.length < 1 || argv[0] !== 'help')
399
509
  return argv;
@@ -722,12 +832,28 @@ class Command {
722
832
  const optionMap = new Map();
723
833
  const hasUserHelp = this.#options.some(o => o.long === 'help');
724
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');
725
839
  if (!hasUserHelp) {
726
840
  optionMap.set('help', BUILTIN_HELP_OPTION);
727
841
  }
728
842
  if (!hasUserVersion && includeVersion) {
729
843
  optionMap.set('version', BUILTIN_VERSION_OPTION);
730
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
+ }
731
857
  for (const opt of this.#options) {
732
858
  optionMap.set(opt.long, opt);
733
859
  }
@@ -1201,37 +1327,13 @@ class PwshCompletion {
1201
1327
  }
1202
1328
  }
1203
1329
 
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
1330
  exports.BashCompletion = BashCompletion;
1231
1331
  exports.Command = Command;
1232
1332
  exports.CommanderError = CommanderError;
1233
1333
  exports.CompletionCommand = CompletionCommand;
1234
1334
  exports.FishCompletion = FishCompletion;
1235
1335
  exports.PwshCompletion = PwshCompletion;
1336
+ exports.logColorfulOption = logColorfulOption;
1337
+ exports.logDateOption = logDateOption;
1236
1338
  exports.logLevelOption = logLevelOption;
1237
1339
  exports.silentOption = silentOption;
package/lib/esm/index.mjs CHANGED
@@ -1,7 +1,58 @@
1
- import { Reporter, LOG_LEVELS, resolveLogLevel } from '@guanghechen/reporter';
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 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
+
5
56
  class CommanderError extends Error {
6
57
  kind;
7
58
  commandPath;
@@ -117,11 +168,70 @@ const BUILTIN_VERSION_OPTION = {
117
168
  args: 'none',
118
169
  desc: 'Show version number',
119
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
+ }
120
230
  class Command {
121
231
  #name;
122
232
  #desc;
123
233
  #version;
124
- #helpSubcommandEnabled;
234
+ #builtin;
125
235
  #reporter;
126
236
  #parent;
127
237
  #options = [];
@@ -133,7 +243,7 @@ class Command {
133
243
  this.#name = config.name ?? '';
134
244
  this.#desc = config.desc;
135
245
  this.#version = config.version;
136
- this.#helpSubcommandEnabled = config.help ?? false;
246
+ this.#builtin = normalizeBuiltinConfig(config.builtin);
137
247
  this.#reporter = config.reporter;
138
248
  }
139
249
  get name() {
@@ -173,7 +283,7 @@ class Command {
173
283
  return this;
174
284
  }
175
285
  subcommand(name, cmd) {
176
- if (this.#helpSubcommandEnabled && name === 'help') {
286
+ if (this.#builtin.command.help && name === 'help') {
177
287
  throw new CommanderError('ConfigurationError', '"help" is a reserved subcommand name when help subcommand is enabled', this.#getCommandPath());
178
288
  }
179
289
  if (cmd.#parent && cmd.#parent !== this) {
@@ -320,7 +430,7 @@ class Command {
320
430
  }
321
431
  lines.push('');
322
432
  }
323
- const showHelpSubcommand = this.#helpSubcommandEnabled && this.#subcommandsList.length > 0;
433
+ const showHelpSubcommand = this.#builtin.command.help && this.#subcommandsList.length > 0;
324
434
  if (this.#subcommandsList.length > 0) {
325
435
  lines.push('Commands:');
326
436
  const cmdLines = [];
@@ -371,7 +481,7 @@ class Command {
371
481
  };
372
482
  }
373
483
  #processHelpSubcommand(argv) {
374
- if (!this.#helpSubcommandEnabled)
484
+ if (!this.#builtin.command.help)
375
485
  return argv;
376
486
  if (argv.length < 1 || argv[0] !== 'help')
377
487
  return argv;
@@ -700,12 +810,28 @@ class Command {
700
810
  const optionMap = new Map();
701
811
  const hasUserHelp = this.#options.some(o => o.long === 'help');
702
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');
703
817
  if (!hasUserHelp) {
704
818
  optionMap.set('help', BUILTIN_HELP_OPTION);
705
819
  }
706
820
  if (!hasUserVersion && includeVersion) {
707
821
  optionMap.set('version', BUILTIN_VERSION_OPTION);
708
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
+ }
709
835
  for (const opt of this.#options) {
710
836
  optionMap.set(opt.long, opt);
711
837
  }
@@ -1179,30 +1305,4 @@ class PwshCompletion {
1179
1305
  }
1180
1306
  }
1181
1307
 
1182
- const logLevelOption = {
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 };
1308
+ export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
@@ -92,6 +92,26 @@ 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 --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
+ }
95
115
  /** Command configuration */
96
116
  interface ICommandConfig {
97
117
  /** Command name (only for root command) */
@@ -100,8 +120,8 @@ interface ICommandConfig {
100
120
  desc: string;
101
121
  /** Version (for root --version) */
102
122
  version?: string;
103
- /** Enable built-in "help" subcommand */
104
- help?: boolean;
123
+ /** Built-in features configuration */
124
+ builtin?: boolean | ICommandBuiltinConfig;
105
125
  /** Default reporter for this command */
106
126
  reporter?: IReporter;
107
127
  }
@@ -355,6 +375,28 @@ declare class PwshCompletion {
355
375
  * ```
356
376
  */
357
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>;
358
400
  /**
359
401
  * Pre-defined --silent option for suppressing non-error output.
360
402
  *
@@ -380,5 +422,5 @@ declare const logLevelOption: ICommandOptionConfig<string>;
380
422
  */
381
423
  declare const silentOption: ICommandOptionConfig<boolean>;
382
424
 
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 };
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.1.0",
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",
@@ -41,7 +41,7 @@
41
41
  "README.md"
42
42
  ],
43
43
  "dependencies": {
44
- "@guanghechen/reporter": "^3.2.0"
44
+ "@guanghechen/reporter": "^3.3.0"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "rollup -c ../../rollup.config.mjs",