@bemoje/cli 0.2.1 → 0.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.
Files changed (121) hide show
  1. package/index.d.ts +6 -0
  2. package/index.js +6 -0
  3. package/lib/Command.d.ts +293 -0
  4. package/lib/Command.js +435 -0
  5. package/lib/CommandHelpAdapter.d.ts +157 -0
  6. package/lib/CommandHelpAdapter.js +100 -0
  7. package/lib/CommanderHelpAdapter.d.ts +56 -0
  8. package/lib/CommanderHelpAdapter.js +90 -0
  9. package/lib/Help.d.ts +263 -0
  10. package/lib/Help.js +477 -0
  11. package/lib/internal/lazyProp.d.ts +5 -0
  12. package/lib/internal/lazyProp.js +24 -0
  13. package/lib/renderHelp.d.ts +6 -0
  14. package/lib/renderHelp.js +12 -0
  15. package/package.json +25 -37
  16. package/LICENSE +0 -21
  17. package/README.md +0 -34
  18. package/cjs/arg/ArgumentBuilder.d.ts +0 -23
  19. package/cjs/arg/ArgumentBuilder.d.ts.map +0 -1
  20. package/cjs/arg/ArgumentBuilder.js +0 -52
  21. package/cjs/arg/ArgumentBuilder.js.map +0 -1
  22. package/cjs/arg/ArgumentParserSelector.d.ts +0 -9
  23. package/cjs/arg/ArgumentParserSelector.d.ts.map +0 -1
  24. package/cjs/arg/ArgumentParserSelector.js +0 -15
  25. package/cjs/arg/ArgumentParserSelector.js.map +0 -1
  26. package/cjs/arg/ArgumentReader.d.ts +0 -15
  27. package/cjs/arg/ArgumentReader.d.ts.map +0 -1
  28. package/cjs/arg/ArgumentReader.js +0 -38
  29. package/cjs/arg/ArgumentReader.js.map +0 -1
  30. package/cjs/arg/ArgumentValidatorSelector.d.ts +0 -8
  31. package/cjs/arg/ArgumentValidatorSelector.d.ts.map +0 -1
  32. package/cjs/arg/ArgumentValidatorSelector.js +0 -16
  33. package/cjs/arg/ArgumentValidatorSelector.js.map +0 -1
  34. package/cjs/cmd/CommandBuilder.d.ts +0 -410
  35. package/cjs/cmd/CommandBuilder.d.ts.map +0 -1
  36. package/cjs/cmd/CommandBuilder.js +0 -1277
  37. package/cjs/cmd/CommandBuilder.js.map +0 -1
  38. package/cjs/cmd/CommandBuilderMetaData.d.ts +0 -26
  39. package/cjs/cmd/CommandBuilderMetaData.d.ts.map +0 -1
  40. package/cjs/cmd/CommandBuilderMetaData.js +0 -45
  41. package/cjs/cmd/CommandBuilderMetaData.js.map +0 -1
  42. package/cjs/cmd/CommandFeatureSelector.d.ts +0 -80
  43. package/cjs/cmd/CommandFeatureSelector.d.ts.map +0 -1
  44. package/cjs/cmd/CommandFeatureSelector.js +0 -114
  45. package/cjs/cmd/CommandFeatureSelector.js.map +0 -1
  46. package/cjs/cmd/DefaultHelpConfig.d.ts +0 -29
  47. package/cjs/cmd/DefaultHelpConfig.d.ts.map +0 -1
  48. package/cjs/cmd/DefaultHelpConfig.js +0 -177
  49. package/cjs/cmd/DefaultHelpConfig.js.map +0 -1
  50. package/cjs/cmd/commanderBackRefs.d.ts +0 -10
  51. package/cjs/cmd/commanderBackRefs.d.ts.map +0 -1
  52. package/cjs/cmd/commanderBackRefs.js +0 -38
  53. package/cjs/cmd/commanderBackRefs.js.map +0 -1
  54. package/cjs/core/OutputManager.d.ts +0 -64
  55. package/cjs/core/OutputManager.d.ts.map +0 -1
  56. package/cjs/core/OutputManager.js +0 -92
  57. package/cjs/core/OutputManager.js.map +0 -1
  58. package/cjs/core/ParserSelector.d.ts +0 -23
  59. package/cjs/core/ParserSelector.d.ts.map +0 -1
  60. package/cjs/core/ParserSelector.js +0 -46
  61. package/cjs/core/ParserSelector.js.map +0 -1
  62. package/cjs/core/ValidatorSelector.d.ts +0 -19
  63. package/cjs/core/ValidatorSelector.d.ts.map +0 -1
  64. package/cjs/core/ValidatorSelector.js +0 -42
  65. package/cjs/core/ValidatorSelector.js.map +0 -1
  66. package/cjs/core/splitCombinedArgvShorts.d.ts +0 -2
  67. package/cjs/core/splitCombinedArgvShorts.d.ts.map +0 -1
  68. package/cjs/core/splitCombinedArgvShorts.js +0 -15
  69. package/cjs/core/splitCombinedArgvShorts.js.map +0 -1
  70. package/cjs/db/AbstractJsonFileSection.d.ts +0 -136
  71. package/cjs/db/AbstractJsonFileSection.d.ts.map +0 -1
  72. package/cjs/db/AbstractJsonFileSection.js +0 -190
  73. package/cjs/db/AbstractJsonFileSection.js.map +0 -1
  74. package/cjs/db/AppDataSection.d.ts +0 -31
  75. package/cjs/db/AppDataSection.d.ts.map +0 -1
  76. package/cjs/db/AppDataSection.js +0 -49
  77. package/cjs/db/AppDataSection.js.map +0 -1
  78. package/cjs/db/ConfigSection.d.ts +0 -46
  79. package/cjs/db/ConfigSection.d.ts.map +0 -1
  80. package/cjs/db/ConfigSection.js +0 -71
  81. package/cjs/db/ConfigSection.js.map +0 -1
  82. package/cjs/db/JsonFile.d.ts +0 -36
  83. package/cjs/db/JsonFile.d.ts.map +0 -1
  84. package/cjs/db/JsonFile.js +0 -60
  85. package/cjs/db/JsonFile.js.map +0 -1
  86. package/cjs/db/PresetsSection.d.ts +0 -45
  87. package/cjs/db/PresetsSection.d.ts.map +0 -1
  88. package/cjs/db/PresetsSection.js +0 -82
  89. package/cjs/db/PresetsSection.js.map +0 -1
  90. package/cjs/index.d.ts +0 -26
  91. package/cjs/index.d.ts.map +0 -1
  92. package/cjs/index.js +0 -29
  93. package/cjs/index.js.map +0 -1
  94. package/cjs/opt/OptionArgumentParserSelector.d.ts +0 -8
  95. package/cjs/opt/OptionArgumentParserSelector.d.ts.map +0 -1
  96. package/cjs/opt/OptionArgumentParserSelector.js +0 -16
  97. package/cjs/opt/OptionArgumentParserSelector.js.map +0 -1
  98. package/cjs/opt/OptionArgumentValidatorSelector.d.ts +0 -8
  99. package/cjs/opt/OptionArgumentValidatorSelector.d.ts.map +0 -1
  100. package/cjs/opt/OptionArgumentValidatorSelector.js +0 -19
  101. package/cjs/opt/OptionArgumentValidatorSelector.js.map +0 -1
  102. package/cjs/opt/OptionBuilder.d.ts +0 -32
  103. package/cjs/opt/OptionBuilder.d.ts.map +0 -1
  104. package/cjs/opt/OptionBuilder.js +0 -97
  105. package/cjs/opt/OptionBuilder.js.map +0 -1
  106. package/cjs/opt/OptionHelpers.d.ts +0 -33
  107. package/cjs/opt/OptionHelpers.d.ts.map +0 -1
  108. package/cjs/opt/OptionHelpers.js +0 -57
  109. package/cjs/opt/OptionHelpers.js.map +0 -1
  110. package/cjs/opt/OptionReader.d.ts +0 -24
  111. package/cjs/opt/OptionReader.d.ts.map +0 -1
  112. package/cjs/opt/OptionReader.js +0 -66
  113. package/cjs/opt/OptionReader.js.map +0 -1
  114. package/cjs/types/IConfig.d.ts +0 -22
  115. package/cjs/types/IConfig.d.ts.map +0 -1
  116. package/cjs/types/IConfig.js +0 -3
  117. package/cjs/types/IConfig.js.map +0 -1
  118. package/cjs/types/IPreset.d.ts +0 -15
  119. package/cjs/types/IPreset.d.ts.map +0 -1
  120. package/cjs/types/IPreset.js +0 -3
  121. package/cjs/types/IPreset.js.map +0 -1
@@ -1,1277 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLI = exports.CommandBuilder = void 0;
4
- const tslib_1 = require("tslib");
5
- /* eslint-disable @typescript-eslint/ban-types */
6
- const ansi_colors_1 = tslib_1.__importDefault(require("ansi-colors"));
7
- const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
8
- const is_async_function_1 = tslib_1.__importDefault(require("is-async-function"));
9
- const os_1 = tslib_1.__importDefault(require("os"));
10
- const path_1 = tslib_1.__importDefault(require("path"));
11
- const extra_typings_1 = require("@commander-js/extra-typings");
12
- const ArgumentBuilder_1 = require("../arg/ArgumentBuilder");
13
- const object_1 = require("@bemoje/object");
14
- const array_1 = require("@bemoje/array");
15
- const array_2 = require("@bemoje/array");
16
- const array_3 = require("@bemoje/array");
17
- const CommandBuilderMetaData_1 = require("./CommandBuilderMetaData");
18
- const commanderBackRefs_1 = require("./commanderBackRefs");
19
- const CommandFeatureSelector_1 = require("./CommandFeatureSelector");
20
- const DefaultHelpConfig_1 = require("./DefaultHelpConfig");
21
- const is_1 = require("@bemoje/is");
22
- const node_1 = require("@bemoje/node");
23
- const extra_typings_2 = require("@commander-js/extra-typings");
24
- const is_2 = require("@bemoje/is");
25
- const is_3 = require("@bemoje/is");
26
- const is_4 = require("@bemoje/is");
27
- const is_5 = require("@bemoje/is");
28
- const is_6 = require("@bemoje/is");
29
- const JsonFile_1 = require("../db/JsonFile");
30
- const object_2 = require("@bemoje/object");
31
- const OptionBuilder_1 = require("../opt/OptionBuilder");
32
- const OptionHelpers_1 = require("../opt/OptionHelpers");
33
- const OutputManager_1 = require("../core/OutputManager");
34
- const object_3 = require("@bemoje/object");
35
- const fs_1 = require("@bemoje/fs");
36
- const object_4 = require("@bemoje/object");
37
- const string_1 = require("@bemoje/string");
38
- /**
39
- * Wrapper around the @see Command class, for more intuitive construction.
40
- */
41
- class CommandBuilder {
42
- static dataDirectory = path_1.default.join(os_1.default.homedir(), 'config', 'cli');
43
- features = new CommandFeatureSelector_1.CommandFeatureSelector(this);
44
- parent = null;
45
- $;
46
- meta = new CommandBuilderMetaData_1.CommandBuilderMetaData();
47
- get db() {
48
- return (0, object_3.realizeLazyProperty)(this, 'db', new JsonFile_1.JsonFile(this));
49
- }
50
- constructor(name, callback, parent, isNative = false, isDefault = false) {
51
- this.meta.isNative = isNative;
52
- this.$ = new extra_typings_1.Command(name);
53
- commanderBackRefs_1.commanderBackRefs.set(this.$, this);
54
- if (parent) {
55
- this.parent = parent;
56
- this.parent.meta.subcommands.push(this);
57
- this.parent.$.addCommand(this.$, { isDefault });
58
- }
59
- this.initializeHelp();
60
- if (callback)
61
- callback.call(this, this);
62
- if (this.parent) {
63
- this.$.copyInheritedSettings(this.parent.$);
64
- this.features.inheritFrom(this.parent.features);
65
- this.inheritParentHiddenGlobals();
66
- }
67
- if (!this.meta.isNative) {
68
- this.assertCommandNameNotReserved(this.name);
69
- this.addUtilCommands();
70
- }
71
- if (this.isRoot) {
72
- for (const child of this.getChildrenIterator({ inclusive: true })) {
73
- if (child.features.isAutoAssignAliasEnabled) {
74
- child.assignAlias();
75
- if (!child.meta.isNative) {
76
- child.assertNoDuplicateCommandNames();
77
- }
78
- }
79
- if (child.features.isAutoAssignOptionFlagsEnabled) {
80
- child.assignOptionFlags();
81
- if (!child.meta.isNative) {
82
- child.assertNoDuplicateOptionNames();
83
- }
84
- }
85
- }
86
- if (this.features.isConfigEnabled) {
87
- this.db.config;
88
- }
89
- }
90
- }
91
- setRecommended() {
92
- this.enableBuiltinOptions({ debug: true, noStderr: true, noStdout: true });
93
- this.autoAssignOptionFlags();
94
- this.autoAssignAlias();
95
- this.presetsEnabled();
96
- }
97
- setName(name) {
98
- this.$.name(name);
99
- return this;
100
- }
101
- deleteDataFile() {
102
- const filepath = this.jsonFilepath;
103
- if (fs_extra_1.default.existsSync(filepath))
104
- (0, fs_1.removeFile)(filepath);
105
- }
106
- /**
107
- * Set the program version to `str`.
108
- *
109
- * This method auto-registers the "-V, --version" flag
110
- * which will print the version number when passed.
111
- *
112
- * You can optionally supply the flags and description to override the defaults.
113
- */
114
- version(string) {
115
- this.$.version(string);
116
- return this;
117
- }
118
- /**
119
- * Set the description. If more than one sentence or string is given,
120
- * then the first will be used as summary and the whole text as description.
121
- * @param lines - description lines
122
- */
123
- description(...lines) {
124
- const description = lines.join('\n');
125
- const summary = description.split(/(\.(\s|\r|\n|$)+)/)[0];
126
- this.$.summary(summary + '.');
127
- this.$.description(description);
128
- return this;
129
- }
130
- /**
131
- * Set an alias for the command.
132
- * You may call more than once to add multiple aliases.
133
- * Only the first alias is shown in the auto-generated help.
134
- */
135
- alias(alias) {
136
- this.assertCommandNameNotReserved(alias);
137
- this.$.alias(alias);
138
- return this;
139
- }
140
- /**
141
- * Set aliases for the command. This overwrites all previously set aliases.
142
- * Only the first alias is shown in the auto-generated help.
143
- */
144
- aliases(...aliases) {
145
- aliases.forEach((alias) => this.assertCommandNameNotReserved(alias));
146
- this.$.aliases(aliases);
147
- return this;
148
- }
149
- /**
150
- * Set the command usage.
151
- */
152
- usage(str) {
153
- this.$.usage(str);
154
- return this;
155
- }
156
- enableBuiltinOptions(options) {
157
- if (!options || options.debug)
158
- this.globalOption('-D, --debug', 'Output debugging information.');
159
- if (!options || options.noColor)
160
- this.globalOption('-C, --noColor', 'Disable color in terminal output.');
161
- if (!options || options.noStderr)
162
- this.globalOption('-E, --noStderr', 'Mute all output to stderr.');
163
- if (!options || options.noStdout)
164
- this.globalOption('-O, --noStdout', 'Mute all output to stdout.');
165
- return this;
166
- }
167
- argument(name, ...args) {
168
- let description = '';
169
- let callback;
170
- if (typeof args[0] === 'string') {
171
- description = args[0];
172
- callback = args[1];
173
- }
174
- else {
175
- callback = args[0];
176
- }
177
- const ins = new ArgumentBuilder_1.ArgumentBuilder(this, name);
178
- this.$.addArgument(ins.$);
179
- if (description) {
180
- ins.description(description);
181
- }
182
- if (typeof callback === 'function') {
183
- callback(ins, this);
184
- }
185
- if (ins.$.variadic && !ins.hasParser && !ins.hasValidators) {
186
- ins.parser.string();
187
- ins.validator.isStringArray();
188
- }
189
- return this;
190
- }
191
- option(flags, ...args) {
192
- let description = '';
193
- let callback;
194
- if (typeof args[0] === 'string') {
195
- description = args[0];
196
- callback = args[1];
197
- }
198
- else {
199
- callback = args[0];
200
- }
201
- const ins = new OptionBuilder_1.OptionBuilder(this, flags);
202
- if (this.hasIdenticalParentOption(ins.$))
203
- return this;
204
- this.$.addOption(ins.$);
205
- if (description) {
206
- ins.description(description);
207
- }
208
- if (typeof callback === 'function') {
209
- callback(ins, this);
210
- }
211
- if (ins.$.variadic && !ins.hasParser && !ins.hasValidators) {
212
- ins.parser.string();
213
- ins.validator.isStringArray();
214
- }
215
- return this;
216
- }
217
- globalOption(flags, ...args) {
218
- let description = '';
219
- let callback;
220
- if (typeof args[0] === 'string') {
221
- description = args[0];
222
- callback = args[1];
223
- }
224
- else {
225
- callback = args[0];
226
- }
227
- return this.option(flags, (ins) => {
228
- if (description)
229
- ins.description(description);
230
- this.meta.globalOptions.push(ins.$);
231
- if (callback)
232
- callback(ins, this);
233
- if (ins.$.hidden)
234
- this.meta.hiddenGlobalOptions.add(ins.$);
235
- });
236
- }
237
- command(name, ...args) {
238
- const [description, callback] = this.handleCommandArgs(args);
239
- const cmd = new CommandBuilder(name, callback, this, false, false);
240
- if (description)
241
- cmd.description(description);
242
- return this;
243
- }
244
- defaultCommand(name, ...args) {
245
- const [description, callback] = this.handleCommandArgs(args);
246
- const cmd = new CommandBuilder(name, callback, this, false, true);
247
- if (description)
248
- cmd.description(description);
249
- return this;
250
- }
251
- nativeCommand(name, ...args) {
252
- const [description, callback] = this.handleCommandArgs(args);
253
- const cmd = new CommandBuilder(name, callback, this, true, false);
254
- if (description)
255
- cmd.description(description);
256
- return this;
257
- }
258
- handleCommandArgs(args) {
259
- let description = '';
260
- let callback;
261
- if (typeof args[0] === 'string') {
262
- description = args[0];
263
- callback = args[1];
264
- }
265
- else {
266
- callback = args[0];
267
- }
268
- return [description, callback];
269
- }
270
- /**
271
- * Register callback function for the command to execute when invoked.
272
- */
273
- action(fn) {
274
- const isAsync = (0, is_async_function_1.default)(fn) || /^\(.+\) ?=> ?tslib_1\.__awaiter\(/.test(fn.toString().trim());
275
- this.meta.isActionAsync = isAsync;
276
- Object.defineProperty(this.meta, 'actionHandler', { value: fn, configurable: false, writable: false });
277
- this.initializeActionWrapper(isAsync);
278
- return this;
279
- }
280
- usageExamples(...examples) {
281
- const table = examples.map(({ command, description }) => {
282
- if (command.length + (description?.length || 0) > 100) {
283
- throw new Error(`Usage example description too long: ${command}`);
284
- }
285
- return [command, description ?? ''];
286
- });
287
- this.description(this.$.description() + '\n\n' + 'Usage Examples:\n' + (0, node_1.formatTableForTerminal)(table));
288
- return this;
289
- }
290
- errorHandler(fn) {
291
- Object.defineProperty(this.meta, 'errorHandler', { value: fn, configurable: true });
292
- return this;
293
- }
294
- appData(key, value) {
295
- this.features.appData(true);
296
- this.db.appData.defineProperty(key, value);
297
- return this;
298
- }
299
- config(key, entry) {
300
- this.features.config(true);
301
- this.db.config.defineProperty(key, entry);
302
- return this;
303
- }
304
- preset(name, preset) {
305
- this.features.presets();
306
- this.db.presets.defineProperty(name, {
307
- description: preset.description,
308
- presets: preset.presets ?? [],
309
- args: preset.args ?? [],
310
- options: preset.options ?? {},
311
- });
312
- return this;
313
- }
314
- presetsEnabled(boolean = true) {
315
- this.features.presets(boolean);
316
- return this;
317
- }
318
- autoAssignOptionFlags(boolean = true) {
319
- this.features.autoAssignOptionFlags(boolean);
320
- return this;
321
- }
322
- autoAssignAlias(boolean = true) {
323
- this.features.autoAssignAlias(boolean);
324
- return this;
325
- }
326
- /**
327
- * Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
328
- *
329
- * @returns `this` command for chaining
330
- */
331
- allowExcessArguments(bool = true) {
332
- this.$.allowExcessArguments(bool);
333
- return this;
334
- }
335
- /**
336
- * Allow unknown options on the command line.
337
- *
338
- * @returns `this` command for chaining
339
- */
340
- allowUnknownOption(bool = true) {
341
- this.$.allowUnknownOption(bool);
342
- return this;
343
- }
344
- /**
345
- * Enable positional options. Positional means global options are specified before subcommands which lets
346
- * subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
347
- *
348
- * The default behaviour is non-positional and global options may appear anywhere on the command line.
349
- *
350
- * @returns `this` command for chaining
351
- */
352
- enablePositionalOptions(positional) {
353
- this.$.enablePositionalOptions(positional);
354
- return this;
355
- }
356
- /**
357
- * Pass through options that come after command-arguments rather than treat them as command-options,
358
- * so actual command-options come before command-arguments. Turning this on for a subcommand requires
359
- * positional options to have been enabled on the program (parent commands).
360
- *
361
- * The default behaviour is non-positional and options may appear before or after command-arguments.
362
- *
363
- * @returns `this` command for chaining
364
- */
365
- passThroughOptions(passThrough) {
366
- this.$.passThroughOptions(passThrough);
367
- return this;
368
- }
369
- /**
370
- * Register callback to use as replacement for calling process.exit.
371
- */
372
- exitOverride(callback) {
373
- this.$.exitOverride(callback);
374
- return this;
375
- }
376
- /**
377
- * Add hook for life cycle event.
378
- */
379
- hook(event, listener) {
380
- this.$.hook(event, listener);
381
- return this;
382
- }
383
- /**
384
- * You can customise the help by overriding Help properties using configureHelp(),
385
- * or with a subclass of Help by overriding createHelp().
386
- */
387
- configureHelp(configuration) {
388
- this.$.configureHelp(configuration);
389
- return this;
390
- }
391
- /**
392
- * Display the help or a custom message after an error occurs.
393
- */
394
- showHelpAfterError(displayHelp) {
395
- this.$.showHelpAfterError(displayHelp);
396
- return this;
397
- }
398
- /**
399
- * Display suggestion of similar commands for unknown commands, or options for unknown options.
400
- */
401
- showSuggestionAfterError(displaySuggestion) {
402
- this.$.showSuggestionAfterError(displaySuggestion);
403
- return this;
404
- }
405
- /**
406
- * Override default decision whether to add implicit help command.
407
- * @example ```
408
- * addHelpCommand() // force on
409
- * addHelpCommand(false); // force off
410
- * addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details
411
- * ```
412
- * @returns `this` command for chaining
413
- */
414
- addHelpCommand(enableOrNameAndArgs, description) {
415
- this.$.addHelpCommand(enableOrNameAndArgs, description);
416
- return this;
417
- }
418
- /**
419
- * Add additional text to be displayed with the built-in help.
420
- *
421
- * Position is 'before' or 'after' to affect just this command,
422
- * and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
423
- */
424
- addHelpText(title, ...lines) {
425
- title = (0, string_1.strFirstCharToUpperCase)((0, string_1.strEnsureEndsWith)(title, ':'));
426
- this.description(this.$.description() + '\n\n' + title + '\n' + lines.join('\n'));
427
- return this;
428
- }
429
- /**
430
- * Set the order in which the help sections are displayed.
431
- * Subcommands inherit this order.
432
- * Defaults to: Usage, Version, Description, Commands, Arguments, Options, Global Options, Presets, Usage Examples
433
- */
434
- helpSectionOrdering(headers) {
435
- this.meta.helpSectionOrder = headers.map((h) => {
436
- return (0, string_1.strEnsureEndsWith)((0, string_1.strFirstCharToUpperCase)(h), ':');
437
- });
438
- return this;
439
- }
440
- throwCommanderError(message, exitCode = 1, type = 'error') {
441
- throw new extra_typings_1.CommanderError(exitCode, type, message);
442
- }
443
- hideGlobalOptions(...names) {
444
- const globals = this.getGlobalOptions();
445
- names = names.length ? names : globals.map((opt) => opt.attributeName());
446
- for (const name of names) {
447
- if (!name)
448
- continue;
449
- let found = false;
450
- for (const opt of globals) {
451
- if (opt.attributeName() === name) {
452
- this.meta.hiddenGlobalOptions.add(opt);
453
- found = true;
454
- break;
455
- }
456
- }
457
- if (!found)
458
- throw new Error(`Unknown global option name: ${name} for command, ${this.name}`);
459
- }
460
- return this;
461
- }
462
- unhideGlobalOptions(...names) {
463
- const globals = this.getGlobalOptions();
464
- names = names.length ? names : globals.map((opt) => opt.attributeName());
465
- for (const name of names) {
466
- if (!name)
467
- continue;
468
- let found = false;
469
- for (const opt of globals) {
470
- if (opt.attributeName() === name) {
471
- this.meta.hiddenGlobalOptions.delete(opt);
472
- found = true;
473
- break;
474
- }
475
- }
476
- if (!found)
477
- this.throwCommanderError(`Unknown global option name: ${name} for command, ${this.name}`);
478
- }
479
- return this;
480
- }
481
- /**
482
- * Set the directory for searching for executable subcommands of this command.
483
- */
484
- executableDir(path) {
485
- this.$.executableDir(path);
486
- return this;
487
- }
488
- /**
489
- * Store option value.
490
- */
491
- setOptionValue(key, value) {
492
- this.$.setOptionValue(key, value);
493
- return this;
494
- }
495
- /**
496
- * Store option value and where the value came from.
497
- */
498
- setOptionValueWithSource(key, value, source) {
499
- this.$.setOptionValueWithSource(key, value, source);
500
- return this;
501
- }
502
- setDataFilepath(filepath) {
503
- Object.defineProperty(this, 'dataFilepath', { value: filepath });
504
- if (Object.hasOwn(this, 'db') && Object.hasOwn(this.db, 'db')) {
505
- this.db.db.setFilepath(filepath);
506
- }
507
- }
508
- /**
509
- * Display error message and exit (or call exitOverride).
510
- */
511
- outputError(message, options) {
512
- this.$.error(message, options);
513
- }
514
- /**
515
- * Output help information for this command.
516
- */
517
- outputHelp() {
518
- console.log(this.getHelpInformation());
519
- }
520
- /**
521
- * Display error message and exit (or call exitOverride).
522
- */
523
- outputDebugMessage(event, getProps = () => ({})) {
524
- OutputManager_1.OutputManager.getInstance().outputDebug(() => ({ event, cmd: this.getPrefixString(), ...getProps() }));
525
- }
526
- parseArguments(args) {
527
- const last = this.arguments.length - 1;
528
- return args.map((arg, i) => {
529
- if (!arg)
530
- return arg;
531
- const parse = this.meta.argParsers[i > last ? last : i];
532
- return parse ? (Array.isArray(arg) ? arg.map((a) => parse(a)) : parse(arg)) : arg;
533
- });
534
- }
535
- /**
536
- * Parses (and validates) options using the parsers defined in the command builder.
537
- */
538
- parseOptions(opts) {
539
- for (const [key, value] of Object.entries(opts)) {
540
- const parse = this.meta.optParsers[key];
541
- opts[key] = parse ? (Array.isArray(value) ? value.map((o) => parse(o)) : parse(value)) : value;
542
- }
543
- return opts;
544
- }
545
- /**
546
- * Validate ALREADY PARSED args using the validators defined in the command builder.
547
- */
548
- assertValidArguments(parsedArgs) {
549
- const last = this.arguments.length - 1;
550
- parsedArgs.forEach((arg, i) => {
551
- if (arg == null)
552
- return;
553
- const index = i > last ? last : i;
554
- const validators = this.meta.argValidators[index];
555
- if (!validators)
556
- return;
557
- for (const isValid of validators) {
558
- (0, is_1.ensureThat)(arg, isValid, { Err: extra_typings_2.InvalidArgumentError });
559
- }
560
- });
561
- return parsedArgs;
562
- }
563
- /**
564
- * Validate ALREADY PARSED options using the validators defined in the command builder.
565
- */
566
- assertValidOptions(parsedOptions) {
567
- for (const [key, value] of Object.entries(parsedOptions)) {
568
- if (!this.meta.optValidators[key])
569
- continue;
570
- if (value == null)
571
- continue;
572
- for (const isValid of this.meta.optValidators[key]) {
573
- (0, is_1.ensureThat)(value, isValid);
574
- }
575
- }
576
- return parsedOptions;
577
- }
578
- assertValidPreset(key, preset) {
579
- const { description, presets, args, options } = preset;
580
- (0, is_1.ensureThat)(key, is_6.isStringWithNoSpacesOrDashes);
581
- (0, is_1.ensureThat)(description, is_4.isString);
582
- (0, is_1.ensureThat)(presets, is_5.isStringArray);
583
- (0, is_1.ensureThat)(args, is_2.isArray);
584
- this.assertPresetArgsOptional(args);
585
- this.assertValidArguments(args);
586
- (0, is_1.ensureThat)(options, is_3.isObject);
587
- this.assertValidOptions(options);
588
- }
589
- throwRatherThanExitProcess() {
590
- const throwError = (error) => {
591
- throw error;
592
- };
593
- this.errorHandler(throwError);
594
- this.exitOverride(throwError);
595
- }
596
- get name() {
597
- return this.$.name();
598
- }
599
- /**
600
- * Get the command at the root of the command tree.
601
- */
602
- get root() {
603
- if (this.isRoot)
604
- return this;
605
- return this.getAncestors().pop();
606
- }
607
- get isRoot() {
608
- return !this.parent;
609
- }
610
- get arguments() {
611
- return this.$.registeredArguments;
612
- }
613
- get options() {
614
- return this.$.options;
615
- }
616
- get commander() {
617
- return this.$;
618
- }
619
- get hasGrandChildren() {
620
- return this.meta.subcommands.some((sub) => !!sub.meta.subcommands.length);
621
- }
622
- /**
623
- * Returns whether a command's last argument is variadic.
624
- */
625
- get isLastArgVariadic() {
626
- if (!this.arguments.length)
627
- return false;
628
- return (0, array_1.arrLast)(this.arguments).variadic;
629
- }
630
- get jsonFilepath() {
631
- return path_1.default.join(CommandBuilder.dataDirectory, this.root.name + '.json');
632
- }
633
- /**
634
- * Get the executable search directory.
635
- */
636
- getExecutableDir() {
637
- return this.$.executableDir();
638
- }
639
- /**
640
- * Retrieve option value.
641
- */
642
- getOptionValue(key) {
643
- return this.$.getOptionValue(key);
644
- }
645
- /**
646
- * Get source of option value.
647
- */
648
- getOptionValueSource(key) {
649
- return this.$.getOptionValueSource(key);
650
- }
651
- /**
652
- * Get source of option value. See also .optsWithGlobals().
653
- */
654
- getOptionValueSourceWithGlobals(key) {
655
- return this.$.getOptionValueSourceWithGlobals(key);
656
- }
657
- getActionHandler() {
658
- return this.meta.actionHandler;
659
- }
660
- getDescription() {
661
- return this.$.description();
662
- }
663
- getSummary() {
664
- return this.$.summary();
665
- }
666
- getVersion() {
667
- return this.$.version();
668
- }
669
- getAlias() {
670
- return this.$.alias();
671
- }
672
- getAliases() {
673
- return this.$.aliases();
674
- }
675
- /**
676
- * Get a commands prefix array based on all its parent/ancestor commands.
677
- */
678
- getPrefixArray() {
679
- return this.getAncestors({ inclusive: true })
680
- .reverse()
681
- .map((node) => node.name);
682
- }
683
- /**
684
- * Get a commands prefix string based on all its parent/ancestor commands.
685
- */
686
- getPrefixString() {
687
- return this.getPrefixArray().join(' ');
688
- }
689
- getGlobalOptions() {
690
- const result = [];
691
- for (const anc of this.getAncestors({ inclusive: true }).reverse()) {
692
- for (const gopt of anc.meta.globalOptions) {
693
- if (!this.meta.hiddenGlobalOptions.has(gopt)) {
694
- result.push(gopt);
695
- }
696
- }
697
- }
698
- return result;
699
- }
700
- getOwnAndGlobalOptions() {
701
- return this.options.concat(this.getGlobalOptions());
702
- }
703
- *getChildrenIterator(options) {
704
- if (options?.inclusive)
705
- yield this;
706
- for (const sub of this.meta.subcommands) {
707
- yield sub;
708
- yield* sub.getChildrenIterator();
709
- }
710
- }
711
- getChildren(options) {
712
- return [...this.getChildrenIterator(options)];
713
- }
714
- *getAncestorsIterator(options) {
715
- if (options?.inclusive)
716
- yield this;
717
- let node = this.parent;
718
- while (node) {
719
- yield node;
720
- node = node.parent;
721
- }
722
- }
723
- /**
724
- * Get a command's ancestors, optionally starting from the command itself.
725
- */
726
- getAncestors(options) {
727
- return [...this.getAncestorsIterator(options)];
728
- }
729
- *getSiblingsIterator() {
730
- if (!this.parent)
731
- return;
732
- for (const sub of this.parent.meta.subcommands) {
733
- if (sub === this)
734
- continue;
735
- yield sub;
736
- }
737
- }
738
- /**
739
- * Returns an array of sibling CommandBuilder objects.
740
- */
741
- getSiblings() {
742
- return [...this.getSiblingsIterator()];
743
- }
744
- /**
745
- * Render the help string for the command.
746
- */
747
- getHelpInformation() {
748
- return this.$.helpInformation();
749
- }
750
- getOptsWithGlobals() {
751
- return (0, object_2.objAssign)({}, ...this.options.map((opt) => ({ [opt.attributeName()]: opt.defaultValue })), this.parseOptions(this.$.optsWithGlobals()));
752
- }
753
- /**
754
- * Parse `argv`, setting options and invoking commands when defined.
755
- *
756
- * The default expectation is that the arguments are from node and have the application as argv[0]
757
- * and the script being run in argv[1], with user parameters after that.
758
- *
759
- * @example
760
- * ```
761
- * program.parse(process.argv);
762
- * program.parse(); // implicitly use process.argv and auto-detect node vs electron conventions
763
- * program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
764
- * ```
765
- *
766
- * @returns `this` command for chaining
767
- */
768
- parse(argv, options) {
769
- this.$.parse(argv, options);
770
- return this;
771
- }
772
- /**
773
- * Parse `argv`, setting options and invoking commands when defined.
774
- *
775
- * Use parseAsync instead of parse if any of your action handlers are async. Returns a Promise.
776
- *
777
- * The default expectation is that the arguments are from node and have the application as argv[0]
778
- * and the script being run in argv[1], with user parameters after that.
779
- *
780
- * @example
781
- * ```
782
- * program.parseAsync(process.argv);
783
- * program.parseAsync(); // implicitly use process.argv and auto-detect node vs electron conventions
784
- * program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
785
- * ```
786
- *
787
- * @returns Promise
788
- */
789
- async parseAsync(argv, options) {
790
- await this.$.parseAsync(argv, options);
791
- return this;
792
- }
793
- execute(argv, options) {
794
- return this.meta.isActionAsync ? this.parseAsync(argv, options) : this.parse(argv, options);
795
- }
796
- getParsedValidArgsOptsWithPresets() {
797
- const [presetArgs, presetOpts, presetOrder] = this.getPresetArgsAndOpts();
798
- const args = this.getParsedValidArgsWithPresets(presetArgs);
799
- const opts = this.getParsedValidOptsWithPresets(presetOpts);
800
- this.debugLogArgsOpts(args, opts, presetArgs, presetOpts, presetOrder);
801
- return [args, opts];
802
- }
803
- getParsedValidArgsWithPresets(presetArgs) {
804
- const result = (0, object_1.arrAssign)([], ...presetArgs, this.parseArguments(this.$.args));
805
- this.combineVariadicArgs(result);
806
- this.assertValidArguments(result);
807
- return this.padArgsWithUndefinedUntilExpectedLength(result);
808
- }
809
- getParsedValidOptsWithPresets(presetOpts) {
810
- const parsed = this.getOptsWithGlobals();
811
- const opts = presetOpts.length ? (0, object_2.objAssign)({}, ...presetOpts, parsed) : parsed;
812
- this.hideOptionsWithDefaultOrNoValue(opts, { defaults: true, undefined: true, invalid: true });
813
- this.assertValidOptions(opts);
814
- return opts;
815
- }
816
- getPresetArgsAndOpts() {
817
- if (!this.features.isPresetsEnabled)
818
- return [[], [], []];
819
- const opts = this.$.optsWithGlobals();
820
- if (!opts.presets)
821
- return [[], [], []];
822
- const presets = this.db.presets.getAll();
823
- const presetOrder = (0, array_2.arrRemoveDuplicates)(opts.presets
824
- .map((name) => {
825
- if (!presets[name])
826
- throw new Error(`Unknown preset name: ${name}`);
827
- return presets[name].presets.concat(name);
828
- })
829
- .flat());
830
- presetOrder.unshift('defaults');
831
- const presetArgs = presetOrder.map((name) => presets[name].args);
832
- const presetOpts = presetOrder.map((name) => presets[name].options);
833
- return [presetArgs, presetOpts, presetOrder];
834
- }
835
- combineVariadicArgs(result) {
836
- if (this.isLastArgVariadic) {
837
- if (result.length && !Array.isArray((0, array_1.arrLast)(result))) {
838
- const rest = result.splice(this.arguments.length - 1);
839
- result.push(rest.filter((arg) => arg != null));
840
- }
841
- else {
842
- result.push([]);
843
- }
844
- }
845
- return result;
846
- }
847
- debugLogArgsOpts(args, opts, presetArgs, presetOpts, presetOrder) {
848
- if (!opts['debug'])
849
- return;
850
- if (this.features.isPresetsEnabled) {
851
- this.outputDebugMessage('parsePresets', () => ({ presetOrder, presetArgs, presetOpts }));
852
- }
853
- this.outputDebugMessage('parseArgsOpts', () => ({
854
- args,
855
- opts,
856
- command: [this.root.name, ...this.root.meta.rawArgs].join(' '),
857
- }));
858
- }
859
- hideOptionsWithDefaultOrNoValue(opts, options = {}) {
860
- const allOpts = this.getOwnAndGlobalOptions();
861
- const optMap = Object.fromEntries(allOpts.map((o) => [o.attributeName(), o]));
862
- for (const [key, value] of Object.entries(opts)) {
863
- if (value === false ||
864
- (!options.undefined && value == null) ||
865
- (!options.invalid && !optMap[key]) ||
866
- (!options.defaults && optMap[key].defaultValue === value)) {
867
- (0, object_4.setNonEnumerable)(opts, key);
868
- }
869
- }
870
- return opts;
871
- }
872
- handleOutputOptions() {
873
- const opts = this.$.optsWithGlobals();
874
- const om = OutputManager_1.OutputManager.getInstance().reset();
875
- if (opts['noColor'])
876
- om.colors.enabled = false;
877
- if (opts['noStderr'])
878
- om.stderr.disable();
879
- if (opts['noStdout'])
880
- om.stdout.disable();
881
- if (opts['debug']) {
882
- om.debug.enable();
883
- om.drainDebugMessageQueue();
884
- }
885
- }
886
- padArgsWithUndefinedUntilExpectedLength(args) {
887
- while (args.length < this.arguments.length)
888
- args.push(undefined);
889
- return args;
890
- }
891
- assertPresetArgsOptional(args) {
892
- // args.forEach((arg, i) => {
893
- // if (arg != null && i < this.arguments.length && this.arguments[i].required) {
894
- // this.throwCommanderError(`Cannot preset required arguments.`)
895
- // }
896
- // })
897
- }
898
- addUtilCommands() {
899
- if (!this.hasGrandChildren &&
900
- !this.features.isConfigEnabled &&
901
- !this.features.isPresetsEnabled &&
902
- !this.features.isAppDataEnabled) {
903
- return;
904
- }
905
- this.nativeCommand('util', (u) => {
906
- const cmd = u.parent;
907
- u.alias('u');
908
- u.description('Utility commands.');
909
- if (cmd.features.isConfigEnabled) {
910
- u.nativeCommand('config', createConfigCommand);
911
- }
912
- if (cmd.features.isPresetsEnabled && cmd.meta.hasCustomActionHandler) {
913
- u.nativeCommand('presets', createPresetsCommand);
914
- }
915
- if (cmd.hasGrandChildren) {
916
- u.nativeCommand('list', createUtilListCommand);
917
- }
918
- if (cmd.isRoot &&
919
- (cmd.features.isConfigEnabled || cmd.features.isPresetsEnabled || cmd.features.isAppDataEnabled)) {
920
- u.nativeCommand('filepath', createUtilFilepathCommand);
921
- }
922
- function createUtilFilepathCommand(f) {
923
- f.alias('f');
924
- f.description('Print filepath to JSON file containing user data, eg. config and presets.');
925
- f.action(async () => {
926
- console.log(path_1.default.dirname(cmd.jsonFilepath));
927
- console.log(cmd.jsonFilepath);
928
- });
929
- }
930
- function createUtilListCommand(l) {
931
- l.alias('l');
932
- l.description('List nested subcommands.');
933
- l.option('--all', 'Include utility commands.');
934
- l.option('--noBorders', (o) => 'Remove borders from output');
935
- l.option('--plain-list', (o) => {
936
- o.description('Only a list of commands with no borders, colors, summaries or formatting.');
937
- o.implies({ noBorders: true, noColor: true });
938
- });
939
- l.action(async (opts) => {
940
- const filter = opts.all
941
- ? // ? (prefix: string) => {
942
- // return !/ (config|presets)( .+)$/gi.test(prefix) && !/ util$/gi.test(prefix)
943
- // }
944
- (prefix) => prefix
945
- : (prefix) => {
946
- return !/ (config|presets|util)( .+)?$/gi.test(prefix);
947
- };
948
- const table = [];
949
- for (const c of cmd.getChildrenIterator({ inclusive: true })) {
950
- const prefix = c.getPrefixString();
951
- if (filter && !filter(prefix))
952
- continue;
953
- table.push([prefix, c.getSummary()]);
954
- }
955
- const ansi = table.map((row) => {
956
- const arr = row[0].split(' ');
957
- const last = arr.pop();
958
- let col = ansi_colors_1.default.magenta;
959
- if (/ (util|config|presets) /.test(row[0])) {
960
- col = ansi_colors_1.default.gray;
961
- }
962
- else if (/ (util|config|presets)$/.test(row[0])) {
963
- col = ansi_colors_1.default.dim;
964
- }
965
- row[0] = arr.map(ansi_colors_1.default.dim).concat(col(last)).join(' ');
966
- return row;
967
- });
968
- let result = (0, node_1.formatTableForTerminal)(ansi, ['Command', 'Summary']);
969
- if (opts.noBorders) {
970
- result = result
971
- .replace(/[├┼┤┐┘└┌┬┴│─]/g, '')
972
- .split('\n')
973
- .map((line) => line.trim())
974
- .filter((line) => line !== '\x1B[90m\x1B[39m')
975
- .join('\n');
976
- }
977
- if (opts.plainList) {
978
- const lines = result.split('\n');
979
- const i = lines[0].indexOf('Summary');
980
- result = lines
981
- .map((line) => line.substring(0, i).trim())
982
- .slice(1)
983
- .join('\n');
984
- }
985
- console.log(result);
986
- });
987
- }
988
- function createPresetsCommand(p) {
989
- const db = cmd.db.presets;
990
- p.alias('p');
991
- p.description('Edit presets in your text editor.', 'A preset consists of pre-set arguments and/or options for a command.', 'Additionally, a preset can have other presets as dependencies.', 'When running the command, multiple presets can be stacked.', 'Required arguments cannot be pre-set.');
992
- p.nativeCommand('edit', (e) => {
993
- e.alias('e');
994
- e.description('Edit as JSON in a text editor.');
995
- e.option('--editor [cmd]', 'The command to launch your preferred text editor.');
996
- e.action(async (opts) => {
997
- db.edit(opts.editor);
998
- console.info(db.getAll());
999
- });
1000
- });
1001
- p.nativeCommand('list', (l) => {
1002
- l.alias('l');
1003
- l.description('List all presets.');
1004
- l.action(async () => console.dir(db.getAll(), { depth: null }));
1005
- });
1006
- // const presets = db.getAll()
1007
- cmd.option('-P, --presets <names...>', (o) => {
1008
- o.description('Apply preset(s).');
1009
- });
1010
- }
1011
- function createConfigCommand(c) {
1012
- const db = cmd.db.config;
1013
- c.alias('c');
1014
- c.description('Manage configuration file.');
1015
- c.nativeCommand('edit', (e) => {
1016
- e.alias('e');
1017
- e.description('Edit as JSON in a text editor.');
1018
- e.option('--editor [cmd]', 'The command to launch your preferred text editor.');
1019
- e.action(async (opts) => {
1020
- db.edit(opts.editor);
1021
- console.info(db.getAll());
1022
- });
1023
- });
1024
- c.nativeCommand('list', (l) => {
1025
- l.alias('l');
1026
- l.description('Print entire config with details.');
1027
- l.action(async () => {
1028
- const result = db.keys.map((key) => ({
1029
- key,
1030
- description: db.descriptions[key],
1031
- value: db.get(key),
1032
- defaultValue: db.defaultValues[key],
1033
- }));
1034
- console.dir(result, { depth: null });
1035
- });
1036
- });
1037
- c.nativeCommand('get', (g) => {
1038
- g.alias('g');
1039
- g.description('Print value(s) from the config.');
1040
- g.argument('[key]', 'The key to print the value of. Omit to print all values.');
1041
- g.action(async (key) => console.log(key ? db.get(key) : db.getAll()));
1042
- });
1043
- c.nativeCommand('set', (s) => {
1044
- s.alias('s');
1045
- s.description('Set a value in the config.');
1046
- s.argument('<key>', 'The key to set the value of.');
1047
- s.argument('<value>', 'The new value.');
1048
- s.action(async (key, val) => {
1049
- const parse = db.parsers[key];
1050
- const value = typeof parse === 'function' ? parse(val) : val;
1051
- db.set(key, value);
1052
- console.info({ [key]: value });
1053
- });
1054
- });
1055
- c.nativeCommand('reset', (r) => {
1056
- r.alias('r');
1057
- r.description('Reset to defaults.');
1058
- r.argument('[key]', 'The key for which to reset the value. Omit to reset entire config.');
1059
- r.action(async (key) => {
1060
- if (key)
1061
- db.reset(key);
1062
- else
1063
- db.resetAll();
1064
- console.info(db.getAll());
1065
- });
1066
- });
1067
- }
1068
- });
1069
- }
1070
- /**
1071
- * Makes aliases for the command.
1072
- * The idea is to be able to navigate the command tree by only typing the first letter(s) of the command names.
1073
- *
1074
- * Example: A command 'cola' would get these aliases: ['c', 'co', 'col'].
1075
- * However, if there are namespace clashes with sibling subcommands that start with the same letter,
1076
- * eg. like 'cola' and 'coal' where the first two letters clash, cola's aliases are reduced to only ['col'] and similarly for 'coal'.
1077
- *
1078
- * This method creates the aliases, ensuring there are no clashes with sublings, why it is important that the
1079
- * entire command tree is built before invoking this method.
1080
- */
1081
- assignAlias() {
1082
- if (this.getAlias() || this.name.length <= 1)
1083
- return this;
1084
- const sibAliases = this.getSiblings()
1085
- .map((sib) => sib.getAliases())
1086
- .flat();
1087
- for (let i = 0; i < this.name.length - 1; i++) {
1088
- let cmdAlias = this.name.substring(0, i + 1);
1089
- let isClash = cmdAlias === 'u' ||
1090
- (0, array_3.arrSome)(sibAliases, (sibAlias) => {
1091
- return cmdAlias === sibAlias;
1092
- });
1093
- if (isClash && i === 0) {
1094
- cmdAlias = cmdAlias.charAt(0).toUpperCase();
1095
- isClash = (0, array_3.arrSome)(sibAliases, (sibAlias) => {
1096
- return cmdAlias === sibAlias;
1097
- });
1098
- }
1099
- if (isClash)
1100
- continue;
1101
- this.alias(cmdAlias);
1102
- return this;
1103
- }
1104
- return this;
1105
- }
1106
- /**
1107
- * Automatically set 'short' and 'long' names to options that don't have one assigned yet.
1108
- *
1109
- * First, it tries to assign a short name based on the first letter of the option's attribute name
1110
- * Both lower and upper case are tried. If these is not available, the next letter of the option name is tried.
1111
- *
1112
- * If none of the letters of the option name are available, the option is skipped until all other
1113
- * options have had letters from their names attempted assigned.
1114
- * Those that remain are assigned the first available letter of the alphabet + 0-9.
1115
- * If there are 64 options for the command and no more alphanumeric characters are available,
1116
- * the option is not assigned a short name.
1117
- */
1118
- assignOptionFlags() {
1119
- const taken = new Set();
1120
- for (const anc of this.getAncestorsIterator({ inclusive: true })) {
1121
- anc.options.forEach((opt) => {
1122
- if (!opt.short)
1123
- return;
1124
- taken.add(opt.short.replace(/^-/g, ''));
1125
- });
1126
- }
1127
- const failed = new Set();
1128
- // assign letter from option name
1129
- this.options.forEach((opt) => {
1130
- if (opt.short)
1131
- return;
1132
- const name = opt.attributeName();
1133
- for (let c = 0; c < name.length; c++) {
1134
- let char = name.charAt(c).toLowerCase();
1135
- if (taken.has(char)) {
1136
- char = char.toUpperCase();
1137
- if (taken.has(char))
1138
- continue;
1139
- }
1140
- OptionHelpers_1.OptionHelpers.setShort(opt, char);
1141
- taken.add(char);
1142
- return;
1143
- }
1144
- failed.add(opt);
1145
- });
1146
- // assign random alphanumeric character.
1147
- const name = 'abcdefghijklmnopqrstuvwxyz1234567890';
1148
- failed.forEach((opt) => {
1149
- for (let c = 0; c < name.length; c++) {
1150
- let char = name.charAt(c);
1151
- if (taken.has(char)) {
1152
- char = char.toUpperCase();
1153
- if (taken.has(char))
1154
- continue;
1155
- }
1156
- OptionHelpers_1.OptionHelpers.setShort(opt, char);
1157
- taken.add(char);
1158
- return;
1159
- }
1160
- });
1161
- }
1162
- assertNoDuplicateCommandNames() {
1163
- const names = this.$.commands.map((sub) => sub.aliases().concat(sub.name())).flat();
1164
- if (names.length !== new Set(names).size) {
1165
- throw new Error(`Duplicate subcommand names/aliases found for command, ${this.name}: ${names.join(', ')}`);
1166
- }
1167
- }
1168
- hasIdenticalParentOption(option) {
1169
- const flags = option.flags;
1170
- for (const anc of this.getAncestorsIterator({ inclusive: true })) {
1171
- for (const opt of anc.$.options) {
1172
- if (flags === opt.flags) {
1173
- return true;
1174
- }
1175
- }
1176
- }
1177
- return false;
1178
- }
1179
- assertNoDuplicateOptionNames() {
1180
- const throwErr = (cmd, opt, anc) => {
1181
- throw new Error(`Duplicate option names > cmd: ${cmd.name}, ${anc ? `anc: ${anc.name}, ` : ''}opt: ${opt}`);
1182
- };
1183
- const set = new Set();
1184
- for (const opt of this.options) {
1185
- if (opt.name() === 'help')
1186
- continue;
1187
- if (opt.short) {
1188
- if (set.has(opt.short))
1189
- throwErr(this, opt.short);
1190
- set.add(opt.short);
1191
- }
1192
- if (opt.long) {
1193
- if (set.has(opt.long))
1194
- throwErr(this, opt.long);
1195
- set.add(opt.long);
1196
- }
1197
- if (opt.attributeName()) {
1198
- if (set.has(opt.attributeName()))
1199
- throwErr(this, opt.attributeName());
1200
- set.add(opt.attributeName());
1201
- }
1202
- }
1203
- for (const anc of this.getAncestorsIterator()) {
1204
- for (const opt of anc.$.options) {
1205
- if (opt.short && set.has(opt.short)) {
1206
- if (opt.short !== 'V')
1207
- continue;
1208
- throwErr(this, opt.short, anc);
1209
- }
1210
- if (opt.long && set.has(opt.long)) {
1211
- throwErr(this, opt.long, anc);
1212
- }
1213
- if (opt.attributeName() && set.has(opt.attributeName())) {
1214
- throwErr(this, opt.attributeName(), anc);
1215
- }
1216
- }
1217
- }
1218
- }
1219
- initializeActionWrapper(isAsync = false) {
1220
- if (isAsync) {
1221
- this.$.action(async () => {
1222
- try {
1223
- this.handleOutputOptions();
1224
- const [args, opts] = this.getParsedValidArgsOptsWithPresets();
1225
- if (opts['help'])
1226
- return this.outputHelp();
1227
- await this.meta.actionHandler.call(this, ...args, opts, this);
1228
- }
1229
- catch (error) {
1230
- this.meta.errorHandler.call(this, error, this);
1231
- }
1232
- });
1233
- }
1234
- else {
1235
- this.$.action(() => {
1236
- try {
1237
- this.handleOutputOptions();
1238
- const [args, opts] = this.getParsedValidArgsOptsWithPresets();
1239
- if (opts['help'])
1240
- return this.outputHelp();
1241
- this.meta.actionHandler.call(this, ...args, opts, this);
1242
- }
1243
- catch (error) {
1244
- this.meta.errorHandler.call(this, error, this);
1245
- }
1246
- });
1247
- }
1248
- }
1249
- initializeHelp() {
1250
- if (this.isRoot)
1251
- this.globalOption('-h, --help', 'show help');
1252
- this.$.addHelpCommand('?', 'show help');
1253
- this.$.configureHelp(DefaultHelpConfig_1.DefaultHelpConfig);
1254
- }
1255
- inheritParentHiddenGlobals() {
1256
- if (!this.parent)
1257
- return;
1258
- for (const opt of this.parent.meta.hiddenGlobalOptions) {
1259
- this.meta.hiddenGlobalOptions.add(opt);
1260
- }
1261
- }
1262
- assertCommandNameNotReserved(name) {
1263
- if (this.isRoot)
1264
- return;
1265
- if (this.meta.isNative)
1266
- return;
1267
- if (name === 'u' || name === 'util') {
1268
- throw new Error(`Name '${name}' is reserved and is not available as name or alias.`);
1269
- }
1270
- }
1271
- }
1272
- exports.CommandBuilder = CommandBuilder;
1273
- function CLI(name, cb) {
1274
- return new CommandBuilder(name, cb);
1275
- }
1276
- exports.CLI = CLI;
1277
- //# sourceMappingURL=CommandBuilder.js.map