@bemoje/cli 0.0.2 → 0.0.3
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/index.cjs.js +2338 -1764
- package/index.esm.js +2243 -1659
- package/package.json +5 -3
- package/src/{core/CommandBuilder → arg}/ArgumentBuilder.d.ts +5 -6
- package/src/arg/ArgumentParserSelector.d.ts +8 -0
- package/src/{core/CommandBuilder → arg}/ArgumentReader.d.ts +1 -2
- package/src/arg/ArgumentValidatorSelector.d.ts +7 -0
- package/src/cmd/CLI.d.ts +2 -0
- package/src/cmd/CommandBuilder.d.ts +238 -0
- package/src/cmd/CommandBuilderMetaData.d.ts +23 -0
- package/src/cmd/CommandFeatureSelector.d.ts +79 -0
- package/src/cmd/DefaultHelpConfig.d.ts +2 -0
- package/src/core/OutputManager.d.ts +63 -0
- package/src/{parsers/selector/AbstractStringParserSelector.d.ts → core/ParserSelector.d.ts} +5 -6
- package/src/core/ValidatorSelector.d.ts +16 -0
- package/src/core/counter.d.ts +3 -0
- package/src/db/AbstractJsonFileSection.d.ts +136 -0
- package/src/db/AppDataSection.d.ts +29 -0
- package/src/db/ConfigSection.d.ts +47 -0
- package/src/db/JsonFile.d.ts +35 -0
- package/src/db/PresetsSection.d.ts +44 -0
- package/src/index.d.ts +102 -112
- package/src/opt/OptionArgumentParserSelector.d.ts +7 -0
- package/src/opt/OptionArgumentValidatorSelector.d.ts +7 -0
- package/src/{core/CommandBuilder → opt}/OptionBuilder.d.ts +6 -5
- package/src/opt/OptionHelpers.d.ts +32 -0
- package/src/{core/CommandBuilder → opt}/OptionReader.d.ts +2 -3
- package/src/proto/overrideCommanderPrototype.d.ts +8 -0
- package/src/types/IConfig.d.ts +21 -0
- package/src/types/IPreset.d.ts +6 -7
- package/src/util/array/arrLast.d.ts +12 -0
- package/src/util/array/arrSome.d.ts +15 -0
- package/src/util/array/types/ArrayPredicate.d.ts +10 -0
- package/src/util/db/JsonDB.d.ts +65 -0
- package/src/util/fs/promptUserEditInTextEditor/IGetUserInputFromEditorOptions.d.ts +15 -0
- package/src/util/fs/promptUserEditInTextEditor/promptUserEditInTextEditorSync.d.ts +9 -0
- package/src/util/fs/promptUserEditInTextEditor/promptUserEditJsonInTextEditorSync.d.ts +13 -0
- package/src/util/fs/readFile/readFileSafeSync.d.ts +13 -0
- package/src/util/fs/readFile/readFileSync.d.ts +10 -0
- package/src/util/fs/readJsonFile/readJsonFileSafeSync.d.ts +9 -0
- package/src/util/fs/removeFile/removeFile.d.ts +1 -0
- package/src/util/fs/tempFile/tempFileSync.d.ts +7 -0
- package/src/util/fs/types/IReadJsonFileOptions.d.ts +1 -0
- package/src/util/fs/writeFile/writeFileSafeSync.d.ts +1 -0
- package/src/util/fs/writeFile/writeFileSync.d.ts +1 -0
- package/src/util/fs/writeJsonFile/writeJsonFileSafe.d.ts +1 -0
- package/src/{core/util → util/function}/MethodDisabler.d.ts +4 -3
- package/src/util/function/funSetName.d.ts +13 -0
- package/src/util/node/execInherit.d.ts +1 -0
- package/src/{core/util → util/object}/createArrayMerger.d.ts +3 -0
- package/src/{core/util → util/object}/createObjectMerger.d.ts +4 -1
- package/src/util/object/objUpdatePropertyDescriptors.d.ts +16 -0
- package/src/util/object/setNonEnumerable.d.ts +15 -0
- package/src/util/os/defaultOpenInEditorCommand.d.ts +5 -0
- package/src/util/os/isOSX.d.ts +6 -0
- package/src/util/os/isVsCodeInstalled.d.ts +5 -0
- package/src/util/os/isWindows.d.ts +8 -0
- package/src/util/path/getTempDataPath.d.ts +6 -0
- package/src/util/regex/regexEscapeString.d.ts +11 -0
- package/src/util/string/strEnsureStartsWith.d.ts +12 -0
- package/src/util/string/strFirstCharToUpperCase.d.ts +9 -0
- package/src/util/string/strIsLowerCase.d.ts +11 -0
- package/src/util/string/strIsUpperCase.d.ts +11 -0
- package/src/util/string/strSplitCamelCase.d.ts +11 -0
- package/src/util/types/Any.d.ts +1 -0
- package/src/util/types/DeepArray.d.ts +10 -0
- package/src/util/types/DeepObject.d.ts +14 -0
- package/src/util/types/JsonArray.d.ts +6 -0
- package/src/util/types/JsonDefinedPrimitive.d.ts +4 -0
- package/src/util/types/JsonObject.d.ts +6 -0
- package/src/util/types/JsonRawPrimitive.d.ts +5 -0
- package/src/util/types/JsonValue.d.ts +7 -0
- package/src/util/types/ObjectKey.d.ts +1 -0
- package/src/util/types/TConstructor.d.ts +5 -0
- package/src/util/types/TFunction.d.ts +4 -0
- package/src/util/types/TFunctionNoNew.d.ts +2 -0
- package/src/util/types/TPlainObject.d.ts +2 -0
- package/src/util/types/TPrimitive.d.ts +1 -0
- package/src/util/types/TValidator.d.ts +1 -0
- package/src/{validators → util/validation}/createTypedArrayValidator.d.ts +1 -3
- package/src/util/validation/ensureThat.d.ts +6 -0
- package/src/util/validation/isFunction.d.ts +11 -0
- package/src/{validators → util/validation}/isNamedFunction.d.ts +1 -1
- package/src/util/validation/isObject.d.ts +15 -0
- package/src/util/validation/isPlainObject.d.ts +6 -0
- package/src/util/validation/isPrimitive.d.ts +12 -0
- package/src/util/validation/numbers/isInteger.d.ts +13 -0
- package/src/util/validation/numbers/isValidNumber.d.ts +15 -0
- package/src/core/CommandBuilder/Base.d.ts +0 -5
- package/src/core/CommandBuilder/CommandBuilder.d.ts +0 -80
- package/src/core/CommandBuilder/CommandBuilder.example.d.ts +0 -1
- package/src/core/CommandBuilder/CommandBuilderMetaData.d.ts +0 -17
- package/src/core/CommandBuilder/CommandFeatureSelector.d.ts +0 -26
- package/src/core/CommandBuilder/OutputManager.d.ts +0 -47
- package/src/core/CommandBuilder/assertCommandNameNotReserved.d.ts +0 -1
- package/src/core/CommandBuilder/ensureBackRefToCommandBuilder.d.ts +0 -7
- package/src/core/CommandBuilder/features/action/actionWrapper.d.ts +0 -5
- package/src/core/CommandBuilder/features/action/combineVariadicArgs.d.ts +0 -3
- package/src/core/CommandBuilder/features/action/debugLogArgsOpts.d.ts +0 -4
- package/src/core/CommandBuilder/features/action/deleteOptionsWithDefaultOrNoValue.d.ts +0 -3
- package/src/core/CommandBuilder/features/action/getPresetArgsAndOpts.d.ts +0 -3
- package/src/core/CommandBuilder/features/action/handleError.d.ts +0 -2
- package/src/core/CommandBuilder/features/action/handleOutputOptions.d.ts +0 -2
- package/src/core/CommandBuilder/features/action/optsWithGlobalsParsed.d.ts +0 -2
- package/src/core/CommandBuilder/features/action/padArgsWithUndefinedUntilExpectedLength.d.ts +0 -3
- package/src/core/CommandBuilder/features/action/parseArguments.d.ts +0 -2
- package/src/core/CommandBuilder/features/action/parseOptions.d.ts +0 -6
- package/src/core/CommandBuilder/features/action/parsedValidArgsOptsWithPresets.d.ts +0 -2
- package/src/core/CommandBuilder/features/action/parsedValidArgsWithPresets.d.ts +0 -2
- package/src/core/CommandBuilder/features/action/parsedValidOptsWithPresets.d.ts +0 -3
- package/src/core/CommandBuilder/features/addConfigCommands.d.ts +0 -3
- package/src/core/CommandBuilder/features/addPresetsCommands.d.ts +0 -3
- package/src/core/CommandBuilder/features/addUtilCommands.d.ts +0 -2
- package/src/core/CommandBuilder/features/assertNoDuplicateCommandNames.d.ts +0 -2
- package/src/core/CommandBuilder/features/assertNoDuplicateOptionNames.d.ts +0 -2
- package/src/core/CommandBuilder/features/autoAssignMissingOptionFlags.d.ts +0 -14
- package/src/core/CommandBuilder/features/autoAssignSubCommandAliases.d.ts +0 -13
- package/src/core/CommandBuilder/features/getClosestNonNativeParent.d.ts +0 -2
- package/src/core/CommandBuilder/getGlobalOptions.d.ts +0 -3
- package/src/core/CommandBuilder/getOwnAndGlobalOptions.d.ts +0 -3
- package/src/core/CommandBuilder/initializeCommand.d.ts +0 -2
- package/src/core/db/AbstractJsonFileSection.d.ts +0 -45
- package/src/core/db/ConfigSection.d.ts +0 -19
- package/src/core/db/JsonDB.d.ts +0 -19
- package/src/core/db/JsonFile.d.ts +0 -25
- package/src/core/db/JsonFileError.d.ts +0 -6
- package/src/core/db/PresetsSection.d.ts +0 -14
- package/src/core/help/configureHelp.d.ts +0 -2
- package/src/core/util/assertPresetArgsOptional.d.ts +0 -3
- package/src/core/util/assertValidArguments.d.ts +0 -6
- package/src/core/util/assertValidOptions.d.ts +0 -6
- package/src/core/util/assertValidPreset.d.ts +0 -3
- package/src/core/util/commandExists.d.ts +0 -5
- package/src/core/util/commandLocation.d.ts +0 -5
- package/src/core/util/errorToString.d.ts +0 -1
- package/src/core/util/escapeShellCommandArgument.d.ts +0 -5
- package/src/core/util/forEachChildRecursive.d.ts +0 -4
- package/src/core/util/getARGV.d.ts +0 -1
- package/src/core/util/getAncestors.d.ts +0 -7
- package/src/core/util/getChildren.d.ts +0 -4
- package/src/core/util/getJsonFilepath.d.ts +0 -2
- package/src/core/util/getOptionArgumentName.d.ts +0 -5
- package/src/core/util/getRootCommand.d.ts +0 -5
- package/src/core/util/getSiblings.d.ts +0 -5
- package/src/core/util/hasVariadicArguments.d.ts +0 -5
- package/src/core/util/objDestroy.d.ts +0 -2
- package/src/core/util/optHasArgument.d.ts +0 -2
- package/src/core/util/prefixArray.d.ts +0 -5
- package/src/core/util/prefixString.d.ts +0 -5
- package/src/core/util/prefixStringsRecursive.d.ts +0 -5
- package/src/core/util/renderOptionFlags.d.ts +0 -6
- package/src/core/util/setOptionLongName.d.ts +0 -6
- package/src/core/util/setOptionShortName.d.ts +0 -6
- package/src/core/util/walkAncestors.d.ts +0 -7
- package/src/core/util/walkChildren.d.ts +0 -4
- package/src/core/util/walkSiblings.d.ts +0 -5
- package/src/parsers/createTupleListParser.d.ts +0 -11
- package/src/parsers/selector/ArgumentParserSelector.d.ts +0 -7
- package/src/parsers/selector/OptionArgumentParserSelector.d.ts +0 -7
- package/src/types/IDefinePropertyOptions.d.ts +0 -9
- package/src/types/IPresets.d.ts +0 -6
- package/src/types/TValidator.d.ts +0 -2
- package/src/validators/createLengthValidator.d.ts +0 -7
- package/src/validators/isInteger.d.ts +0 -1
- package/src/validators/isIntegerArray.d.ts +0 -4
- package/src/validators/isNull.d.ts +0 -1
- package/src/validators/isNumber.d.ts +0 -1
- package/src/validators/isNumberArray.d.ts +0 -4
- package/src/validators/isNumericString.d.ts +0 -1
- package/src/validators/selector/ArgumentValidatorSelector.d.ts +0 -6
- package/src/validators/selector/OptionArgumentValidatorSelector.d.ts +0 -6
- package/src/validators/selector/ValidatorSelector.d.ts +0 -17
- /package/src/core/{util/splitCombinedArgvShorts.d.ts → splitCombinedArgvShorts.d.ts} +0 -0
- /package/src/{core/CommandBuilder → util/errors}/ErrorParser.d.ts +0 -0
- /package/src/{core/CommandBuilder/features → util/node}/formatTableForTerminal.d.ts +0 -0
- /package/src/{core/util → util/object}/arrAssign.d.ts +0 -0
- /package/src/{core/util → util/object}/objAssign.d.ts +0 -0
- /package/src/{core/util → util/object}/realizeLazyProperty.d.ts +0 -0
- /package/src/{parsers → util/string-parsers}/createBooleanParser.d.ts +0 -0
- /package/src/{parsers → util/string-parsers}/createTypedListParser.d.ts +0 -0
- /package/src/{parsers → util/string-parsers}/parseBoolean.d.ts +0 -0
- /package/src/{parsers → util/string-parsers}/parseInteger.d.ts +0 -0
- /package/src/{parsers → util/string-parsers}/parseNumber.d.ts +0 -0
- /package/src/{parsers → util/string-parsers}/parseString.d.ts +0 -0
- /package/src/{types → util/types}/TStringParser.d.ts +0 -0
- /package/src/{validators → util/validation}/isArray.d.ts +0 -0
- /package/src/{validators → util/validation}/isBoolean.d.ts +0 -0
- /package/src/{validators → util/validation}/isNamedFunctionArray.d.ts +0 -0
- /package/src/{validators → util/validation}/isString.d.ts +0 -0
- /package/src/{validators → util/validation}/isStringArray.d.ts +0 -0
- /package/src/{validators → util/validation}/isStringWithNoSpacesOrDashes.d.ts +0 -0
package/index.cjs.js
CHANGED
|
@@ -3,28 +3,23 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var commander = require('commander');
|
|
6
|
-
var
|
|
6
|
+
var colors = require('ansi-colors');
|
|
7
|
+
var fs = require('fs-extra');
|
|
8
|
+
var isAsyncFunction = require('is-async-function');
|
|
7
9
|
var os = require('os');
|
|
8
10
|
var path = require('path');
|
|
9
11
|
var Table = require('cli-table');
|
|
10
|
-
var
|
|
12
|
+
var child_process = require('child_process');
|
|
11
13
|
|
|
12
14
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
13
15
|
|
|
16
|
+
var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
|
|
17
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
18
|
+
var isAsyncFunction__default = /*#__PURE__*/_interopDefaultLegacy(isAsyncFunction);
|
|
14
19
|
var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
|
|
15
20
|
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
16
21
|
var Table__default = /*#__PURE__*/_interopDefaultLegacy(Table);
|
|
17
22
|
|
|
18
|
-
class Base {
|
|
19
|
-
constructor(){
|
|
20
|
-
var _Base_nextIndex_this_constructor_name;
|
|
21
|
-
this.id = Base.nextIndex[this.constructor.name] = 1 + ((_Base_nextIndex_this_constructor_name = Base.nextIndex[this.constructor.name]) != null ? _Base_nextIndex_this_constructor_name : 0);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
(()=>{
|
|
25
|
-
Base.nextIndex = {};
|
|
26
|
-
})();
|
|
27
|
-
|
|
28
23
|
/**
|
|
29
24
|
* Creates a parser function that parses a delimited string into a list of typed values.
|
|
30
25
|
* The parser function takes a string and returns an array of typed values.
|
|
@@ -60,7 +55,10 @@ function parseString(string) {
|
|
|
60
55
|
return string;
|
|
61
56
|
}
|
|
62
57
|
|
|
63
|
-
class
|
|
58
|
+
class ParserSelector {
|
|
59
|
+
constructor(builder){
|
|
60
|
+
this.builder = builder;
|
|
61
|
+
}
|
|
64
62
|
string() {
|
|
65
63
|
return this.custom(parseString);
|
|
66
64
|
}
|
|
@@ -82,20 +80,33 @@ class AbstractStringParserSelector extends Base {
|
|
|
82
80
|
delimited(delimiter = ',', parser) {
|
|
83
81
|
return this.custom(createTypedListParser(delimiter, parser));
|
|
84
82
|
}
|
|
85
|
-
constructor(builder){
|
|
86
|
-
super();
|
|
87
|
-
this.builder = builder;
|
|
88
|
-
}
|
|
89
83
|
}
|
|
90
84
|
|
|
91
|
-
class ArgumentParserSelector extends
|
|
85
|
+
class ArgumentParserSelector extends ParserSelector {
|
|
86
|
+
constructor(builder){
|
|
87
|
+
super(builder);
|
|
88
|
+
}
|
|
92
89
|
custom(parser) {
|
|
93
90
|
this.builder.cmd.meta.argParsers[this.builder.index] = parser;
|
|
94
91
|
return this.builder;
|
|
95
92
|
}
|
|
96
93
|
}
|
|
97
94
|
|
|
98
|
-
|
|
95
|
+
const counts = new Map();
|
|
96
|
+
function countInstance(ctor) {
|
|
97
|
+
const name = ctor.name;
|
|
98
|
+
const count = counts.get(name) ?? 0;
|
|
99
|
+
counts.set(name, count + 1);
|
|
100
|
+
}
|
|
101
|
+
function printCounts() {
|
|
102
|
+
console.log(counts);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
class ArgumentReader {
|
|
106
|
+
constructor(parent){
|
|
107
|
+
this.parent = parent;
|
|
108
|
+
countInstance(ArgumentBuilder);
|
|
109
|
+
}
|
|
99
110
|
get $() {
|
|
100
111
|
return this.parent.$;
|
|
101
112
|
}
|
|
@@ -123,10 +134,49 @@ class ArgumentReader extends Base {
|
|
|
123
134
|
get optional() {
|
|
124
135
|
return !this.$.required;
|
|
125
136
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns the last element of an array.
|
|
141
|
+
* Throws an error if the array is empty.
|
|
142
|
+
* @template T The type of elements in the array.
|
|
143
|
+
* @param array The array to get the last element from.
|
|
144
|
+
* @returns The last element of the array.
|
|
145
|
+
* @throws If the array is empty.
|
|
146
|
+
* @example const numbers = [1, 2, 3, 4, 5];
|
|
147
|
+
* const lastNumber = arrLast(numbers);
|
|
148
|
+
* //=> 5
|
|
149
|
+
*/ function arrLast(array) {
|
|
150
|
+
if (!array.length) throw new Error('Cannot get last element of empty array.');
|
|
151
|
+
return array[array.length - 1];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function ensureThat(value, validator, options = {}) {
|
|
155
|
+
const result = validator(value, ...options.args ?? []);
|
|
156
|
+
if (result === true) return value;
|
|
157
|
+
const message = typeof result === 'string' ? `${result}. Got: ${value}` : `Expected '${validator.name}'. Got: ${value}`;
|
|
158
|
+
throw new (options.Err ?? Error)(message);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* This function sets the name of a function and returns the function with the new name.
|
|
163
|
+
* @template T - The type of the function.
|
|
164
|
+
* @param name The new name to be set for the function.
|
|
165
|
+
* @param fun The function whose name is to be set.
|
|
166
|
+
* @returns The function with the new name.
|
|
167
|
+
* @example ```ts
|
|
168
|
+
* const myFun = () => 'Hello World';
|
|
169
|
+
* funSetName('newFun', myFun).name;;
|
|
170
|
+
* //=> 'newFun'
|
|
171
|
+
* ```
|
|
172
|
+
*/ function funSetName(name, fun) {
|
|
173
|
+
Object.defineProperty(fun, 'name', {
|
|
174
|
+
value: name,
|
|
175
|
+
configurable: true,
|
|
176
|
+
writable: true,
|
|
177
|
+
enumerable: false
|
|
178
|
+
});
|
|
179
|
+
return fun;
|
|
130
180
|
}
|
|
131
181
|
|
|
132
182
|
/**
|
|
@@ -139,6 +189,17 @@ function isNamedFunctionArray(array) {
|
|
|
139
189
|
return Array.isArray(array) && array.every(isNamedFunction);
|
|
140
190
|
}
|
|
141
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Converts the first character of a string to uppercase.
|
|
194
|
+
* @param string The string to be converted.
|
|
195
|
+
* @example ```ts
|
|
196
|
+
* strFirstCharToUpperCase('hello');
|
|
197
|
+
* //=> 'Hello'
|
|
198
|
+
* ```
|
|
199
|
+
*/ function strFirstCharToUpperCase(string) {
|
|
200
|
+
return string.charAt(0).toUpperCase() + string.substring(1);
|
|
201
|
+
}
|
|
202
|
+
|
|
142
203
|
/**
|
|
143
204
|
* Creates a validator function that checks whether the input is an array where all elements are valid according to every validator provided.
|
|
144
205
|
*
|
|
@@ -148,30 +209,57 @@ function isNamedFunctionArray(array) {
|
|
|
148
209
|
* @throws TypeError - if no name is provided and not all validators are named functions.
|
|
149
210
|
*/ function createTypedArrayValidator(validators, name) {
|
|
150
211
|
if (!name) {
|
|
151
|
-
|
|
152
|
-
name = '
|
|
212
|
+
ensureThat(validators, isNamedFunctionArray);
|
|
213
|
+
name = 'isArrayWhereEach' + validators.map((fun)=>strFirstCharToUpperCase(fun.name)).join('And');
|
|
153
214
|
}
|
|
154
|
-
return
|
|
215
|
+
return funSetName(name, function(array) {
|
|
155
216
|
return Array.isArray(array) && array.every((value)=>validators.every((isValid)=>isValid(value)));
|
|
156
217
|
});
|
|
157
218
|
}
|
|
158
219
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Checks if the provided number is an integer.
|
|
222
|
+
* @remarks This function uses the built-in `Number.isInteger` method.
|
|
223
|
+
* @param int The number to check.
|
|
224
|
+
* @returns A boolean indicating whether the provided number is an integer.
|
|
225
|
+
* @example ```ts
|
|
226
|
+
* isInteger(5);
|
|
227
|
+
* //=> true
|
|
228
|
+
* isInteger(5.5);
|
|
229
|
+
* //=> false
|
|
230
|
+
* ```
|
|
231
|
+
*/ const isInteger = Number.isInteger;
|
|
164
232
|
|
|
165
233
|
function isString(value) {
|
|
166
234
|
return typeof value === 'string';
|
|
167
235
|
}
|
|
168
236
|
|
|
169
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Checks if the provided value is a valid number.
|
|
239
|
+
* @remarks This function checks if the provided value is a finite number and not NaN.
|
|
240
|
+
* @param number The value to check.
|
|
241
|
+
* @returns A boolean indicating whether the provided value is a valid number.
|
|
242
|
+
* @example ```ts
|
|
243
|
+
* isValidNumber(123);
|
|
244
|
+
* //=> true
|
|
245
|
+
* isValidNumber(NaN);
|
|
246
|
+
* //=> false
|
|
247
|
+
* isValidNumber(Infinity);
|
|
248
|
+
* //=> false
|
|
249
|
+
* ```
|
|
250
|
+
*/ function isValidNumber(number) {
|
|
251
|
+
return isFinite(number) && !isNaN(number);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
class ValidatorSelector {
|
|
255
|
+
constructor(builder){
|
|
256
|
+
this.builder = builder;
|
|
257
|
+
}
|
|
170
258
|
isString() {
|
|
171
259
|
return this.custom(isString);
|
|
172
260
|
}
|
|
173
261
|
isNumber() {
|
|
174
|
-
return this.custom(
|
|
262
|
+
return this.custom(isValidNumber);
|
|
175
263
|
}
|
|
176
264
|
isInteger() {
|
|
177
265
|
return this.custom(isInteger);
|
|
@@ -180,7 +268,7 @@ class AbstractValidatorSelector extends Base {
|
|
|
180
268
|
return this.arrayWhereEach(isString);
|
|
181
269
|
}
|
|
182
270
|
isNumberArray() {
|
|
183
|
-
return this.arrayWhereEach(
|
|
271
|
+
return this.arrayWhereEach(isValidNumber);
|
|
184
272
|
}
|
|
185
273
|
isIntegerArray() {
|
|
186
274
|
return this.arrayWhereEach(isInteger);
|
|
@@ -188,15 +276,14 @@ class AbstractValidatorSelector extends Base {
|
|
|
188
276
|
arrayWhereEach(...validators) {
|
|
189
277
|
return this.custom(createTypedArrayValidator(validators));
|
|
190
278
|
}
|
|
191
|
-
constructor(builder){
|
|
192
|
-
super();
|
|
193
|
-
this.builder = builder;
|
|
194
|
-
}
|
|
195
279
|
}
|
|
196
280
|
|
|
197
|
-
class ArgumentValidatorSelector extends
|
|
281
|
+
class ArgumentValidatorSelector extends ValidatorSelector {
|
|
282
|
+
constructor(builder){
|
|
283
|
+
super(builder);
|
|
284
|
+
}
|
|
198
285
|
custom(validator) {
|
|
199
|
-
|
|
286
|
+
arrLast(this.builder.cmd.meta.argValidators).push(validator);
|
|
200
287
|
return this.builder;
|
|
201
288
|
}
|
|
202
289
|
}
|
|
@@ -212,16 +299,20 @@ function realizeLazyProperty(obj, key, value) {
|
|
|
212
299
|
}
|
|
213
300
|
|
|
214
301
|
/**
|
|
215
|
-
* Wrapper around the @see Argument class
|
|
216
|
-
*/ class ArgumentBuilder
|
|
302
|
+
* Wrapper around the @see Argument class from 'commander'.
|
|
303
|
+
*/ class ArgumentBuilder {
|
|
304
|
+
constructor(cmd, name){
|
|
305
|
+
this.cmd = cmd;
|
|
306
|
+
countInstance(ArgumentBuilder);
|
|
307
|
+
this.$ = new commander.Argument(name);
|
|
308
|
+
this.index = cmd.meta.argValidators.length;
|
|
309
|
+
cmd.meta.argValidators[this.index] = [];
|
|
310
|
+
}
|
|
217
311
|
description(string) {
|
|
218
312
|
this.$.description = string;
|
|
219
313
|
return this;
|
|
220
314
|
}
|
|
221
315
|
default(value, description) {
|
|
222
|
-
if (this.$.required) {
|
|
223
|
-
throw new Error('Cannot set default value on required argument: ' + this.$.name());
|
|
224
|
-
}
|
|
225
316
|
this.$.default(value, description);
|
|
226
317
|
return this;
|
|
227
318
|
}
|
|
@@ -238,209 +329,87 @@ function realizeLazyProperty(obj, key, value) {
|
|
|
238
329
|
get get() {
|
|
239
330
|
return realizeLazyProperty(this, 'get', new ArgumentReader(this));
|
|
240
331
|
}
|
|
241
|
-
constructor(cmd, name){
|
|
242
|
-
super();
|
|
243
|
-
this.cmd = cmd;
|
|
244
|
-
this.$ = new commander.Argument(name);
|
|
245
|
-
this.index = cmd.meta.argValidators.length;
|
|
246
|
-
cmd.meta.argValidators[this.index] = [];
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function assertCommandNameNotReserved(name) {
|
|
251
|
-
if (name === 'u' || name === 'util') {
|
|
252
|
-
throw new Error(`Name '${name}' is reserved and is not available as name or alias.`);
|
|
253
|
-
}
|
|
254
332
|
}
|
|
255
333
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
334
|
+
/**
|
|
335
|
+
* Creates a function that merges arrays based on a predicate function.
|
|
336
|
+
*/ function createArrayMerger(predicate) {
|
|
337
|
+
return function arrMerge(target, ...sources) {
|
|
338
|
+
for (const src of sources){
|
|
339
|
+
for(let i = 0; i < src.length; i++){
|
|
340
|
+
if (predicate(src[i], i, src)) {
|
|
341
|
+
target[i] = src[i];
|
|
342
|
+
}
|
|
343
|
+
}
|
|
261
344
|
}
|
|
262
345
|
return target;
|
|
263
346
|
};
|
|
264
|
-
return _extends.apply(this, arguments);
|
|
265
347
|
}
|
|
266
348
|
|
|
267
|
-
|
|
268
|
-
get argParsers() {
|
|
269
|
-
return realizeLazyProperty(this, 'argParsers', []);
|
|
270
|
-
}
|
|
271
|
-
get argValidators() {
|
|
272
|
-
return realizeLazyProperty(this, 'argValidators', []);
|
|
273
|
-
}
|
|
274
|
-
get optParsers() {
|
|
275
|
-
return realizeLazyProperty(this, 'optParsers', {});
|
|
276
|
-
}
|
|
277
|
-
get optValidators() {
|
|
278
|
-
return realizeLazyProperty(this, 'optValidators', {});
|
|
279
|
-
}
|
|
280
|
-
constructor(...args){
|
|
281
|
-
super(...args);
|
|
282
|
-
this.subcommands = [];
|
|
283
|
-
this.globalOptions = [];
|
|
284
|
-
this.hiddenGlobalOptions = new Set();
|
|
285
|
-
this.isNative = false;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
349
|
+
const arrAssign = createArrayMerger((value)=>value != null);
|
|
288
350
|
|
|
289
351
|
/**
|
|
290
|
-
*
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (this._config === boolean) return this;
|
|
306
|
-
if (this.cmd.meta.isNative) throw new Error('Cannot configure config for native command.');
|
|
307
|
-
if (this._config !== boolean) {
|
|
308
|
-
this._config = boolean;
|
|
309
|
-
this.debugToggle({
|
|
310
|
-
config: boolean
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
return this;
|
|
314
|
-
}
|
|
315
|
-
presets(boolean = true) {
|
|
316
|
-
if (this.cmd.meta.isNative) {
|
|
317
|
-
throw new Error('Cannot configure presets for native command.');
|
|
318
|
-
}
|
|
319
|
-
if (this._presets !== boolean) {
|
|
320
|
-
this._presets = boolean;
|
|
321
|
-
this.debugToggle({
|
|
322
|
-
presets: boolean
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
return this;
|
|
326
|
-
}
|
|
327
|
-
autoAssignMissingOptionFlags(boolean = true) {
|
|
328
|
-
if (this._autoAssignMissingOptionFlags !== boolean) {
|
|
329
|
-
this._autoAssignMissingOptionFlags = boolean;
|
|
330
|
-
this.debugToggle({
|
|
331
|
-
autoAssignMissingOptionFlags: boolean
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
return this;
|
|
335
|
-
}
|
|
336
|
-
autoAssignSubCommandAliases(boolean = true) {
|
|
337
|
-
if (this._autoAssignSubCommandAliases !== boolean) {
|
|
338
|
-
this._autoAssignSubCommandAliases = boolean;
|
|
339
|
-
this.debugToggle({
|
|
340
|
-
autoAssignSubCommandAliases: boolean
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
return this;
|
|
344
|
-
}
|
|
345
|
-
all(boolean = true) {
|
|
346
|
-
this.utils(boolean);
|
|
347
|
-
this.config(boolean);
|
|
348
|
-
this.presets(boolean);
|
|
349
|
-
this.autoAssignMissingOptionFlags(boolean);
|
|
350
|
-
this.autoAssignSubCommandAliases(boolean);
|
|
351
|
-
return this.cmd;
|
|
352
|
-
}
|
|
353
|
-
get isUtilsEnabled() {
|
|
354
|
-
if (this.cmd.meta.isNative) return false;
|
|
355
|
-
return this._utils;
|
|
356
|
-
}
|
|
357
|
-
get isConfigEnabled() {
|
|
358
|
-
if (this.cmd.meta.isNative) return false;
|
|
359
|
-
return this._config;
|
|
360
|
-
}
|
|
361
|
-
get isPresetsEnabled() {
|
|
362
|
-
if (this.cmd.meta.isNative) return false;
|
|
363
|
-
return this._presets;
|
|
364
|
-
}
|
|
365
|
-
get isAutoAssignMissingOptionFlagsEnabled() {
|
|
366
|
-
return this._autoAssignMissingOptionFlags;
|
|
367
|
-
}
|
|
368
|
-
get isAutoAssignSubCommandAliasesEnabled() {
|
|
369
|
-
return this._autoAssignSubCommandAliases;
|
|
370
|
-
}
|
|
371
|
-
constructor(cmd){
|
|
372
|
-
var _cmd_parent, _cmd;
|
|
373
|
-
super();
|
|
374
|
-
this.cmd = cmd;
|
|
375
|
-
this._utils = false;
|
|
376
|
-
this._config = false;
|
|
377
|
-
this._presets = false;
|
|
378
|
-
this._autoAssignMissingOptionFlags = false;
|
|
379
|
-
this._autoAssignSubCommandAliases = false;
|
|
380
|
-
const parent = (_cmd = cmd) == null ? void 0 : (_cmd_parent = _cmd.parent) == null ? void 0 : _cmd_parent.features;
|
|
381
|
-
if (parent) {
|
|
382
|
-
if (!this.cmd.meta.isNative) {
|
|
383
|
-
this._utils = parent._utils;
|
|
384
|
-
this._config = parent._config;
|
|
385
|
-
this._presets = parent._presets;
|
|
386
|
-
}
|
|
387
|
-
this._autoAssignMissingOptionFlags = parent._autoAssignMissingOptionFlags;
|
|
388
|
-
this._autoAssignSubCommandAliases = parent._autoAssignSubCommandAliases;
|
|
352
|
+
* Checks if at least one element in the array satisfies the provided predicate.
|
|
353
|
+
* @param predicate The predicate function to apply to each element.
|
|
354
|
+
* @template T The type of elements in the input array.
|
|
355
|
+
* @returns Returns `true` if at least one element in the array passes the test implemented by the provided function, otherwise `false`.
|
|
356
|
+
* @param input The array to check.
|
|
357
|
+
* @example ```ts
|
|
358
|
+
* const numbers = [1, 2, 3, 4, 5];
|
|
359
|
+
* const isEven = (num) => num % 2 === 0;
|
|
360
|
+
* arrSome(numbers, isEven);
|
|
361
|
+
* //=> true
|
|
362
|
+
* ```
|
|
363
|
+
*/ function arrSome(input, predicate) {
|
|
364
|
+
for(let i = 0, len = input.length; i < len; i++){
|
|
365
|
+
if (predicate(input[i], i, input) === true) {
|
|
366
|
+
return true;
|
|
389
367
|
}
|
|
390
368
|
}
|
|
369
|
+
return false;
|
|
391
370
|
}
|
|
392
371
|
|
|
393
372
|
/**
|
|
394
|
-
*
|
|
395
|
-
*/ function
|
|
396
|
-
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
node = node.parent;
|
|
402
|
-
}
|
|
373
|
+
* Checks if the provided value is a plain object, i.e. an object created by the native base `Object` constructor.
|
|
374
|
+
*/ function isPlainObject(value) {
|
|
375
|
+
if (Object.prototype.toString.call(value) !== '[object Object]') return false;
|
|
376
|
+
if (!value?.constructor) return true;
|
|
377
|
+
if (Object.prototype.toString.call(value.constructor.prototype) !== '[object Object]') return false;
|
|
378
|
+
if (!Object.prototype.hasOwnProperty.call(value.constructor.prototype, 'isPrototypeOf')) return false;
|
|
379
|
+
return true;
|
|
403
380
|
}
|
|
404
381
|
|
|
405
382
|
/**
|
|
406
|
-
*
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
return arg;
|
|
417
|
-
}
|
|
418
|
-
return Array.from(arg.replace('-', '')).map((s)=>'-' + s);
|
|
419
|
-
}).flat();
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
function getARGV(argv) {
|
|
423
|
-
if (argv) ARGV = splitCombinedArgvShorts(argv);
|
|
424
|
-
return ARGV.slice();
|
|
383
|
+
* Checks if the provided value is a primitive type (null, undefined, bigint, boolean, number, string or symbol).
|
|
384
|
+
* @param value The value to check.
|
|
385
|
+
* @returns A boolean indicating whether the provided value is a primitive type.
|
|
386
|
+
* @example
|
|
387
|
+
* isPrimitive(123);
|
|
388
|
+
* //=> true
|
|
389
|
+
* isPrimitive({});
|
|
390
|
+
* //=> false
|
|
391
|
+
*/ function isPrimitive(value) {
|
|
392
|
+
return typeof value !== 'object' && typeof value !== 'function' || value === null;
|
|
425
393
|
}
|
|
426
|
-
let ARGV = splitCombinedArgvShorts(process.argv.slice(2));
|
|
427
394
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
return result;
|
|
395
|
+
/**
|
|
396
|
+
* Escapes special characters in a string to be used in a regular expression.
|
|
397
|
+
* @param str The input string to escape.
|
|
398
|
+
* @returns The escaped string.
|
|
399
|
+
* @example ```ts
|
|
400
|
+
* const input = 'Hello, world!';
|
|
401
|
+
* regexEscapeString(input);;
|
|
402
|
+
* //=> 'Hello, world!'
|
|
403
|
+
* ```
|
|
404
|
+
*/ function regexEscapeString(str) {
|
|
405
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
|
|
406
|
+
;
|
|
441
407
|
}
|
|
442
408
|
|
|
443
409
|
class ErrorParser {
|
|
410
|
+
constructor(error){
|
|
411
|
+
this.error = error instanceof Error ? error : new Error(String(error));
|
|
412
|
+
}
|
|
444
413
|
get name() {
|
|
445
414
|
return this.error.name;
|
|
446
415
|
}
|
|
@@ -465,35 +434,32 @@ class ErrorParser {
|
|
|
465
434
|
toJSON() {
|
|
466
435
|
return this.toObject();
|
|
467
436
|
}
|
|
468
|
-
constructor(error){
|
|
469
|
-
this.error = error instanceof Error ? error : new Error(String(error));
|
|
470
|
-
}
|
|
471
437
|
}
|
|
472
438
|
function errPrettyStack(error, parsedStackFrames) {
|
|
473
|
-
const frames = parsedStackFrames
|
|
439
|
+
const frames = parsedStackFrames ?? errParseStack(error.stack || '');
|
|
474
440
|
// width of the first column = the longest frame.cell string
|
|
475
441
|
const offset = 2 + frames.reduce((acc, frame)=>Math.max(acc, frame[0].length), 0);
|
|
476
442
|
// type and message
|
|
477
443
|
const result = [
|
|
478
|
-
|
|
444
|
+
colors__default["default"].bold(colors__default["default"].red(error.name)) + ': ' + ' '.repeat(Math.max(0, offset - error.name.length)) + colors__default["default"].red(error.message)
|
|
479
445
|
];
|
|
480
446
|
// stack trace
|
|
481
|
-
result.push(
|
|
447
|
+
result.push(colors__default["default"].yellow('stack') + ':');
|
|
482
448
|
result.push(frames.map((frame)=>{
|
|
483
449
|
const [call, file] = frame;
|
|
484
450
|
let s = ' ';
|
|
485
451
|
let fp;
|
|
486
452
|
if (file.startsWith('node:')) {
|
|
487
|
-
s +=
|
|
488
|
-
fp =
|
|
453
|
+
s += colors__default["default"].gray(call);
|
|
454
|
+
fp = colors__default["default"].gray(file);
|
|
489
455
|
} else if (file.includes('node_modules')) {
|
|
490
456
|
s += call;
|
|
491
457
|
const base = path__default["default"].basename(file.split(':')[0]);
|
|
492
|
-
fp = file.replace(base,
|
|
458
|
+
fp = file.replace(base, colors__default["default"].yellow(base));
|
|
493
459
|
} else {
|
|
494
460
|
s += call;
|
|
495
461
|
const base = path__default["default"].basename(file.split(':')[0]);
|
|
496
|
-
fp = file.replace(base,
|
|
462
|
+
fp = file.replace(base, colors__default["default"].red(base));
|
|
497
463
|
}
|
|
498
464
|
s += ' '.repeat(offset - call.length);
|
|
499
465
|
s += fp;
|
|
@@ -510,22 +476,21 @@ function errPrettyStack(error, parsedStackFrames) {
|
|
|
510
476
|
for (const k of keys){
|
|
511
477
|
if (typeof k === 'symbol') continue;
|
|
512
478
|
const key = k;
|
|
513
|
-
let s =
|
|
514
|
-
if (
|
|
479
|
+
let s = colors__default["default"].yellow(key.toString()) + ': ';
|
|
480
|
+
if (isPlainObject(error[key])) {
|
|
515
481
|
const json = JSON.stringify(error[key], null, 2);
|
|
516
482
|
if (json.length < 350) {
|
|
517
483
|
s += JSON.stringify(error[key], null, 2).split('\n').map((line)=>{
|
|
518
484
|
const arr = line.split('": ');
|
|
519
|
-
arr[0] =
|
|
485
|
+
arr[0] = colors__default["default"].gray(arr[0].replace('"', ''));
|
|
520
486
|
return arr.join(': ');
|
|
521
487
|
}).join('\n');
|
|
522
488
|
} else {
|
|
523
489
|
s += JSON.stringify(error[key]);
|
|
524
490
|
}
|
|
525
|
-
} else if (
|
|
491
|
+
} else if (isPrimitive(error[key])) {
|
|
526
492
|
s += String(error[key]);
|
|
527
493
|
} else if (error[key] != null && typeof error[key] === 'object') {
|
|
528
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
529
494
|
s += error[key].toString();
|
|
530
495
|
} else {
|
|
531
496
|
s += JSON.stringify(error[key]);
|
|
@@ -537,7 +502,7 @@ function errPrettyStack(error, parsedStackFrames) {
|
|
|
537
502
|
function errParseStack(stack) {
|
|
538
503
|
if (!stack) return [];
|
|
539
504
|
const nodeRe = /^\s*at (?:((?:\[object object\])?[^\\/]+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;
|
|
540
|
-
const recwd = new RegExp('^' +
|
|
505
|
+
const recwd = new RegExp('^' + regexEscapeString(process.cwd() + path__default["default"].sep), 'i');
|
|
541
506
|
const frames = [];
|
|
542
507
|
for (const line of stack.split('\n')){
|
|
543
508
|
const parts = nodeRe.exec(line);
|
|
@@ -582,19 +547,18 @@ function errToObject(error) {
|
|
|
582
547
|
// console.log('----------------------')
|
|
583
548
|
// }
|
|
584
549
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
function
|
|
594
|
-
return
|
|
550
|
+
/**
|
|
551
|
+
* Checks if the given value is a function.
|
|
552
|
+
*
|
|
553
|
+
* @example ```ts
|
|
554
|
+
* isFunction(class {}); //=> true
|
|
555
|
+
* isFunction(function () {}); //=> true
|
|
556
|
+
* isFunction(() => {}); //=> true
|
|
557
|
+
* ```
|
|
558
|
+
*/ function isFunction(value) {
|
|
559
|
+
return typeof value === 'function' && value !== Function.prototype;
|
|
595
560
|
}
|
|
596
561
|
|
|
597
|
-
var _defaultDescriptor = /*#__PURE__*/ _class_private_field_loose_key("_defaultDescriptor"), _noop = /*#__PURE__*/ _class_private_field_loose_key("_noop"), _memoized = /*#__PURE__*/ _class_private_field_loose_key("_memoized"), _obj = /*#__PURE__*/ _class_private_field_loose_key("_obj"), _key = /*#__PURE__*/ _class_private_field_loose_key("_key"), _original = /*#__PURE__*/ _class_private_field_loose_key("_original"), _hasOwn = /*#__PURE__*/ _class_private_field_loose_key("_hasOwn"), _originalDescriptor = /*#__PURE__*/ _class_private_field_loose_key("_originalDescriptor"), _noopDescriptor = /*#__PURE__*/ _class_private_field_loose_key("_noopDescriptor"), _isEnabled = /*#__PURE__*/ _class_private_field_loose_key("_isEnabled");
|
|
598
562
|
/**
|
|
599
563
|
* A class that creates an object with methods for disabling/enabling a given method on a given object.
|
|
600
564
|
*
|
|
@@ -610,1035 +574,710 @@ var _defaultDescriptor = /*#__PURE__*/ _class_private_field_loose_key("_defaultD
|
|
|
610
574
|
* console.log('This will print')
|
|
611
575
|
*
|
|
612
576
|
* assert(md.original === process.stdout.write)
|
|
613
|
-
*/ class MethodDisabler
|
|
577
|
+
*/ class MethodDisabler {
|
|
578
|
+
static #defaultDescriptor(value) {
|
|
579
|
+
return {
|
|
580
|
+
value,
|
|
581
|
+
writable: true,
|
|
582
|
+
enumerable: true,
|
|
583
|
+
configurable: true
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
static #noop = (...args)=>void 0;
|
|
587
|
+
static #memoized = new WeakMap();
|
|
588
|
+
#obj;
|
|
589
|
+
#key;
|
|
590
|
+
#original;
|
|
591
|
+
#hasOwn;
|
|
592
|
+
#originalDescriptor;
|
|
593
|
+
#noopDescriptor;
|
|
594
|
+
#isEnabled;
|
|
595
|
+
/**
|
|
596
|
+
* @param obj - The object on which the method is defined.
|
|
597
|
+
* @param key - The property name of the method.
|
|
598
|
+
*/ constructor(obj, key){
|
|
599
|
+
this.#isEnabled = true;
|
|
600
|
+
ensureThat(obj[key], isFunction);
|
|
601
|
+
this.#obj = obj;
|
|
602
|
+
this.#key = key;
|
|
603
|
+
this.#original = obj[key];
|
|
604
|
+
this.#hasOwn = Object.hasOwn(obj, key);
|
|
605
|
+
this.#originalDescriptor = this.#hasOwn ? Object.getOwnPropertyDescriptor(obj, key) : MethodDisabler.#defaultDescriptor(this.#original);
|
|
606
|
+
this.#noopDescriptor = Object.assign({}, this.#originalDescriptor, {
|
|
607
|
+
value: MethodDisabler.#noop
|
|
608
|
+
});
|
|
609
|
+
// return stored if memoized
|
|
610
|
+
if (MethodDisabler.#memoized.get(obj)?.has(key)) {
|
|
611
|
+
return MethodDisabler.#memoized.get(obj)?.get(key);
|
|
612
|
+
}
|
|
613
|
+
//memoize
|
|
614
|
+
if (!MethodDisabler.#memoized.has(obj)) MethodDisabler.#memoized.set(obj, new Map());
|
|
615
|
+
const methods = MethodDisabler.#memoized.get(obj);
|
|
616
|
+
methods.set(key, this);
|
|
617
|
+
}
|
|
614
618
|
/**
|
|
615
619
|
* Disable the method.
|
|
616
620
|
*/ disable() {
|
|
617
621
|
if (!this.isEnabled) return;
|
|
618
|
-
Object.defineProperty(
|
|
619
|
-
|
|
622
|
+
Object.defineProperty(this.#obj, this.#key, this.#noopDescriptor);
|
|
623
|
+
this.#isEnabled = false;
|
|
620
624
|
}
|
|
621
625
|
/**
|
|
622
626
|
* Enable the method.
|
|
623
627
|
*/ enable() {
|
|
624
628
|
if (this.isEnabled) return;
|
|
625
|
-
if (
|
|
626
|
-
else delete
|
|
627
|
-
|
|
629
|
+
if (this.#hasOwn) Object.defineProperty(this.#obj, this.#key, this.#originalDescriptor);
|
|
630
|
+
else delete this.#obj[this.#key];
|
|
631
|
+
this.#isEnabled = true;
|
|
628
632
|
}
|
|
629
633
|
/**
|
|
630
634
|
* The original method before it was disabled.
|
|
631
635
|
*/ get original() {
|
|
632
|
-
return
|
|
636
|
+
return this.#original;
|
|
633
637
|
}
|
|
634
638
|
/**
|
|
635
639
|
* Whether the method is currently enabled.
|
|
636
640
|
*/ get isEnabled() {
|
|
637
|
-
return
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* @param obj - The object on which the method is defined.
|
|
641
|
-
* @param key - The property name of the method.
|
|
642
|
-
*/ constructor(obj, key){
|
|
643
|
-
var _class_private_field_loose_base__memoized_get;
|
|
644
|
-
super();
|
|
645
|
-
Object.defineProperty(this, _obj, {
|
|
646
|
-
writable: true,
|
|
647
|
-
value: void 0
|
|
648
|
-
});
|
|
649
|
-
Object.defineProperty(this, _key, {
|
|
650
|
-
writable: true,
|
|
651
|
-
value: void 0
|
|
652
|
-
});
|
|
653
|
-
Object.defineProperty(this, _original, {
|
|
654
|
-
writable: true,
|
|
655
|
-
value: void 0
|
|
656
|
-
});
|
|
657
|
-
Object.defineProperty(this, _hasOwn, {
|
|
658
|
-
writable: true,
|
|
659
|
-
value: void 0
|
|
660
|
-
});
|
|
661
|
-
Object.defineProperty(this, _originalDescriptor, {
|
|
662
|
-
writable: true,
|
|
663
|
-
value: void 0
|
|
664
|
-
});
|
|
665
|
-
Object.defineProperty(this, _noopDescriptor, {
|
|
666
|
-
writable: true,
|
|
667
|
-
value: void 0
|
|
668
|
-
});
|
|
669
|
-
Object.defineProperty(this, _isEnabled, {
|
|
670
|
-
writable: true,
|
|
671
|
-
value: void 0
|
|
672
|
-
});
|
|
673
|
-
_class_private_field_loose_base(this, _isEnabled)[_isEnabled] = true;
|
|
674
|
-
util.assertThat(obj[key], util.isFunction);
|
|
675
|
-
_class_private_field_loose_base(this, _obj)[_obj] = obj;
|
|
676
|
-
_class_private_field_loose_base(this, _key)[_key] = key;
|
|
677
|
-
_class_private_field_loose_base(this, _original)[_original] = obj[key];
|
|
678
|
-
_class_private_field_loose_base(this, _hasOwn)[_hasOwn] = Object.hasOwn(obj, key);
|
|
679
|
-
_class_private_field_loose_base(this, _originalDescriptor)[_originalDescriptor] = _class_private_field_loose_base(this, _hasOwn)[_hasOwn] ? Object.getOwnPropertyDescriptor(obj, key) : _class_private_field_loose_base(MethodDisabler, _defaultDescriptor)[_defaultDescriptor](_class_private_field_loose_base(this, _original)[_original]);
|
|
680
|
-
_class_private_field_loose_base(this, _noopDescriptor)[_noopDescriptor] = Object.assign({}, _class_private_field_loose_base(this, _originalDescriptor)[_originalDescriptor], {
|
|
681
|
-
value: _class_private_field_loose_base(MethodDisabler, _noop)[_noop]
|
|
682
|
-
});
|
|
683
|
-
// return stored if memoized
|
|
684
|
-
if ((_class_private_field_loose_base__memoized_get = _class_private_field_loose_base(MethodDisabler, _memoized)[_memoized].get(obj)) == null ? void 0 : _class_private_field_loose_base__memoized_get.has(key)) {
|
|
685
|
-
var _class_private_field_loose_base__memoized_get1;
|
|
686
|
-
return (_class_private_field_loose_base__memoized_get1 = _class_private_field_loose_base(MethodDisabler, _memoized)[_memoized].get(obj)) == null ? void 0 : _class_private_field_loose_base__memoized_get1.get(key);
|
|
687
|
-
}
|
|
688
|
-
//memoize
|
|
689
|
-
if (!_class_private_field_loose_base(MethodDisabler, _memoized)[_memoized].has(obj)) _class_private_field_loose_base(MethodDisabler, _memoized)[_memoized].set(obj, new Map());
|
|
690
|
-
const methods = _class_private_field_loose_base(MethodDisabler, _memoized)[_memoized].get(obj);
|
|
691
|
-
methods.set(key, this);
|
|
641
|
+
return this.#isEnabled;
|
|
692
642
|
}
|
|
693
643
|
}
|
|
694
|
-
Object.defineProperty(MethodDisabler, _defaultDescriptor, {
|
|
695
|
-
value: defaultDescriptor
|
|
696
|
-
});
|
|
697
|
-
Object.defineProperty(MethodDisabler, _noop, {
|
|
698
|
-
writable: true,
|
|
699
|
-
value: (...args)=>void 0
|
|
700
|
-
});
|
|
701
|
-
Object.defineProperty(MethodDisabler, _memoized, {
|
|
702
|
-
writable: true,
|
|
703
|
-
value: new WeakMap()
|
|
704
|
-
});
|
|
705
|
-
function defaultDescriptor(value) {
|
|
706
|
-
return {
|
|
707
|
-
value,
|
|
708
|
-
writable: true,
|
|
709
|
-
enumerable: true,
|
|
710
|
-
configurable: true
|
|
711
|
-
};
|
|
712
|
-
}
|
|
713
644
|
|
|
714
|
-
const stdout = new MethodDisabler(process.stdout, 'write');
|
|
715
|
-
const stderr = new MethodDisabler(process.stderr, 'write');
|
|
716
|
-
const debug = new MethodDisabler(console, 'debug');
|
|
717
|
-
debug.disable();
|
|
718
645
|
/**
|
|
719
|
-
*
|
|
646
|
+
* The OutputManager class manages the output of debug messages to the console.
|
|
720
647
|
*/ class OutputManager {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
648
|
+
/**
|
|
649
|
+
* Returns the singleton instance of the OutputManager class.
|
|
650
|
+
* If the instance does not exist, it creates a new one.
|
|
651
|
+
*/ static getInstance() {
|
|
652
|
+
if (!this.instance) this.instance = new OutputManager();
|
|
725
653
|
return this.instance;
|
|
726
654
|
}
|
|
727
|
-
|
|
728
|
-
|
|
655
|
+
/**
|
|
656
|
+
* Constructs a new instance of the OutputManager class.
|
|
657
|
+
* console.debug is disabled by default.
|
|
658
|
+
*/ constructor(){
|
|
659
|
+
/**
|
|
660
|
+
* Ansi-colors object
|
|
661
|
+
*/ this.colors = colors__default["default"];
|
|
662
|
+
/**
|
|
663
|
+
* A MethodDisabler instance for disabling the write method of the process.stdout object.
|
|
664
|
+
*/ this.stdout = new MethodDisabler(process.stdout, 'write');
|
|
665
|
+
/**
|
|
666
|
+
* A MethodDisabler instance for disabling the write method of the process.stderr object.
|
|
667
|
+
*/ this.stderr = new MethodDisabler(process.stderr, 'write');
|
|
668
|
+
/**
|
|
669
|
+
* A MethodDisabler instance for disabling the debug method of the console object.
|
|
670
|
+
*/ this.debug = new MethodDisabler(console, 'debug');
|
|
671
|
+
/**
|
|
672
|
+
* An array that holds queued debug messages.
|
|
673
|
+
*/ this.debugMsgQueue = [];
|
|
674
|
+
countInstance(OutputManager);
|
|
675
|
+
this.debug.disable();
|
|
676
|
+
colors__default["default"].enabled = (()=>{
|
|
677
|
+
const { FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env;
|
|
678
|
+
return !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== 'dumb' && (FORCE_COLOR != null && FORCE_COLOR !== '0' || process.stdout && process.stdout.isTTY);
|
|
679
|
+
})();
|
|
680
|
+
}
|
|
681
|
+
get queueSize() {
|
|
682
|
+
return this.debugMsgQueue.length;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Resets the OutputManager to its default state.
|
|
686
|
+
* - Enables colors.
|
|
687
|
+
* - Enables the write method of the process.stdout object.
|
|
688
|
+
* - Enables the write method of the process.stderr object.
|
|
689
|
+
* - Disables the debug method of the console object.
|
|
690
|
+
* @returns The OutputManager instance.
|
|
691
|
+
*/ reset() {
|
|
692
|
+
this.colors.enabled = true;
|
|
729
693
|
this.stdout.enable();
|
|
730
694
|
this.stderr.enable();
|
|
731
695
|
this.debug.disable();
|
|
732
696
|
return this;
|
|
733
697
|
}
|
|
734
|
-
|
|
698
|
+
/**
|
|
699
|
+
* Outputs a debug message to the console.
|
|
700
|
+
* If the debug method is enabled, the message is immediately logged to the console.
|
|
701
|
+
* Otherwise, the message is added to the debug message queue.
|
|
702
|
+
* @param fn - A function that returns the debug message.
|
|
703
|
+
*/ outputDebug(fn) {
|
|
735
704
|
if (this.debug.isEnabled) console.debug(fn());
|
|
736
|
-
else this.
|
|
705
|
+
else this.debugMsgQueue.push(fn);
|
|
737
706
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
this.colors = util.colors;
|
|
744
|
-
this.stdout = stdout;
|
|
745
|
-
this.stderr = stderr;
|
|
746
|
-
this.debug = debug;
|
|
747
|
-
this.debugMsgs = [];
|
|
707
|
+
/**
|
|
708
|
+
* Drains the debug message queue by logging all the messages to the console.
|
|
709
|
+
*/ drainDebugMessageQueue() {
|
|
710
|
+
this.debugMsgQueue.forEach((fn)=>console.debug(fn()));
|
|
711
|
+
this.debugMsgQueue.splice(0, this.debugMsgQueue.length);
|
|
748
712
|
}
|
|
749
713
|
}
|
|
750
714
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if (opts['disableStdout']) om.stdout.disable();
|
|
766
|
-
if (opts['debug']) {
|
|
767
|
-
om.debug.enable();
|
|
768
|
-
om.outputDebugMessages();
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
function debugLogArgsOpts(cb, args, opts, presetArgs, presetOpts, presetOrder) {
|
|
773
|
-
if (opts['debug']) {
|
|
774
|
-
cb.outputDebugInfo('action', ()=>{
|
|
775
|
-
return _extends({}, cb.features.isPresetsEnabled ? {
|
|
776
|
-
presetOrder,
|
|
777
|
-
presetArgs,
|
|
778
|
-
presetOpts
|
|
779
|
-
} : {}, {
|
|
780
|
-
args,
|
|
781
|
-
opts,
|
|
782
|
-
command: [
|
|
783
|
-
cb.root.name,
|
|
784
|
-
...getARGV()
|
|
785
|
-
].join(' ')
|
|
786
|
-
});
|
|
787
|
-
});
|
|
715
|
+
class CommandBuilderMetaData {
|
|
716
|
+
constructor(){
|
|
717
|
+
this.subcommands = [];
|
|
718
|
+
this.globalOptions = [];
|
|
719
|
+
this.hiddenGlobalOptions = new Set();
|
|
720
|
+
this.presetOptionKeys = [];
|
|
721
|
+
this.argParsers = [];
|
|
722
|
+
this.argValidators = [];
|
|
723
|
+
this.optParsers = {};
|
|
724
|
+
this.optValidators = {};
|
|
725
|
+
this.rawArgs = [];
|
|
726
|
+
this.isNative = false;
|
|
727
|
+
this.isInitialized = false;
|
|
728
|
+
countInstance(CommandBuilderMetaData);
|
|
788
729
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
[],
|
|
794
|
-
[],
|
|
795
|
-
[]
|
|
796
|
-
];
|
|
797
|
-
const presets = cmd.db.presets.getAll();
|
|
798
|
-
const opts = cmd.$.optsWithGlobals();
|
|
799
|
-
const selectedPresets = Object.keys(presets).filter((name)=>opts[name] === true);
|
|
800
|
-
const order = new Set();
|
|
801
|
-
for (const name of [
|
|
802
|
-
'defaults',
|
|
803
|
-
...selectedPresets
|
|
804
|
-
]){
|
|
805
|
-
for (const n of presets[name].presets.concat(name)){
|
|
806
|
-
if (order.has(n)) order.delete(n);
|
|
807
|
-
order.add(n);
|
|
808
|
-
}
|
|
730
|
+
get actionHandler() {
|
|
731
|
+
return async function defaultActionHandler() {
|
|
732
|
+
this.outputHelp();
|
|
733
|
+
};
|
|
809
734
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
presetOrder
|
|
819
|
-
];
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
function createArrayMerger(predicate) {
|
|
823
|
-
return function arrMerge(target, ...sources) {
|
|
824
|
-
for (const src of sources){
|
|
825
|
-
for(let i = 0; i < src.length; i++){
|
|
826
|
-
if (predicate(src[i], i, src)) {
|
|
827
|
-
target[i] = src[i];
|
|
828
|
-
}
|
|
735
|
+
get errorHandler() {
|
|
736
|
+
return function defaultErrorHandler(error) {
|
|
737
|
+
const parsed = new ErrorParser(error);
|
|
738
|
+
if (OutputManager.getInstance().debug.isEnabled) {
|
|
739
|
+
console.error(parsed.prettyStack());
|
|
740
|
+
this.outputError(parsed.summary());
|
|
741
|
+
} else {
|
|
742
|
+
this.outputError(parsed.summary());
|
|
829
743
|
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
get hasCustomActionHandler() {
|
|
747
|
+
return Object.hasOwn(this, 'actionHandler');
|
|
748
|
+
}
|
|
749
|
+
get hasCustomErrorHandler() {
|
|
750
|
+
return Object.hasOwn(this, 'errorHandler');
|
|
751
|
+
}
|
|
833
752
|
}
|
|
834
753
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
*/ function assertValidArguments(cmd, parsedArgs) {
|
|
840
|
-
const last = cmd.arguments.length - 1;
|
|
841
|
-
parsedArgs.forEach((arg, i)=>{
|
|
842
|
-
if (arg == null) return;
|
|
843
|
-
const index = i > last ? last : i;
|
|
844
|
-
const validators = cmd.meta.argValidators[index];
|
|
845
|
-
if (!validators) return;
|
|
846
|
-
for (const isValid of validators){
|
|
847
|
-
util.assertThat(arg, isValid);
|
|
754
|
+
function splitCombinedArgvShorts(argv) {
|
|
755
|
+
return argv.map((arg)=>{
|
|
756
|
+
if (arg.length < 3 || !arg.startsWith('-') || arg.startsWith('--') || arg.includes('=')) {
|
|
757
|
+
return arg;
|
|
848
758
|
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
/**
|
|
854
|
-
* Returns whether a command's last argument is variadic.
|
|
855
|
-
*/ function hasVariadicArguments(cmd) {
|
|
856
|
-
if (!cmd.arguments.length) return false;
|
|
857
|
-
return util.arrLast(cmd.arguments).variadic;
|
|
759
|
+
return Array.from(arg.replace('-', '')).map((s)=>'-' + s);
|
|
760
|
+
}).flat();
|
|
858
761
|
}
|
|
859
762
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
763
|
+
const commanderBackRefs = new WeakMap();
|
|
764
|
+
const oldParse = commander.Command.prototype.parse;
|
|
765
|
+
commander.Command.prototype.parse = function parse(argv, options) {
|
|
766
|
+
if (argv) {
|
|
767
|
+
argv = splitCombinedArgvShorts(argv.slice());
|
|
768
|
+
this.builder.meta.rawArgs = argv.slice(options?.from === 'user' ? 0 : 2);
|
|
769
|
+
} else {
|
|
770
|
+
this.builder.meta.rawArgs = process.argv.slice(2);
|
|
771
|
+
}
|
|
772
|
+
return oldParse.call(this, argv, options);
|
|
773
|
+
};
|
|
774
|
+
const oldParseAsync = commander.Command.prototype.parseAsync;
|
|
775
|
+
commander.Command.prototype.parseAsync = async function(argv, options) {
|
|
776
|
+
if (argv) {
|
|
777
|
+
argv = splitCombinedArgvShorts(argv.slice());
|
|
778
|
+
this.builder.meta.rawArgs = argv.slice(options?.from === 'user' ? 0 : 2);
|
|
779
|
+
} else {
|
|
780
|
+
this.builder.meta.rawArgs = process.argv.slice(2);
|
|
864
781
|
}
|
|
865
|
-
return
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
const $ = cmd.$;
|
|
875
|
-
const last = $.registeredArguments.length - 1;
|
|
876
|
-
return args.map((arg, i)=>{
|
|
877
|
-
if (!arg) return arg;
|
|
878
|
-
const parse = cmd.meta.argParsers[i > last ? last : i];
|
|
879
|
-
return parse ? parse(arg) : arg;
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
function parsedValidArgsWithPresets(cmd, presetArgs) {
|
|
884
|
-
const result = arrAssign([], ...presetArgs, parseArguments(cmd, cmd.$.args));
|
|
885
|
-
combineVariadicArgs(cmd, result);
|
|
886
|
-
assertValidArguments(cmd, result);
|
|
887
|
-
return padArgsWithUndefinedUntilExpectedLength(cmd, result);
|
|
888
|
-
}
|
|
782
|
+
return await oldParseAsync.call(this, argv, options);
|
|
783
|
+
};
|
|
784
|
+
Object.defineProperty(commander.Command.prototype, 'builder', {
|
|
785
|
+
get () {
|
|
786
|
+
const ins = commanderBackRefs.get(this);
|
|
787
|
+
if (!ins) throw new Error(`CommandBuilder not found for command ${this.name()}`);
|
|
788
|
+
return ins;
|
|
789
|
+
}
|
|
790
|
+
});
|
|
889
791
|
|
|
890
792
|
/**
|
|
891
|
-
*
|
|
892
|
-
*/
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
793
|
+
* Represents a selector for enabling or disabling command features.
|
|
794
|
+
*/ class CommandFeatureSelector {
|
|
795
|
+
/**
|
|
796
|
+
* Creates a new instance of the CommandFeatureSelector class.
|
|
797
|
+
* @param cmd - The command builder instance.
|
|
798
|
+
*/ constructor(cmd){
|
|
799
|
+
this.cmd = cmd;
|
|
800
|
+
this./**
|
|
801
|
+
* Indicates whether the app data feature is enabled.
|
|
802
|
+
*/ isAppDataEnabled = false;
|
|
803
|
+
this./**
|
|
804
|
+
* Indicates whether the config feature is enabled.
|
|
805
|
+
*/ isConfigEnabled = false;
|
|
806
|
+
this./**
|
|
807
|
+
* Indicates whether the presets feature is enabled.
|
|
808
|
+
*/ isPresetsEnabled = false;
|
|
809
|
+
this./**
|
|
810
|
+
* Indicates whether the auto assign missing option flags feature is enabled.
|
|
811
|
+
*/ isAutoAssignMissingOptionFlagsEnabled = false;
|
|
812
|
+
this./**
|
|
813
|
+
* Indicates whether the auto assign sub command aliases feature is enabled.
|
|
814
|
+
*/ isAutoAssignSubCommandAliasesEnabled = false;
|
|
815
|
+
countInstance(CommandFeatureSelector);
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Inherits the feature settings from a parent CommandFeatureSelector instance.
|
|
819
|
+
* @param parentFeatures - The parent CommandFeatureSelector instance to inherit from.
|
|
820
|
+
*/ inheritFrom(parentFeatures) {
|
|
821
|
+
if (!parentFeatures) return;
|
|
822
|
+
if (this.cmd.meta.isNative) this.isAutoAssignMissingOptionFlagsEnabled = true;
|
|
823
|
+
else this.isAutoAssignMissingOptionFlagsEnabled = parentFeatures.isAutoAssignMissingOptionFlagsEnabled;
|
|
824
|
+
this.isAutoAssignSubCommandAliasesEnabled = parentFeatures.isAutoAssignSubCommandAliasesEnabled;
|
|
825
|
+
this.isPresetsEnabled = parentFeatures.isPresetsEnabled;
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Enables or disables the app data feature.
|
|
829
|
+
* @param boolean - Indicates whether the app data feature should be enabled or disabled.
|
|
830
|
+
* @returns The current CommandFeatureSelector instance.
|
|
831
|
+
* @throws Error if the command is native and the app data feature is being configured.
|
|
832
|
+
*/ appData(boolean = true) {
|
|
833
|
+
return this.setProperty(boolean, 'isAppDataEnabled', 'appData', true);
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Enables or disables the config feature.
|
|
837
|
+
* @param boolean - Indicates whether the config feature should be enabled or disabled.
|
|
838
|
+
* @returns The current CommandFeatureSelector instance.
|
|
839
|
+
* @throws Error if the command is native and the config feature is being configured.
|
|
840
|
+
*/ config(boolean = true) {
|
|
841
|
+
return this.setProperty(boolean, 'isConfigEnabled', 'config', true);
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Enables or disables the presets feature.
|
|
845
|
+
* @param boolean - Indicates whether the presets feature should be enabled or disabled.
|
|
846
|
+
* @returns The current CommandFeatureSelector instance.
|
|
847
|
+
* @throws Error if the command is native and the presets feature is being configured.
|
|
848
|
+
*/ presets(boolean = true) {
|
|
849
|
+
return this.setProperty(boolean, 'isPresetsEnabled', 'presets', true);
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Enables or disables the auto assign missing option flags feature.
|
|
853
|
+
* @param boolean - Indicates whether the auto assign missing option flags feature should be enabled or disabled.
|
|
854
|
+
* @returns The current CommandFeatureSelector instance.
|
|
855
|
+
*/ autoAssignMissingOptionFlags(boolean = true) {
|
|
856
|
+
return this.setProperty(boolean, 'isAutoAssignMissingOptionFlagsEnabled', 'autoAssignMissingOptionFlags', false);
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Enables or disables the auto assign sub command aliases feature.
|
|
860
|
+
* @param boolean - Indicates whether the auto assign sub command aliases feature should be enabled or disabled.
|
|
861
|
+
* @returns The current CommandFeatureSelector instance.
|
|
862
|
+
*/ autoAssignSubCommandAliases(boolean = true) {
|
|
863
|
+
return this.setProperty(boolean, 'isAutoAssignSubCommandAliasesEnabled', 'autoAssignSubCommandAliases', false);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Helper method to enable or disable a feature.
|
|
867
|
+
* @param boolean - Indicates whether the auto assign sub command aliases feature should be enabled or disabled.
|
|
868
|
+
* @param prop - The property name to set.
|
|
869
|
+
* @param method - The method name to output in the debug message.
|
|
870
|
+
* @param throwIfNative - Indicates whether an error should be thrown if the command is native.
|
|
871
|
+
* @returns The current CommandFeatureSelector instance.
|
|
872
|
+
*/ setProperty(boolean = true, prop, method, throwIfNative) {
|
|
873
|
+
if (this[prop] === boolean) return this;
|
|
874
|
+
if (throwIfNative && this.cmd.meta.isNative) throw new Error(`Cannot configure ${method} for native command.`);
|
|
875
|
+
Object.defineProperty(this, prop, {
|
|
876
|
+
value: boolean,
|
|
877
|
+
configurable: true,
|
|
878
|
+
writable: true,
|
|
879
|
+
enumerable: true
|
|
880
|
+
});
|
|
881
|
+
this.cmd.outputDebugMessage('featureEnabled', ()=>({
|
|
882
|
+
[method]: boolean
|
|
883
|
+
}));
|
|
884
|
+
return this;
|
|
899
885
|
}
|
|
900
|
-
return parsedOptions;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
function getOwnAndGlobalOptions(cmd) {
|
|
904
|
-
return cmd.options.concat(getGlobalOptions(cmd));
|
|
905
886
|
}
|
|
906
887
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
888
|
+
const DefaultHelpConfig = {
|
|
889
|
+
helpWidth: undefined,
|
|
890
|
+
showGlobalOptions: true,
|
|
891
|
+
sortSubcommands: false,
|
|
892
|
+
sortOptions: false,
|
|
893
|
+
subcommandTerm,
|
|
894
|
+
argumentTerm,
|
|
895
|
+
commandUsage,
|
|
896
|
+
visibleOptions,
|
|
897
|
+
visibleGlobalOptions,
|
|
898
|
+
subcommandDescription,
|
|
899
|
+
optionDescription,
|
|
900
|
+
argumentDescription,
|
|
901
|
+
commandDescription,
|
|
902
|
+
formatHelp
|
|
903
|
+
};
|
|
904
|
+
function formatHelp(cmd) {
|
|
905
|
+
let result = commander.Help.prototype.formatHelp.call(this, cmd, this);
|
|
906
|
+
result = movePresetOptionsUnderOwnHeader(result);
|
|
907
|
+
result = rearrangeSections(result);
|
|
908
|
+
result = fixLinebreaks(result);
|
|
909
|
+
result = addColors(result);
|
|
910
|
+
return result;
|
|
911
|
+
function movePresetOptionsUnderOwnHeader(result) {
|
|
912
|
+
const lines = result.split('\n');
|
|
913
|
+
const presetLines = lines.filter((line)=>line.includes('[Preset]:'));
|
|
914
|
+
const firstPresetIndex = lines.findIndex((line)=>line.includes('[Preset]'));
|
|
915
|
+
if (firstPresetIndex !== -1) {
|
|
916
|
+
lines.splice(firstPresetIndex, presetLines.length);
|
|
917
|
+
lines.push('', 'Preset Options:', ...presetLines);
|
|
918
|
+
result = lines.join('\n');
|
|
912
919
|
}
|
|
920
|
+
return result;
|
|
913
921
|
}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
922
|
+
function rearrangeSections(result) {
|
|
923
|
+
const order = [
|
|
924
|
+
'Usage:',
|
|
925
|
+
'Version:',
|
|
926
|
+
'Description:',
|
|
927
|
+
'Commands:',
|
|
928
|
+
'Arguments:',
|
|
929
|
+
'Options:',
|
|
930
|
+
'Global Options:',
|
|
931
|
+
'Preset Options:'
|
|
932
|
+
];
|
|
933
|
+
const blocks = {};
|
|
934
|
+
let lastAddedBlock = 'Description:';
|
|
935
|
+
result.split(/\n\n+/).forEach((block)=>{
|
|
936
|
+
const title = block.split(':')[0].trim() + ':';
|
|
937
|
+
if (/^[A-Z][\w ]+:/.test(title)) {
|
|
938
|
+
blocks[title] = block;
|
|
939
|
+
lastAddedBlock = title;
|
|
940
|
+
if (!order.includes(title)) order.push(title);
|
|
941
|
+
} else {
|
|
942
|
+
if (!order.includes(lastAddedBlock)) order.push(lastAddedBlock);
|
|
943
|
+
blocks[lastAddedBlock] = ((blocks[lastAddedBlock] || '') + '\n\n' + block).trim();
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
result = order.map((title)=>blocks[title]).join('\n\n').trim();
|
|
947
|
+
return result;
|
|
948
|
+
}
|
|
949
|
+
function fixLinebreaks(result) {
|
|
950
|
+
result = '\n' + result.trim() + '\n\n';
|
|
951
|
+
result = result.replace(/\n\n+/g, '\n\n');
|
|
952
|
+
return result;
|
|
953
|
+
}
|
|
954
|
+
function addColors(result) {
|
|
955
|
+
result = result.replace(/\|/g, colors__default["default"].gray(colors__default["default"].dim('|')));
|
|
956
|
+
result = result.replace(/^[A-Z][\w ]+:/gm, (s)=>colors__default["default"].yellow(s));
|
|
957
|
+
return result;
|
|
923
958
|
}
|
|
924
|
-
return opts;
|
|
925
959
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
const
|
|
929
|
-
|
|
960
|
+
function subcommandTerm(cmd) {
|
|
961
|
+
const args = cmd.registeredArguments.map((arg)=>this.argumentTerm(arg)).join(' ');
|
|
962
|
+
const parent = cmd.parent || cmd;
|
|
963
|
+
const hasAliases = !cmd.parent || parent.commands.some((c)=>!!c.alias());
|
|
964
|
+
if (!hasAliases) return cmd.name() + (args ? ' ' + args : '');
|
|
965
|
+
const padsize = Math.max(1, ...parent.commands.map((c)=>c.alias()?.length || 1));
|
|
966
|
+
let alias = cmd.alias() || ' ';
|
|
967
|
+
alias = alias.padEnd(padsize, ' ') + ' |';
|
|
968
|
+
return alias + cmd.name() + (args ? ' ' + args : '');
|
|
969
|
+
}
|
|
970
|
+
function argumentTerm(arg) {
|
|
971
|
+
let r = arg.name();
|
|
972
|
+
const rest = arg.variadic ? '...' : '';
|
|
973
|
+
if (arg.required) r = '<' + r + rest + '>';
|
|
974
|
+
else r = '[' + r + rest + ']';
|
|
975
|
+
return r;
|
|
976
|
+
}
|
|
977
|
+
function commandUsage(cmd) {
|
|
978
|
+
const args = cmd.registeredArguments.map((arg)=>this.argumentTerm(arg)).join(' ');
|
|
979
|
+
return [
|
|
980
|
+
cmd.builder.getPrefixString() + ' ' + (args ? args : '[command]'),
|
|
981
|
+
'[options]'
|
|
982
|
+
].join(' ');
|
|
930
983
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
const
|
|
934
|
-
const
|
|
935
|
-
|
|
936
|
-
assertValidOptions(cb, opts);
|
|
937
|
-
return opts;
|
|
984
|
+
function visibleOptions(cmd) {
|
|
985
|
+
const builder = cmd.builder;
|
|
986
|
+
const opts = cmd.options.filter((opt)=>!opt.hidden && !builder.meta.globalOptions.includes(opt));
|
|
987
|
+
const presets = opts.filter((opt)=>opt.description.startsWith('[Preset]'));
|
|
988
|
+
return opts.filter((opt)=>!presets.includes(opt)).concat(presets);
|
|
938
989
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
return [
|
|
946
|
-
args,
|
|
947
|
-
opts
|
|
948
|
-
];
|
|
990
|
+
function visibleGlobalOptions(cmd) {
|
|
991
|
+
const gopts = cmd.builder.getGlobalOptions();
|
|
992
|
+
if (gopts.find((opt)=>opt.long === '--help')) return gopts;
|
|
993
|
+
const help = cmd.options.find((opt)=>opt.long === '--help');
|
|
994
|
+
if (help) gopts.push(help);
|
|
995
|
+
return gopts;
|
|
949
996
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
*
|
|
953
|
-
*/ function actionWrapper(cmd) {
|
|
954
|
-
const meta = cmd.meta;
|
|
955
|
-
cmd.$.action(async ()=>{
|
|
956
|
-
handleOutputOptions(cmd);
|
|
957
|
-
const [args, opts] = parsedValidArgsOptsWithPresets(cmd);
|
|
958
|
-
if (opts['help'] || !meta.actionHandler) return cmd.outputHelp();
|
|
959
|
-
return await meta.actionHandler(...args, opts, cmd).catch((err)=>handleError(cmd, err));
|
|
960
|
-
});
|
|
997
|
+
function subcommandDescription(cmd) {
|
|
998
|
+
return colors__default["default"].gray(commander.Help.prototype.subcommandDescription.call(this, cmd));
|
|
961
999
|
}
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
for (const anc of walkAncestors(cmd, {
|
|
965
|
-
includeSelf: true
|
|
966
|
-
})){
|
|
967
|
-
if (!anc.meta.isNative) return anc;
|
|
968
|
-
}
|
|
969
|
-
return cmd.root;
|
|
1000
|
+
function optionDescription(opt) {
|
|
1001
|
+
return colors__default["default"].gray(commander.Help.prototype.optionDescription.call(this, opt));
|
|
970
1002
|
}
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1003
|
+
function argumentDescription(arg) {
|
|
1004
|
+
return colors__default["default"].gray(commander.Help.prototype.argumentDescription.call(this, arg));
|
|
1005
|
+
}
|
|
1006
|
+
function commandDescription(cmd) {
|
|
1007
|
+
const v = cmd.builder.getVersion();
|
|
1008
|
+
const version = v ? colors__default["default"].yellow('Version: ') + v + '\n\n' : '';
|
|
1009
|
+
const description = 'Description:\n' + commander.Help.prototype.commandDescription.call(this, cmd);
|
|
1010
|
+
return version + description;
|
|
974
1011
|
}
|
|
975
|
-
const createConfig = (()=>{
|
|
976
|
-
return function createConfig(config) {
|
|
977
|
-
config.description('Manage configuration file.');
|
|
978
|
-
config.alias('c');
|
|
979
|
-
config.nativeCommand('edit', createEdit);
|
|
980
|
-
config.nativeCommand('list', createList);
|
|
981
|
-
config.nativeCommand('get', createGet);
|
|
982
|
-
config.nativeCommand('set', createSet);
|
|
983
|
-
config.nativeCommand('reset', createReset);
|
|
984
|
-
};
|
|
985
|
-
function createEdit(edit) {
|
|
986
|
-
edit.description('Edit as JSON in a text editor.');
|
|
987
|
-
edit.option('--editor [cmd]', (e)=>{
|
|
988
|
-
e.description('The command to launch your preferred text editor.');
|
|
989
|
-
e.default(util.defaultOpenInEditorCommand());
|
|
990
|
-
});
|
|
991
|
-
edit.action(editAction);
|
|
992
|
-
}
|
|
993
|
-
async function editAction(opts, edit) {
|
|
994
|
-
const cmd = getClosestNonNativeParent(edit);
|
|
995
|
-
cmd.db.config.edit(opts.editor);
|
|
996
|
-
console.info(cmd.db.config.getAll());
|
|
997
|
-
}
|
|
998
|
-
function createList(list) {
|
|
999
|
-
list.description('Print entire config with values, descriptions and defaults.');
|
|
1000
|
-
list.action(listAction);
|
|
1001
|
-
}
|
|
1002
|
-
async function listAction(_, list) {
|
|
1003
|
-
const cmd = getClosestNonNativeParent(list);
|
|
1004
|
-
console.dir(cmd.db.config.keys.map((key)=>{
|
|
1005
|
-
return {
|
|
1006
|
-
key,
|
|
1007
|
-
description: cmd.db.config.descriptions[key],
|
|
1008
|
-
value: cmd.db.config.get(key),
|
|
1009
|
-
defaultValue: cmd.db.config.defaultValues
|
|
1010
|
-
};
|
|
1011
|
-
}));
|
|
1012
|
-
}
|
|
1013
|
-
function createGet(get) {
|
|
1014
|
-
get.description('Print value(s) from the config.');
|
|
1015
|
-
get.argument('[key]', (a)=>{
|
|
1016
|
-
a.description('The key to print the value of. Omit to print all values.');
|
|
1017
|
-
a.choices(a.cmd.db.config.keys);
|
|
1018
|
-
});
|
|
1019
|
-
get.action(getAction);
|
|
1020
|
-
}
|
|
1021
|
-
async function getAction(key, get) {
|
|
1022
|
-
const cmd = getClosestNonNativeParent(get);
|
|
1023
|
-
if (key) console.log(cmd.db.config.get(key));
|
|
1024
|
-
else console.log(cmd.db.config.getAll());
|
|
1025
|
-
}
|
|
1026
|
-
function createSet(set) {
|
|
1027
|
-
set.description('Set a value in the config.');
|
|
1028
|
-
set.argument('<key>', (a)=>{
|
|
1029
|
-
a.description('The key to set the value of.');
|
|
1030
|
-
a.choices(a.cmd.db.config.keys);
|
|
1031
|
-
});
|
|
1032
|
-
set.argument('<value>', (a)=>a.description('The new value.'));
|
|
1033
|
-
set.action(setAction);
|
|
1034
|
-
}
|
|
1035
|
-
async function setAction(key, value, set) {
|
|
1036
|
-
const cmd = getClosestNonNativeParent(set);
|
|
1037
|
-
const from = cmd.db.config.get(key);
|
|
1038
|
-
const to = cmd.db.config.parsers[key](value);
|
|
1039
|
-
cmd.db.config.set(key, to);
|
|
1040
|
-
console.info({
|
|
1041
|
-
changed: key,
|
|
1042
|
-
from,
|
|
1043
|
-
to
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1046
|
-
function createReset(reset) {
|
|
1047
|
-
reset.description('Reset to defaults.');
|
|
1048
|
-
reset.argument('[key]', (a)=>{
|
|
1049
|
-
a.description('The key for which to reset the value. Omit to reset entire config.');
|
|
1050
|
-
a.choices(a.cmd.db.config.keys);
|
|
1051
|
-
});
|
|
1052
|
-
reset.action(resetAction);
|
|
1053
|
-
}
|
|
1054
|
-
async function resetAction(key, reset) {
|
|
1055
|
-
var _reset_parent;
|
|
1056
|
-
const cmd = (_reset_parent = reset.parent) == null ? void 0 : _reset_parent.parent;
|
|
1057
|
-
if (key) cmd.db.config.reset(key);
|
|
1058
|
-
else cmd.db.config.resetAll();
|
|
1059
|
-
console.info(cmd.db.config.getAll());
|
|
1060
|
-
}
|
|
1061
|
-
})();
|
|
1062
|
-
|
|
1063
|
-
function addPresetsCommands(cmd) {
|
|
1064
|
-
cmd.nativeCommand('presets', createPresets);
|
|
1065
|
-
}
|
|
1066
|
-
const createPresets = (()=>{
|
|
1067
|
-
return function createPresets(presets) {
|
|
1068
|
-
const cmd = getClosestNonNativeParent(presets);
|
|
1069
|
-
for (const [name, pre] of Object.entries(cmd.db.presets.getAll())){
|
|
1070
|
-
if (name === 'defaults') continue;
|
|
1071
|
-
cmd.option(`--${name}`, (opt)=>{
|
|
1072
|
-
opt.description('[Preset]: ' + pre.description);
|
|
1073
|
-
if (pre.presets.length) {
|
|
1074
|
-
opt.implies(pre.presets.reduce((acc, key)=>{
|
|
1075
|
-
acc[key] = true;
|
|
1076
|
-
return acc;
|
|
1077
|
-
}, {}));
|
|
1078
|
-
}
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
presets.alias('p');
|
|
1082
|
-
presets.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.');
|
|
1083
|
-
presets.nativeCommand('edit', createEdit);
|
|
1084
|
-
presets.nativeCommand('list', createList);
|
|
1085
|
-
};
|
|
1086
|
-
function createEdit(edit) {
|
|
1087
|
-
edit.description('Edit as JSON in a text editor.');
|
|
1088
|
-
edit.option('--editor [cmd]', (e)=>{
|
|
1089
|
-
e.description('The command to launch your preferred text editor.');
|
|
1090
|
-
e.default(util.defaultOpenInEditorCommand());
|
|
1091
|
-
});
|
|
1092
|
-
edit.action(editAction);
|
|
1093
|
-
}
|
|
1094
|
-
async function editAction(opts, edit) {
|
|
1095
|
-
const cmd = getClosestNonNativeParent(edit);
|
|
1096
|
-
cmd.db.presets.edit(opts.editor);
|
|
1097
|
-
console.info(cmd.db.presets.getAll());
|
|
1098
|
-
}
|
|
1099
|
-
function createList(list) {
|
|
1100
|
-
list.description('List all presets.');
|
|
1101
|
-
list.action(listAction);
|
|
1102
|
-
}
|
|
1103
|
-
async function listAction(_, list) {
|
|
1104
|
-
const cmd = getClosestNonNativeParent(list);
|
|
1105
|
-
console.dir(cmd.db.presets.getAll(), {
|
|
1106
|
-
depth: null
|
|
1107
|
-
});
|
|
1108
|
-
}
|
|
1109
|
-
})();
|
|
1110
1012
|
|
|
1111
1013
|
function formatTableForTerminal(rows, headers) {
|
|
1112
1014
|
if (!rows.length || !rows[0].length) return '';
|
|
1113
1015
|
const table = new Table__default["default"]();
|
|
1114
1016
|
if (headers && headers.length) {
|
|
1115
|
-
table.push(headers.map((s)=>
|
|
1017
|
+
table.push(headers.map((s)=>colors__default["default"].bold(colors__default["default"].yellow(s))));
|
|
1116
1018
|
}
|
|
1117
1019
|
for (const row of rows)table.push(row);
|
|
1118
1020
|
return table.toString();
|
|
1119
1021
|
}
|
|
1120
1022
|
|
|
1121
|
-
|
|
1122
|
-
* Get a commands prefix array based on all its parent/ancestor commands.
|
|
1123
|
-
*/ function prefixArray(cmd) {
|
|
1124
|
-
return getAncestors(cmd, {
|
|
1125
|
-
includeSelf: true
|
|
1126
|
-
}).reverse().map((node)=>node.name);
|
|
1127
|
-
}
|
|
1023
|
+
const isArray = Array.isArray;
|
|
1128
1024
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1025
|
+
/**
|
|
1026
|
+
* Checks if the provided value is an object (null, arrays and functions not included).
|
|
1027
|
+
* @template T - The type of the value to check.
|
|
1028
|
+
* @param value The value to check.
|
|
1029
|
+
* @returns A boolean indicating whether the provided value is an object.
|
|
1030
|
+
* @example ```ts
|
|
1031
|
+
* isObject({});;
|
|
1032
|
+
* //=> true
|
|
1033
|
+
* isObject([1]);;
|
|
1034
|
+
* //=> false
|
|
1035
|
+
* isObject(123);;
|
|
1036
|
+
* //=> false
|
|
1037
|
+
* ```
|
|
1038
|
+
*/ function isObject(value) {
|
|
1039
|
+
return value != null && typeof value === 'object' && !Array.isArray(value);
|
|
1131
1040
|
}
|
|
1132
1041
|
|
|
1133
1042
|
/**
|
|
1134
|
-
*
|
|
1135
|
-
*/ function
|
|
1136
|
-
return
|
|
1043
|
+
* Determine whether the input is a string array.
|
|
1044
|
+
*/ function isStringArray(value) {
|
|
1045
|
+
return Array.isArray(value) && value.every((v)=>isString(v));
|
|
1137
1046
|
}
|
|
1138
1047
|
|
|
1139
|
-
function
|
|
1140
|
-
|
|
1141
|
-
if ((_options = options) == null ? void 0 : _options.includeSelf) yield cmd;
|
|
1142
|
-
for (const sub of cmd.meta.subcommands){
|
|
1143
|
-
yield sub;
|
|
1144
|
-
yield* walkChildren(sub);
|
|
1145
|
-
}
|
|
1048
|
+
function isStringWithNoSpacesOrDashes(value) {
|
|
1049
|
+
return isString(value) && /^[^\s-]+$/i.test(value);
|
|
1146
1050
|
}
|
|
1147
1051
|
|
|
1148
1052
|
/**
|
|
1149
|
-
*
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
})){
|
|
1155
|
-
const prefix = prefixString(c);
|
|
1156
|
-
if (filter && !filter(prefix, c)) continue;
|
|
1157
|
-
result.push([
|
|
1158
|
-
prefix,
|
|
1159
|
-
c.get.summary
|
|
1160
|
-
]);
|
|
1161
|
-
}
|
|
1162
|
-
return result;
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
function addUtilCommands(cmd) {
|
|
1166
|
-
cmd.nativeCommand('util', createUtil);
|
|
1053
|
+
* Checks if the current platform is OSX.
|
|
1054
|
+
* It checks the 'process' object and the 'platform' property to determine if the platform is 'darwin'.
|
|
1055
|
+
* @returns A boolean indicating whether the current platform is OSX.
|
|
1056
|
+
*/ function isOSX() {
|
|
1057
|
+
return process.platform === 'darwin';
|
|
1167
1058
|
}
|
|
1168
|
-
const createUtil = (()=>{
|
|
1169
|
-
return function createUtil(util) {
|
|
1170
|
-
util.$.alias('u');
|
|
1171
|
-
util.description('Utility commands.');
|
|
1172
|
-
const cmd = getClosestNonNativeParent(util);
|
|
1173
|
-
if (cmd.features.isConfigEnabled) {
|
|
1174
|
-
addConfigCommands(util);
|
|
1175
|
-
}
|
|
1176
|
-
if (cmd.features.isPresetsEnabled && cmd.meta.actionHandler) {
|
|
1177
|
-
addPresetsCommands(util);
|
|
1178
|
-
}
|
|
1179
|
-
if (hasGrandChildren(cmd) || usesJsonFile(cmd)) {
|
|
1180
|
-
util.nativeCommand('tree', createTree);
|
|
1181
|
-
}
|
|
1182
|
-
if (usesJsonFile(cmd)) {
|
|
1183
|
-
util.nativeCommand('filepath', createFilepath);
|
|
1184
|
-
}
|
|
1185
|
-
};
|
|
1186
|
-
function hasGrandChildren(c) {
|
|
1187
|
-
return c.meta.subcommands.some((c)=>!!c.meta.subcommands.length);
|
|
1188
|
-
}
|
|
1189
|
-
function usesJsonFile(c) {
|
|
1190
|
-
return c.features.isConfigEnabled || c.features.isPresetsEnabled;
|
|
1191
|
-
}
|
|
1192
|
-
function createFilepath(fp) {
|
|
1193
|
-
fp.description('Print filepath to JSON file containing user data, eg. config and presets.');
|
|
1194
|
-
fp.action(filepathAction);
|
|
1195
|
-
}
|
|
1196
|
-
async function filepathAction(_, fp) {
|
|
1197
|
-
const cmd = getClosestNonNativeParent(fp);
|
|
1198
|
-
console.log(getJsonFilepath(cmd));
|
|
1199
|
-
}
|
|
1200
|
-
function createTree(tree) {
|
|
1201
|
-
tree.description('List nested subcommands.');
|
|
1202
|
-
tree.action(treeAction);
|
|
1203
|
-
tree.nativeCommand('all', createTreeAll);
|
|
1204
|
-
}
|
|
1205
|
-
async function treeAction(_, tree) {
|
|
1206
|
-
const cmd = getClosestNonNativeParent(tree);
|
|
1207
|
-
const table = prefixStringsRecursive(cmd, (prefix)=>{
|
|
1208
|
-
return !/ (config|presets|util)( .+)?$/gi.test(prefix);
|
|
1209
|
-
});
|
|
1210
|
-
console.log(formatCommandTable(table));
|
|
1211
|
-
}
|
|
1212
|
-
function createTreeAll(all) {
|
|
1213
|
-
all.description('List all subcommands including utility commands.');
|
|
1214
|
-
all.action(treeAllAction);
|
|
1215
|
-
}
|
|
1216
|
-
async function treeAllAction(_, all) {
|
|
1217
|
-
const cmd = getClosestNonNativeParent(all);
|
|
1218
|
-
const table = prefixStringsRecursive(cmd);
|
|
1219
|
-
console.log(formatCommandTable(table));
|
|
1220
|
-
}
|
|
1221
|
-
function formatCommandTable(table) {
|
|
1222
|
-
const ansi = table.map((row)=>{
|
|
1223
|
-
const arr = row[0].split(' ');
|
|
1224
|
-
const last = arr.pop();
|
|
1225
|
-
let col = util.colors.magenta;
|
|
1226
|
-
if (row[1].startsWith('[Preset]')) {
|
|
1227
|
-
col = util.colors.green;
|
|
1228
|
-
} else if (/ (util|config|presets) /.test(row[0])) {
|
|
1229
|
-
col = util.colors.gray;
|
|
1230
|
-
} else if (/ (util|config|presets)/.test(row[0])) {
|
|
1231
|
-
col = util.colors.dim;
|
|
1232
|
-
}
|
|
1233
|
-
row[0] = arr.map(util.colors.dim).concat(col(last)).join(' ');
|
|
1234
|
-
return row;
|
|
1235
|
-
});
|
|
1236
|
-
return formatTableForTerminal(ansi, [
|
|
1237
|
-
'Command',
|
|
1238
|
-
'Summary'
|
|
1239
|
-
]);
|
|
1240
|
-
}
|
|
1241
|
-
})();
|
|
1242
1059
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1060
|
+
/**
|
|
1061
|
+
* Returns whether Visual Studio Code is installed on the system.
|
|
1062
|
+
* @example isVsCodeInstalled() //=> true
|
|
1063
|
+
*/ function isVsCodeInstalled() {
|
|
1064
|
+
try {
|
|
1065
|
+
const stdout = child_process.execSync('code --help').toString();
|
|
1066
|
+
return stdout.startsWith('Visual Studio Code') && stdout.includes('-w --wait');
|
|
1067
|
+
} catch (e) {
|
|
1068
|
+
return false;
|
|
1247
1069
|
}
|
|
1248
1070
|
}
|
|
1249
1071
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
if (set.has(opt.short)) throwErr(cmd, opt.short);
|
|
1259
|
-
set.add(opt.short);
|
|
1260
|
-
}
|
|
1261
|
-
if (opt.long) {
|
|
1262
|
-
if (set.has(opt.long)) throwErr(cmd, opt.long);
|
|
1263
|
-
set.add(opt.long);
|
|
1264
|
-
}
|
|
1265
|
-
if (opt.attributeName()) {
|
|
1266
|
-
if (set.has(opt.attributeName())) throwErr(cmd, opt.attributeName());
|
|
1267
|
-
set.add(opt.attributeName());
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
for (const anc of walkAncestors(cmd)){
|
|
1271
|
-
for (const opt of anc.$.options){
|
|
1272
|
-
if (opt.short && set.has(opt.short)) {
|
|
1273
|
-
if (opt.short !== 'V') continue;
|
|
1274
|
-
throwErr(cmd, opt.short, anc);
|
|
1275
|
-
}
|
|
1276
|
-
if (opt.long && set.has(opt.long)) {
|
|
1277
|
-
throwErr(cmd, opt.long, anc);
|
|
1278
|
-
}
|
|
1279
|
-
if (opt.attributeName() && set.has(opt.attributeName())) {
|
|
1280
|
-
throwErr(cmd, opt.attributeName(), anc);
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Checks if the current platform is Windows.
|
|
1074
|
+
* @remarks
|
|
1075
|
+
* It checks the 'process' object and the 'platform' property to determine if the platform is 'win32'.
|
|
1076
|
+
* It also checks the 'OSTYPE' environment variable to see if it matches 'msys' or 'cygwin'.
|
|
1077
|
+
* @returns A boolean indicating whether the current platform is Windows.
|
|
1078
|
+
*/ function isWindows() {
|
|
1079
|
+
return isWin;
|
|
1284
1080
|
}
|
|
1081
|
+
const isWin = process && (process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env['OSTYPE'] || ''));
|
|
1285
1082
|
|
|
1286
1083
|
/**
|
|
1287
|
-
*
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
if (
|
|
1291
|
-
return
|
|
1084
|
+
* Get the default command to open a file in in a text editor.
|
|
1085
|
+
* If VSCode is installed, this is used. Otherwise, the default text editor of the OS is used.
|
|
1086
|
+
*/ function defaultOpenInEditorCommand() {
|
|
1087
|
+
if (!COMMAND) COMMAND = isVsCodeInstalled() ? 'code -w' : isWindows() ? 'notepad' : isOSX() ? 'open vi' : 'xdg-open';
|
|
1088
|
+
return COMMAND;
|
|
1292
1089
|
}
|
|
1090
|
+
let COMMAND = '';
|
|
1293
1091
|
|
|
1294
1092
|
/**
|
|
1295
|
-
*
|
|
1296
|
-
*
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
return
|
|
1093
|
+
* Reads a file and returns the file's contents.
|
|
1094
|
+
* Identical to fs.readFileSync, except that it uses utf8 encoding by default.
|
|
1095
|
+
*
|
|
1096
|
+
* @param filepath - The path to the file.
|
|
1097
|
+
* @param encoding - The encoding to use when reading the file.
|
|
1098
|
+
* @returns The file's contents.
|
|
1099
|
+
*/ function readFileSync(filepath, encoding = 'utf8') {
|
|
1100
|
+
return fs__default["default"].readFileSync(filepath, encoding);
|
|
1303
1101
|
}
|
|
1304
1102
|
|
|
1305
1103
|
/**
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1104
|
+
* Ensures that a string starts with a specified substring. If the string already starts with the specified substring, it is returned as is. Otherwise, the substring is appended to the end of the string.
|
|
1105
|
+
* @param string The string to be processed.
|
|
1106
|
+
* @param startsWith The substring that the string should end with.
|
|
1107
|
+
* @example ```ts
|
|
1108
|
+
* strEnsureStartsWith('json', '.');
|
|
1109
|
+
* //=> '.json'
|
|
1110
|
+
* strEnsureStartsWith('.json', '.');
|
|
1111
|
+
* //=> '.json'
|
|
1112
|
+
* ```
|
|
1113
|
+
*/ function strEnsureStartsWith(string, startsWith) {
|
|
1114
|
+
return string.startsWith(startsWith) ? string : startsWith + string;
|
|
1311
1115
|
}
|
|
1312
1116
|
|
|
1313
1117
|
/**
|
|
1314
|
-
*
|
|
1315
|
-
*
|
|
1316
|
-
* First, it tries to assign a short name based on the first letter of the option's attribute name
|
|
1317
|
-
* Both lower and upper case are tried. If these is not available, the next letter of the option name is tried.
|
|
1118
|
+
* Returns a path to the os tmpdir location.
|
|
1318
1119
|
*
|
|
1319
|
-
*
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
* If there are 64 options for the command and no more alphanumeric characters are available,
|
|
1323
|
-
* the option is not assigned a short name.
|
|
1324
|
-
*/ function autoAssignMissingOptionFlags(cmd) {
|
|
1325
|
-
const taken = new Set();
|
|
1326
|
-
for (const anc of walkAncestors(cmd, {
|
|
1327
|
-
includeSelf: true
|
|
1328
|
-
})){
|
|
1329
|
-
anc.options.forEach((opt)=>{
|
|
1330
|
-
if (!opt.short) return;
|
|
1331
|
-
taken.add(opt.short.replace(/^-/g, ''));
|
|
1332
|
-
});
|
|
1333
|
-
}
|
|
1334
|
-
const failed = new Set();
|
|
1335
|
-
// assign letter from option name
|
|
1336
|
-
cmd.options.forEach((opt)=>{
|
|
1337
|
-
if (opt.short) return;
|
|
1338
|
-
const name = opt.attributeName();
|
|
1339
|
-
for(let c = 0; c < name.length; c++){
|
|
1340
|
-
let char = name.charAt(c).toLowerCase();
|
|
1341
|
-
if (taken.has(char)) {
|
|
1342
|
-
char = char.toUpperCase();
|
|
1343
|
-
if (taken.has(char)) continue;
|
|
1344
|
-
}
|
|
1345
|
-
setOptionShortName(opt, char);
|
|
1346
|
-
taken.add(char);
|
|
1347
|
-
return;
|
|
1348
|
-
}
|
|
1349
|
-
failed.add(opt);
|
|
1350
|
-
});
|
|
1351
|
-
// assign random alphanumeric character.
|
|
1352
|
-
const name = 'abcdefghijklmnopqrstuvwxyz1234567890';
|
|
1353
|
-
failed.forEach((opt)=>{
|
|
1354
|
-
for(let c = 0; c < name.length; c++){
|
|
1355
|
-
let char = name.charAt(c);
|
|
1356
|
-
if (taken.has(char)) {
|
|
1357
|
-
char = char.toUpperCase();
|
|
1358
|
-
if (taken.has(char)) continue;
|
|
1359
|
-
}
|
|
1360
|
-
setOptionShortName(opt, char);
|
|
1361
|
-
taken.add(char);
|
|
1362
|
-
return;
|
|
1363
|
-
}
|
|
1364
|
-
});
|
|
1120
|
+
* @param paths - The paths to join to the os tmpdir location.
|
|
1121
|
+
*/ function getTempDataPath(...paths) {
|
|
1122
|
+
return path__default["default"].join(tempdir, ...paths);
|
|
1365
1123
|
}
|
|
1124
|
+
const tempdir = fs__default["default"].realpathSync(os__default["default"].tmpdir());
|
|
1366
1125
|
|
|
1367
1126
|
/**
|
|
1368
|
-
*
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1127
|
+
* Syncrhonously creates a temporary file and deletes it after the callback has finished.
|
|
1128
|
+
* @param fileExtension - The file extension to use for the temporary file.
|
|
1129
|
+
* @param callback - The callback to execute with the temporary file path. The callback can return a promise and the temporary file will not be deleted until the promise has resolved or rejected.
|
|
1130
|
+
*/ function tempFileSync(fileExtension, callback) {
|
|
1131
|
+
const fpath = getTempDataPath('temp', Date.now() + strEnsureStartsWith(fileExtension, '.'));
|
|
1132
|
+
fs__default["default"].ensureFileSync(fpath);
|
|
1133
|
+
try {
|
|
1134
|
+
const retval = callback(fpath);
|
|
1135
|
+
fs__default["default"].remove(fpath);
|
|
1136
|
+
return retval;
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
fs__default["default"].remove(fpath);
|
|
1374
1139
|
}
|
|
1375
1140
|
}
|
|
1376
1141
|
|
|
1377
1142
|
/**
|
|
1378
|
-
*
|
|
1379
|
-
*/ function getSiblings(cmd) {
|
|
1380
|
-
return [
|
|
1381
|
-
...walkSiblings(cmd)
|
|
1382
|
-
];
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
/**
|
|
1386
|
-
* Makes aliases for the command.
|
|
1387
|
-
* The idea is to be able to navigate the command tree by only typing the first letter(s) of the command names.
|
|
1388
|
-
*
|
|
1389
|
-
* Example: A command 'cola' would get these aliases: ['c', 'co', 'col'].
|
|
1390
|
-
* However, if there are namespace clashes with sibling subcommands that start with the same letter,
|
|
1391
|
-
* eg. like 'cola' and 'coal' where the first two letters clash, cola's aliases are reduced to only ['col'] and similarly for 'coal'.
|
|
1143
|
+
* Prompts the user to edit a string in the user's text editor.
|
|
1392
1144
|
*
|
|
1393
|
-
*
|
|
1394
|
-
*
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
const
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1145
|
+
* @example ```ts
|
|
1146
|
+
* promptUserEditInTextEditor({ editor: 'notepad' })
|
|
1147
|
+
* ```
|
|
1148
|
+
*/ function promptUserEditInTextEditorSync(options) {
|
|
1149
|
+
const { editor, content, extension } = applyDefaults(options);
|
|
1150
|
+
return tempFileSync(extension, (tempfile)=>{
|
|
1151
|
+
fs.writeFileSync(tempfile, content);
|
|
1152
|
+
child_process.execSync(`${editor} ${tempfile}`, {
|
|
1153
|
+
stdio: 'inherit'
|
|
1402
1154
|
});
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
isClash = util.arrSome(sibAliases, (sibAlias)=>{
|
|
1406
|
-
return cmdAlias === sibAlias;
|
|
1407
|
-
});
|
|
1408
|
-
}
|
|
1409
|
-
if (isClash) continue;
|
|
1410
|
-
cmd.alias(cmdAlias);
|
|
1411
|
-
return;
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
function configureHelp(cmd) {
|
|
1416
|
-
const cmdr = cmd.$;
|
|
1417
|
-
cmdr.addHelpCommand('?', 'show help');
|
|
1418
|
-
cmdr.configureHelp(opts);
|
|
1155
|
+
return readFileSync(tempfile);
|
|
1156
|
+
});
|
|
1419
1157
|
}
|
|
1420
|
-
|
|
1158
|
+
function applyDefaults(options = {}) {
|
|
1159
|
+
const content = options.content ?? '';
|
|
1160
|
+
const extension = strEnsureStartsWith(options.extension ?? '.txt', '.');
|
|
1161
|
+
const editor = options.editor ?? defaultOpenInEditorCommand();
|
|
1421
1162
|
return {
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
sortOptions: false,
|
|
1426
|
-
subcommandTerm,
|
|
1427
|
-
argumentTerm,
|
|
1428
|
-
commandUsage,
|
|
1429
|
-
visibleOptions,
|
|
1430
|
-
visibleGlobalOptions,
|
|
1431
|
-
subcommandDescription,
|
|
1432
|
-
optionDescription,
|
|
1433
|
-
argumentDescription,
|
|
1434
|
-
commandDescription,
|
|
1435
|
-
formatHelp
|
|
1163
|
+
content,
|
|
1164
|
+
extension,
|
|
1165
|
+
editor
|
|
1436
1166
|
};
|
|
1437
|
-
function formatHelp(cmd) {
|
|
1438
|
-
let result = commander.Help.prototype.formatHelp.call(this, cmd, this);
|
|
1439
|
-
result = movePresetOptionsUnderOwnHeader(result);
|
|
1440
|
-
result = rearrangeSections(result);
|
|
1441
|
-
result = fixLinebreaks(result);
|
|
1442
|
-
result = addColors(result);
|
|
1443
|
-
return result;
|
|
1444
|
-
function movePresetOptionsUnderOwnHeader(result) {
|
|
1445
|
-
const lines = result.split('\n');
|
|
1446
|
-
const presetLines = lines.filter((line)=>line.includes('[Preset]:'));
|
|
1447
|
-
const firstPresetIndex = lines.findIndex((line)=>line.includes('[Preset]'));
|
|
1448
|
-
if (firstPresetIndex !== -1) {
|
|
1449
|
-
lines.splice(firstPresetIndex, presetLines.length);
|
|
1450
|
-
lines.push('', 'Preset Options:', ...presetLines);
|
|
1451
|
-
result = lines.join('\n');
|
|
1452
|
-
}
|
|
1453
|
-
return result;
|
|
1454
|
-
}
|
|
1455
|
-
function rearrangeSections(result) {
|
|
1456
|
-
const order = [
|
|
1457
|
-
'Usage:',
|
|
1458
|
-
'Version:',
|
|
1459
|
-
'Description:',
|
|
1460
|
-
'Commands:',
|
|
1461
|
-
'Arguments:',
|
|
1462
|
-
'Options:',
|
|
1463
|
-
'Global Options:',
|
|
1464
|
-
'Preset Options:'
|
|
1465
|
-
];
|
|
1466
|
-
const blocks = {};
|
|
1467
|
-
let lastAddedBlock = 'Description:';
|
|
1468
|
-
result.split(/\n\n+/).forEach((block)=>{
|
|
1469
|
-
const title = block.split(':')[0].trim() + ':';
|
|
1470
|
-
if (/^[A-Z][\w ]+:/.test(title)) {
|
|
1471
|
-
blocks[title] = block;
|
|
1472
|
-
lastAddedBlock = title;
|
|
1473
|
-
if (!order.includes(title)) order.push(title);
|
|
1474
|
-
} else {
|
|
1475
|
-
if (!order.includes(lastAddedBlock)) order.push(lastAddedBlock);
|
|
1476
|
-
blocks[lastAddedBlock] = ((blocks[lastAddedBlock] || '') + '\n\n' + block).trim();
|
|
1477
|
-
}
|
|
1478
|
-
});
|
|
1479
|
-
result = order.map((title)=>blocks[title]).join('\n\n').trim();
|
|
1480
|
-
return result;
|
|
1481
|
-
}
|
|
1482
|
-
function fixLinebreaks(result) {
|
|
1483
|
-
result = '\n' + result.trim() + '\n\n';
|
|
1484
|
-
result = result.replace(/\n\n+/g, '\n\n');
|
|
1485
|
-
return result;
|
|
1486
|
-
}
|
|
1487
|
-
function addColors(result) {
|
|
1488
|
-
result = result.replace(/\|/g, util.colors.gray(util.colors.dim('|')));
|
|
1489
|
-
result = result.replace(/^[A-Z][\w ]+:/gm, (s)=>util.colors.yellow(s));
|
|
1490
|
-
return result;
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
function subcommandTerm(cmd) {
|
|
1494
|
-
const args = cmd.registeredArguments.map((arg)=>this.argumentTerm(arg)).join(' ');
|
|
1495
|
-
const parent = cmd.parent || cmd;
|
|
1496
|
-
const padsize = Math.max(1, ...parent.commands.map((c)=>{
|
|
1497
|
-
var _c_alias;
|
|
1498
|
-
return ((_c_alias = c.alias()) == null ? void 0 : _c_alias.length) || 1;
|
|
1499
|
-
}));
|
|
1500
|
-
let alias = cmd.alias() || ' ';
|
|
1501
|
-
alias = alias.padEnd(padsize, ' ') + ' |';
|
|
1502
|
-
return alias + cmd.name() + (args ? ' ' + args : '');
|
|
1503
|
-
}
|
|
1504
|
-
function argumentTerm(arg) {
|
|
1505
|
-
let r = arg.name();
|
|
1506
|
-
const rest = arg.variadic ? '...' : '';
|
|
1507
|
-
if (arg.required) r = '<' + r + rest + '>';
|
|
1508
|
-
else r = '[' + r + rest + ']';
|
|
1509
|
-
return r;
|
|
1510
|
-
}
|
|
1511
|
-
function commandUsage(cmd) {
|
|
1512
|
-
const args = cmd.registeredArguments.map((arg)=>this.argumentTerm(arg)).join(' ');
|
|
1513
|
-
return [
|
|
1514
|
-
prefixString(cmd.builder) + ' ' + (args ? args : '[command]'),
|
|
1515
|
-
'[options]'
|
|
1516
|
-
].join(' ');
|
|
1517
|
-
}
|
|
1518
|
-
function visibleOptions(cmd) {
|
|
1519
|
-
const builder = cmd.builder;
|
|
1520
|
-
const opts = cmd.options.filter((opt)=>!opt.hidden && !builder.meta.globalOptions.includes(opt));
|
|
1521
|
-
const presets = opts.filter((opt)=>opt.description.startsWith('[Preset]'));
|
|
1522
|
-
return opts.filter((opt)=>!presets.includes(opt)).concat(presets);
|
|
1523
|
-
}
|
|
1524
|
-
function visibleGlobalOptions(cmd) {
|
|
1525
|
-
return getGlobalOptions(cmd.builder);
|
|
1526
|
-
}
|
|
1527
|
-
function subcommandDescription(cmd) {
|
|
1528
|
-
return util.colors.gray(commander.Help.prototype.subcommandDescription.call(this, cmd));
|
|
1529
|
-
}
|
|
1530
|
-
function optionDescription(opt) {
|
|
1531
|
-
return util.colors.gray(commander.Help.prototype.optionDescription.call(this, opt));
|
|
1532
|
-
}
|
|
1533
|
-
function argumentDescription(arg) {
|
|
1534
|
-
return util.colors.gray(commander.Help.prototype.argumentDescription.call(this, arg));
|
|
1535
|
-
}
|
|
1536
|
-
function commandDescription(cmd) {
|
|
1537
|
-
const v = cmd.builder.get.version;
|
|
1538
|
-
const version = v ? util.colors.yellow('Version: ') + v + '\n\n' : '';
|
|
1539
|
-
const description = 'Description:\n' + commander.Help.prototype.commandDescription.call(this, cmd);
|
|
1540
|
-
return version + description;
|
|
1541
|
-
}
|
|
1542
|
-
})();
|
|
1543
|
-
|
|
1544
|
-
function ensureBackRefToCommandBuilder(cmd) {
|
|
1545
|
-
commandToBuilderMap.set(cmd.$, cmd);
|
|
1546
|
-
}
|
|
1547
|
-
const commandToBuilderMap = new WeakMap();
|
|
1548
|
-
Object.defineProperty(commander.Command.prototype, 'builder', {
|
|
1549
|
-
get () {
|
|
1550
|
-
const ins = commandToBuilderMap.get(this);
|
|
1551
|
-
if (!ins) throw new Error(`CommandBuilder not found for command ${this.name()}`);
|
|
1552
|
-
return ins;
|
|
1553
|
-
}
|
|
1554
|
-
});
|
|
1555
|
-
|
|
1556
|
-
function initializeCommand(cmd, callback) {
|
|
1557
|
-
const t0_precb = Date.now();
|
|
1558
|
-
ensureBackRefToCommandBuilder(cmd);
|
|
1559
|
-
actionWrapper(cmd);
|
|
1560
|
-
configureHelp(cmd);
|
|
1561
|
-
inheritBasicSettings(cmd);
|
|
1562
|
-
inheritHiddenGlobalOptions(cmd);
|
|
1563
|
-
const precb = Date.now() - t0_precb;
|
|
1564
|
-
const t0_cb = Date.now();
|
|
1565
|
-
if (callback) callback(cmd);
|
|
1566
|
-
const cb = Date.now() - t0_cb;
|
|
1567
|
-
const t0_postcb = Date.now();
|
|
1568
|
-
if (cmd.features.isUtilsEnabled) addUtilCommands(cmd);
|
|
1569
|
-
if (cmd.features.isAutoAssignSubCommandAliasesEnabled) {
|
|
1570
|
-
autoAssignSubCommandAliases(cmd);
|
|
1571
|
-
}
|
|
1572
|
-
if (cmd.features.isAutoAssignMissingOptionFlagsEnabled) {
|
|
1573
|
-
autoAssignMissingOptionFlags(cmd);
|
|
1574
|
-
}
|
|
1575
|
-
assertNoDuplicateCommandNames(cmd);
|
|
1576
|
-
assertNoDuplicateOptionNames(cmd);
|
|
1577
|
-
const postcb = Date.now() - t0_postcb;
|
|
1578
|
-
if (precb + cb + postcb > 10) cmd.outputDebugInfo('init timer', ()=>({
|
|
1579
|
-
precb,
|
|
1580
|
-
cb,
|
|
1581
|
-
postcb
|
|
1582
|
-
}));
|
|
1583
|
-
return cmd;
|
|
1584
|
-
}
|
|
1585
|
-
function inheritBasicSettings(cmd) {
|
|
1586
|
-
if (!cmd.parent) return;
|
|
1587
|
-
const cmdr = cmd.$;
|
|
1588
|
-
if (cmdr.parent) cmdr.copyInheritedSettings(cmdr.parent);
|
|
1589
|
-
}
|
|
1590
|
-
function inheritHiddenGlobalOptions(cmd) {
|
|
1591
|
-
if (!cmd.parent) return;
|
|
1592
|
-
for (const opt of cmd.parent.meta.hiddenGlobalOptions){
|
|
1593
|
-
cmd.meta.hiddenGlobalOptions.add(opt);
|
|
1594
|
-
}
|
|
1595
1167
|
}
|
|
1596
1168
|
|
|
1597
1169
|
/**
|
|
1598
|
-
*
|
|
1599
|
-
|
|
1170
|
+
* Edit a JSON-stringify-compatible value in the user's editor and return the (JSON.parse'd) result.
|
|
1171
|
+
*
|
|
1172
|
+
* @param value - The value to edit (NOT a json string). Defaults to an empty object.
|
|
1173
|
+
* @param editor - Launch command to start your editor. Defaults to VSCode: 'code -w' (if installed).
|
|
1174
|
+
* - Otherwise this logic: isWindows() ? 'notepad' : isOSX() ? 'open vi' : 'xdg-open'
|
|
1175
|
+
*
|
|
1176
|
+
* @example ```ts
|
|
1177
|
+
* promptUserEditJsonInTextEditorSync([1, 2])
|
|
1178
|
+
* ```
|
|
1179
|
+
*/ function promptUserEditJsonInTextEditorSync(value = {}, editor) {
|
|
1180
|
+
const json = promptUserEditInTextEditorSync({
|
|
1181
|
+
editor,
|
|
1182
|
+
content: JSON.stringify(value, null, 2),
|
|
1183
|
+
extension: '.json'
|
|
1184
|
+
});
|
|
1185
|
+
return JSON.parse(json);
|
|
1600
1186
|
}
|
|
1601
1187
|
|
|
1602
1188
|
/**
|
|
1603
|
-
* A class that represents
|
|
1604
|
-
*/ class AbstractJsonFileSection
|
|
1605
|
-
|
|
1606
|
-
|
|
1189
|
+
* A class that represents a section of the JSON file used as a simple database.
|
|
1190
|
+
*/ class AbstractJsonFileSection {
|
|
1191
|
+
/**
|
|
1192
|
+
* Creates an instance of AbstractJsonFileSection.
|
|
1193
|
+
* @param file - The parent JsonFile instance.
|
|
1194
|
+
* @param name - The name of the section.
|
|
1195
|
+
* @param keysAreFixed - Indicates whether the keys in the section are fixed.
|
|
1196
|
+
*/ constructor(file, name, keysAreFixed){
|
|
1197
|
+
this.file = file;
|
|
1198
|
+
this.name = name;
|
|
1199
|
+
this.keysAreFixed = keysAreFixed;
|
|
1200
|
+
this.isInitialized = false;
|
|
1201
|
+
this.defaultValues = {};
|
|
1202
|
+
this.prefixBaseString = file.cmd.getPrefixArray().join('_');
|
|
1607
1203
|
}
|
|
1608
1204
|
/**
|
|
1609
|
-
*
|
|
1610
|
-
|
|
1205
|
+
* The JsonDB associated with the section.
|
|
1206
|
+
*/ get db() {
|
|
1207
|
+
return this.file.db;
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* The CommandBuilder associated with the section.
|
|
1211
|
+
*/ get cmd() {
|
|
1212
|
+
return this.file.cmd;
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Saves the section.
|
|
1216
|
+
* @returns A promise that resolves when the section is saved.
|
|
1217
|
+
*/ async save() {
|
|
1218
|
+
return await this.db.save();
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Gets the object path prefix as dot-separated keys for this section of the JSON file database.
|
|
1222
|
+
* @param key - An optional key to append to the prefix path.
|
|
1223
|
+
* @returns The object path prefix.
|
|
1224
|
+
* @throws An error if the keys are fixed and the specified key does not exist in the default values.
|
|
1611
1225
|
*/ prefix(key) {
|
|
1612
|
-
if (this.
|
|
1613
|
-
throw new
|
|
1226
|
+
if (this.keysAreFixed && key && !Object.hasOwn(this.defaultValues, key)) {
|
|
1227
|
+
throw new Error(`No entry with key '${key}'`);
|
|
1614
1228
|
}
|
|
1615
|
-
return this.name + (key ? '.' + key : '');
|
|
1229
|
+
return this.prefixBaseString + '.' + this.name + (key ? '.' + key : '');
|
|
1616
1230
|
}
|
|
1617
|
-
|
|
1231
|
+
/**
|
|
1232
|
+
* Gets the value associated with the specified key.
|
|
1233
|
+
* @param key - The key to get the value for.
|
|
1234
|
+
* @returns The value associated with the key.
|
|
1235
|
+
*/ get(key) {
|
|
1618
1236
|
this.initialize(false);
|
|
1619
|
-
|
|
1620
|
-
return (_this_file_db_getSafe = this.file.db.getSafe(this.prefix(key))) != null ? _this_file_db_getSafe : this.defaultValues[key];
|
|
1237
|
+
return this.db.getSafe(this.prefix(key)) ?? this.defaultValues[key];
|
|
1621
1238
|
}
|
|
1622
|
-
|
|
1239
|
+
/**
|
|
1240
|
+
* Gets all the values in the section.
|
|
1241
|
+
* @returns All the values in the section.
|
|
1242
|
+
*/ getAll() {
|
|
1623
1243
|
this.initialize(false);
|
|
1624
|
-
|
|
1625
|
-
return (_this_file_db_getSafe = this.file.db.getSafe(this.prefix())) != null ? _this_file_db_getSafe : this.defaultValues;
|
|
1244
|
+
return this.db.getSafe(this.prefix()) ?? JSON.parse(JSON.stringify(this.defaultValues));
|
|
1626
1245
|
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1246
|
+
/**
|
|
1247
|
+
* Gets the keys in the section.
|
|
1248
|
+
* @returns The keys in the section.
|
|
1249
|
+
*/ get keys() {
|
|
1250
|
+
// if (this.keysAreFixed) return Object.keys(this.defaultValues)
|
|
1251
|
+
return Object.keys(this.getAll());
|
|
1629
1252
|
}
|
|
1630
|
-
|
|
1253
|
+
/**
|
|
1254
|
+
* Gets the number of keys in the section.
|
|
1255
|
+
* @returns The number of keys in the section.
|
|
1256
|
+
*/ count() {
|
|
1257
|
+
return this.keys.length;
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Sets the value associated with the specified key.
|
|
1261
|
+
* @param key - The key to set the value for.
|
|
1262
|
+
* @param value - The value to set.
|
|
1263
|
+
* @param save - Indicates whether to save the section after setting the value.
|
|
1264
|
+
*/ set(key, value, save = true) {
|
|
1631
1265
|
this.initialize();
|
|
1632
1266
|
this.assertValid(key, value);
|
|
1633
|
-
this.
|
|
1267
|
+
this.db.set(this.prefix(key), value, save);
|
|
1634
1268
|
}
|
|
1635
|
-
|
|
1269
|
+
/**
|
|
1270
|
+
* Sets all the values in the section.
|
|
1271
|
+
* @param values - The values to set.
|
|
1272
|
+
* @param save - Indicates whether to save the section after setting the values.
|
|
1273
|
+
*/ setAll(values, save = true) {
|
|
1636
1274
|
const original = this.getAll();
|
|
1637
1275
|
for (const [key, value] of Object.entries(values)){
|
|
1276
|
+
if (value === original[key]) continue;
|
|
1638
1277
|
if (JSON.stringify(value) === JSON.stringify(original[key])) continue;
|
|
1639
1278
|
this.set(key, value, false);
|
|
1640
1279
|
}
|
|
1641
|
-
if (!this.
|
|
1280
|
+
if (!this.keysAreFixed) {
|
|
1642
1281
|
for (const name of Object.keys(original)){
|
|
1643
1282
|
if (Object.hasOwn(values, name)) continue;
|
|
1644
1283
|
this.delete(name, false);
|
|
@@ -1646,122 +1285,208 @@ function inheritHiddenGlobalOptions(cmd) {
|
|
|
1646
1285
|
}
|
|
1647
1286
|
if (save) this.save();
|
|
1648
1287
|
}
|
|
1649
|
-
|
|
1288
|
+
/**
|
|
1289
|
+
* Updates the value associated with the specified key.
|
|
1290
|
+
* @param key - The key to set the value for.
|
|
1291
|
+
* @param callback - The callback function that returns the new value.
|
|
1292
|
+
* @param save - Indicates whether to save the section after setting the value.
|
|
1293
|
+
*/ update(key, callback, save = true) {
|
|
1294
|
+
this.set(key, callback(this.get(key), key), save);
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Resets the value associated with the specified key to its default value.
|
|
1298
|
+
* @param key - The key to reset.
|
|
1299
|
+
* @param save - Indicates whether to save the section after resetting the value.
|
|
1300
|
+
*/ reset(key, save = true) {
|
|
1650
1301
|
this.set(key, this.defaultValues[key], save);
|
|
1651
1302
|
}
|
|
1652
|
-
|
|
1303
|
+
/**
|
|
1304
|
+
* Resets all the values in the section to their default values.
|
|
1305
|
+
* @param save - Indicates whether to save the section after resetting the values.
|
|
1306
|
+
*/ resetAll(save = true) {
|
|
1653
1307
|
this.setAll(this.defaultValues, save);
|
|
1654
1308
|
}
|
|
1655
1309
|
/**
|
|
1656
|
-
*
|
|
1657
|
-
* -
|
|
1658
|
-
* -
|
|
1659
|
-
|
|
1660
|
-
*/ save() {
|
|
1661
|
-
this.file.db.save();
|
|
1662
|
-
}
|
|
1663
|
-
delete(key, save = true) {
|
|
1310
|
+
* Deletes the value associated with the specified key.
|
|
1311
|
+
* @param key - The key to delete.
|
|
1312
|
+
* @param save - Indicates whether to save the section after deleting the value.
|
|
1313
|
+
*/ delete(key, save = true) {
|
|
1664
1314
|
this.initialize();
|
|
1665
|
-
this.
|
|
1315
|
+
this.db.delete(this.prefix(key), save);
|
|
1666
1316
|
}
|
|
1667
|
-
|
|
1668
|
-
|
|
1317
|
+
/**
|
|
1318
|
+
* Deletes all the values in the section.
|
|
1319
|
+
* @param save - Indicates whether to save the section after deleting the values.
|
|
1320
|
+
*/ deleteAll(save = true) {
|
|
1321
|
+
for (const key of this.keys){
|
|
1669
1322
|
this.delete(key, false);
|
|
1670
1323
|
}
|
|
1671
1324
|
if (save) this.save();
|
|
1672
1325
|
}
|
|
1673
|
-
|
|
1326
|
+
/**
|
|
1327
|
+
* Edits the values in the section using a text editor.
|
|
1328
|
+
* @param editor - The text editor to use. If not specified, the default text editor command will be used.
|
|
1329
|
+
*/ edit(editor) {
|
|
1674
1330
|
const original = this.getAll();
|
|
1675
|
-
const parsed =
|
|
1331
|
+
const parsed = promptUserEditJsonInTextEditorSync(original, editor || defaultOpenInEditorCommand());
|
|
1676
1332
|
this.setAll(parsed);
|
|
1677
1333
|
}
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
/**
|
|
1337
|
+
* A class that represents the appdata section of the JSON file used as simple database.
|
|
1338
|
+
*/ class AppDataSection extends AbstractJsonFileSection {
|
|
1678
1339
|
/**
|
|
1679
|
-
*
|
|
1680
|
-
* @param
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1340
|
+
* Creates an instance of AppDataSection.
|
|
1341
|
+
* @param file - The parent JsonFile instance.
|
|
1342
|
+
* @param name - The name of the section.
|
|
1343
|
+
*/ constructor(file, name){
|
|
1344
|
+
super(file, name, false);
|
|
1345
|
+
countInstance(AppDataSection);
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Does nothing
|
|
1349
|
+
*/ assertValid() {
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Defines a property for the section.
|
|
1354
|
+
* @param key - The key of the property.
|
|
1355
|
+
*/ defineProperty(key, value) {
|
|
1356
|
+
if (typeof value === 'object') value = JSON.parse(JSON.stringify(value));
|
|
1357
|
+
this.defaultValues[key] = value;
|
|
1686
1358
|
this.isInitialized = false;
|
|
1687
|
-
|
|
1688
|
-
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Initializes the section.
|
|
1362
|
+
* @param save - Indicates whether to save the section after initialization.
|
|
1363
|
+
* @returns A string if an error occurred during initialization, otherwise void.
|
|
1364
|
+
*/ initialize(save = false) {
|
|
1365
|
+
if (this.isInitialized) return;
|
|
1366
|
+
const data = this.db.getSafe(this.prefix());
|
|
1367
|
+
if (!data) this.db.set(this.prefix(), this.defaultValues, save);
|
|
1368
|
+
this.isInitialized = true;
|
|
1689
1369
|
}
|
|
1690
1370
|
}
|
|
1691
1371
|
|
|
1372
|
+
/**
|
|
1373
|
+
* Creates a function that merges objects based on a predicate function.
|
|
1374
|
+
*/ function createObjectMerger(predicate) {
|
|
1375
|
+
return function objMerge(target, ...sources) {
|
|
1376
|
+
for (const src of sources){
|
|
1377
|
+
for (const [key, value] of Object.entries(src)){
|
|
1378
|
+
if (predicate(value, key, src)) {
|
|
1379
|
+
target[key] = value;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
return target;
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
const objAssign = createObjectMerger((value)=>value != null);
|
|
1388
|
+
|
|
1692
1389
|
/**
|
|
1693
1390
|
* A class that represents the user-config section of the JSON file used as simple database.
|
|
1694
1391
|
*/ class ConfigSection extends AbstractJsonFileSection {
|
|
1695
|
-
|
|
1392
|
+
/**
|
|
1393
|
+
* Creates an instance of AbstractJsonFileSection.
|
|
1394
|
+
* @param file - The parent JsonFile instance.
|
|
1395
|
+
* @param name - The name of the section.
|
|
1396
|
+
*/ constructor(file, name){
|
|
1397
|
+
super(file, name, true);
|
|
1398
|
+
/**
|
|
1399
|
+
* String parsers for when editing config from command-line.
|
|
1400
|
+
*/ this.parsers = {};
|
|
1401
|
+
/**
|
|
1402
|
+
* Descriptions for each property key.
|
|
1403
|
+
*/ this.descriptions = {};
|
|
1404
|
+
/**
|
|
1405
|
+
* Validators for each property key.
|
|
1406
|
+
*/ this.validators = {};
|
|
1407
|
+
countInstance(ConfigSection);
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Asserts that a key-value pair is valid.
|
|
1411
|
+
* @param key - The key to assert.
|
|
1412
|
+
* @param value - The value to assert.
|
|
1413
|
+
*/ assertValid(key, value) {
|
|
1696
1414
|
if (!this.validators[key]) return;
|
|
1697
|
-
|
|
1415
|
+
ensureThat(value, this.validators[key]);
|
|
1698
1416
|
}
|
|
1699
|
-
|
|
1417
|
+
/**
|
|
1418
|
+
* Defines a property for the section.
|
|
1419
|
+
* @param key - The key of the property.
|
|
1420
|
+
* @param options - The options for the property.
|
|
1421
|
+
*/ defineProperty(key, options) {
|
|
1700
1422
|
const { description, defaultValue, parse, validate } = options;
|
|
1701
|
-
this.
|
|
1702
|
-
this.
|
|
1703
|
-
this.
|
|
1704
|
-
this.
|
|
1423
|
+
this.descriptions[key] = description;
|
|
1424
|
+
this.defaultValues[key] = typeof defaultValue === 'object' ? JSON.parse(JSON.stringify(defaultValue)) : defaultValue;
|
|
1425
|
+
if (parse) this.parsers[key] = parse;
|
|
1426
|
+
if (validate) this.validators[key] = validate;
|
|
1705
1427
|
this.assertValid(key, options.defaultValue);
|
|
1706
1428
|
}
|
|
1707
|
-
|
|
1429
|
+
/**
|
|
1430
|
+
* Initializes the section.
|
|
1431
|
+
* @param save - Indicates whether to save the section after initialization.
|
|
1432
|
+
* @returns A string if an error occurred during initialization, otherwise void.
|
|
1433
|
+
*/ initialize(save = false) {
|
|
1708
1434
|
if (this.isInitialized) return;
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
var _this_file_db_getSafe;
|
|
1713
|
-
const values = (_this_file_db_getSafe = this.file.db.getSafe(this.prefix())) != null ? _this_file_db_getSafe : this.defaultValues;
|
|
1714
|
-
const config = {};
|
|
1715
|
-
for (const key of Object.keys(this.defaultValues)){
|
|
1716
|
-
if (values[key] != null) {
|
|
1717
|
-
config[key] = values[key];
|
|
1718
|
-
} else {
|
|
1719
|
-
config[key] = this.defaultValues[key];
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
this.file.db.set(this.prefix(), config, save);
|
|
1435
|
+
const data = this.db.getSafe(this.prefix());
|
|
1436
|
+
const result = objAssign({}, JSON.parse(JSON.stringify(this.defaultValues)), data || {});
|
|
1437
|
+
this.db.set(this.prefix(), result, save);
|
|
1723
1438
|
this.isInitialized = true;
|
|
1724
1439
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
// defaultValue: defaultOpenInEditorCommand() as Val,
|
|
1739
|
-
// parse: parseString,
|
|
1740
|
-
// })
|
|
1741
|
-
// }
|
|
1742
|
-
if (file.cmd.features.isPresetsEnabled) {
|
|
1743
|
-
this.defineProperty('disabledBuiltinPresets', {
|
|
1744
|
-
description: 'Builtin presets that are disabled.',
|
|
1745
|
-
defaultValue: [],
|
|
1746
|
-
parse: createTypedListParser(',', parseString),
|
|
1747
|
-
validate: function isArrayOfPresetNames(value) {
|
|
1748
|
-
if (!Array.isArray(value)) return false;
|
|
1749
|
-
return value.every((name)=>{
|
|
1750
|
-
return Object.hasOwn(file.presets.defaultValues, name);
|
|
1751
|
-
});
|
|
1752
|
-
}
|
|
1753
|
-
});
|
|
1754
|
-
}
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/**
|
|
1443
|
+
* Reads a JSON file and then parses it into an object.
|
|
1444
|
+
* If an error occurs, it returns undefined.
|
|
1445
|
+
*
|
|
1446
|
+
* @param filepath - The path to the JSON file.
|
|
1447
|
+
* @param options - Options for reading the JSON file.
|
|
1448
|
+
*/ function readJsonFileSafeSync(filepath, options) {
|
|
1449
|
+
try {
|
|
1450
|
+
return fs__default["default"].readJsonSync(filepath, options);
|
|
1451
|
+
} catch (error) {
|
|
1452
|
+
return undefined;
|
|
1755
1453
|
}
|
|
1756
1454
|
}
|
|
1757
1455
|
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1456
|
+
/**
|
|
1457
|
+
* Represents a simple JSON file database.
|
|
1458
|
+
*/ class JsonDB {
|
|
1459
|
+
/**
|
|
1460
|
+
* Creates a new instance of the JsonDB class.
|
|
1461
|
+
* @param filepath - The filepath where the data file is stored or to be stored.
|
|
1462
|
+
*/ constructor(filepath, indents = 0){
|
|
1463
|
+
this.filepath = filepath;
|
|
1464
|
+
this.indents = indents;
|
|
1465
|
+
this.data = readJsonFileSafeSync(this.filepath) ?? {};
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Saves the data to the JSON file.
|
|
1469
|
+
*/ async save(indents = this.indents) {
|
|
1470
|
+
return await fs.outputJson(this.filepath, this.data, {
|
|
1471
|
+
spaces: indents
|
|
1472
|
+
});
|
|
1761
1473
|
}
|
|
1762
|
-
|
|
1474
|
+
/**
|
|
1475
|
+
* Sets the filepath of the JSON file.
|
|
1476
|
+
* @param filepath - The new filepath.
|
|
1477
|
+
*/ setFilepath(filepath, save = true) {
|
|
1478
|
+
if (this.filepath === filepath) return;
|
|
1479
|
+
this.filepath = filepath;
|
|
1480
|
+
if (save) this.save();
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Sets a value in the JSON database.
|
|
1484
|
+
* @param prefix - Object path prefix as dot-separated keys.
|
|
1485
|
+
* @param value - The value to set.
|
|
1486
|
+
* @param save - Whether to save the data to the JSON file.
|
|
1487
|
+
*/ set(prefix, value = {}, save = true) {
|
|
1763
1488
|
if (!prefix) {
|
|
1764
|
-
this.data =
|
|
1489
|
+
this.data = ensureThat(value, isObject);
|
|
1765
1490
|
} else {
|
|
1766
1491
|
const keys = prefix.split('.');
|
|
1767
1492
|
const lastKey = keys.pop();
|
|
@@ -1776,12 +1501,21 @@ class JsonDB extends Base {
|
|
|
1776
1501
|
}
|
|
1777
1502
|
if (save) this.save();
|
|
1778
1503
|
}
|
|
1779
|
-
|
|
1504
|
+
/**
|
|
1505
|
+
* Gets a value from the JSON database.
|
|
1506
|
+
* @param prefix - Object path prefix as dot-separated keys.
|
|
1507
|
+
* @returns The value associated with the key.
|
|
1508
|
+
* @throws An error if no entry is found at the specified key.
|
|
1509
|
+
*/ get(prefix) {
|
|
1780
1510
|
const value = this.getSafe(prefix);
|
|
1781
|
-
if (value === undefined) throw new Error(`No
|
|
1782
|
-
return value;
|
|
1511
|
+
if (value === undefined) throw new Error(`No entry at '${prefix}'`);
|
|
1512
|
+
return this.cloneDeep(value);
|
|
1783
1513
|
}
|
|
1784
|
-
|
|
1514
|
+
/**
|
|
1515
|
+
* Gets a value from the JSON database safely.
|
|
1516
|
+
* @param prefix - Object path prefix as dot-separated keys.
|
|
1517
|
+
* @returns The value associated with the key, or undefined if no entry is found.
|
|
1518
|
+
*/ getSafe(prefix) {
|
|
1785
1519
|
if (!prefix) return this.cloneDeep(this.data);
|
|
1786
1520
|
const keys = prefix.split('.');
|
|
1787
1521
|
let node = this.data;
|
|
@@ -1793,11 +1527,19 @@ class JsonDB extends Base {
|
|
|
1793
1527
|
}
|
|
1794
1528
|
return this.cloneDeep(node);
|
|
1795
1529
|
}
|
|
1796
|
-
|
|
1530
|
+
/**
|
|
1531
|
+
* Checks if a key exists in the JSON database.
|
|
1532
|
+
* @param prefix - Object path prefix as dot-separated keys.
|
|
1533
|
+
* @returns True if the key exists, false otherwise.
|
|
1534
|
+
*/ has(prefix) {
|
|
1797
1535
|
if (!prefix) return true;
|
|
1798
1536
|
return this.getSafe(prefix) !== undefined;
|
|
1799
1537
|
}
|
|
1800
|
-
|
|
1538
|
+
/**
|
|
1539
|
+
* Deletes a value from the JSON database.
|
|
1540
|
+
* @param prefix - Object path prefix as dot-separated keys.
|
|
1541
|
+
* @param save - Whether to save the data to the JSON file.
|
|
1542
|
+
*/ delete(prefix, save = true) {
|
|
1801
1543
|
if (!prefix) {
|
|
1802
1544
|
this.data = {};
|
|
1803
1545
|
} else {
|
|
@@ -1814,160 +1556,112 @@ class JsonDB extends Base {
|
|
|
1814
1556
|
}
|
|
1815
1557
|
if (save) this.save();
|
|
1816
1558
|
}
|
|
1817
|
-
cloneDeep(obj) {
|
|
1818
|
-
return JSON.parse(JSON.stringify(obj));
|
|
1819
|
-
}
|
|
1820
1559
|
/**
|
|
1821
|
-
*
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1828
|
-
const [queue, writeJsonFileSafeLimited] = util.funAsyncRateLimit(util.writeJsonFileSafe, {
|
|
1829
|
-
concurrency: 1,
|
|
1830
|
-
autoStart: true,
|
|
1831
|
-
timeout: 3000,
|
|
1832
|
-
throwOnTimeout: true
|
|
1833
|
-
});
|
|
1834
|
-
const opts = {
|
|
1835
|
-
spaces: 2
|
|
1836
|
-
};
|
|
1837
|
-
this.save = ()=>{
|
|
1838
|
-
writeJsonFileSafeLimited(this.filepath, this.data, opts).catch((err)=>{
|
|
1839
|
-
var _err;
|
|
1840
|
-
this.file.cmd.outputUserError(((_err = err) == null ? void 0 : _err.message) || String(err));
|
|
1841
|
-
});
|
|
1842
|
-
};
|
|
1843
|
-
// const cmdr = getCommander(this.file.cmd)
|
|
1844
|
-
// const awaitQueue = async () => await queue.onIdle()
|
|
1845
|
-
// process.on('exit', awaitQueue)
|
|
1846
|
-
// cmdr.exitOverride(awaitQueue)
|
|
1560
|
+
* Creates a deep clone of an object.
|
|
1561
|
+
* @param obj - The object to clone.
|
|
1562
|
+
* @returns The cloned object.
|
|
1563
|
+
*/ cloneDeep(obj) {
|
|
1564
|
+
if (typeof obj !== 'object') return obj;
|
|
1565
|
+
return JSON.parse(JSON.stringify(obj));
|
|
1847
1566
|
}
|
|
1848
1567
|
}
|
|
1849
1568
|
|
|
1850
|
-
function assertPresetArgsOptional(cmd, args) {
|
|
1851
|
-
args.forEach((arg, i)=>{
|
|
1852
|
-
if (arg != null && i < cmd.arguments.length && cmd.arguments[i].required) {
|
|
1853
|
-
throw new Error(`Cannot preset required arguments.`);
|
|
1854
|
-
}
|
|
1855
|
-
});
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
const isArray = Array.isArray;
|
|
1859
|
-
|
|
1860
|
-
/**
|
|
1861
|
-
* Determine whether the input is a string array.
|
|
1862
|
-
*/ function isStringArray(value) {
|
|
1863
|
-
return Array.isArray(value) && value.every((v)=>isString(v));
|
|
1864
|
-
}
|
|
1865
|
-
|
|
1866
|
-
function isStringWithNoSpacesOrDashes(value) {
|
|
1867
|
-
return isString(value) && /^[^\s-]+$/i.test(value);
|
|
1868
|
-
}
|
|
1869
|
-
|
|
1870
|
-
function assertValidPreset(cmd, key, preset) {
|
|
1871
|
-
const { description, presets, args, options } = preset;
|
|
1872
|
-
util.assertThat(key, isStringWithNoSpacesOrDashes);
|
|
1873
|
-
util.assertThat(description, isString);
|
|
1874
|
-
util.assertThat(presets, isStringArray);
|
|
1875
|
-
util.assertThat(args, isArray);
|
|
1876
|
-
assertPresetArgsOptional(cmd, args);
|
|
1877
|
-
assertValidArguments(cmd, args);
|
|
1878
|
-
util.assertThat(options, util.isObject);
|
|
1879
|
-
assertValidOptions(cmd, options);
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
function createObjectMerger(predicate) {
|
|
1883
|
-
return function objMerge(target, ...sources) {
|
|
1884
|
-
for (const src of sources){
|
|
1885
|
-
for (const [key, value] of Object.entries(src)){
|
|
1886
|
-
if (predicate(value, key, src)) {
|
|
1887
|
-
target[key] = value;
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
|
-
return target;
|
|
1892
|
-
};
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1895
|
-
const objAssign = createObjectMerger((value)=>value != null);
|
|
1896
|
-
|
|
1897
1569
|
/**
|
|
1898
1570
|
* A class that represents the user-presets section of the JSON file used as simple database.
|
|
1899
1571
|
*/ class PresetsSection extends AbstractJsonFileSection {
|
|
1900
|
-
|
|
1901
|
-
|
|
1572
|
+
/**
|
|
1573
|
+
* Creates an instance of AppDataSection.
|
|
1574
|
+
* @param file - The parent JsonFile instance.
|
|
1575
|
+
* @param name - The name of the section.
|
|
1576
|
+
*/ constructor(file, name){
|
|
1577
|
+
super(file, name, false);
|
|
1578
|
+
countInstance(PresetsSection);
|
|
1579
|
+
this.defineProperty('defaults', {
|
|
1580
|
+
description: 'All presets inherit from this preset',
|
|
1581
|
+
presets: [],
|
|
1582
|
+
args: this.cmd.arguments.map((arg)=>arg.defaultValue ?? null),
|
|
1583
|
+
options: this.cmd.getOwnAndGlobalOptions().reduce((acc, opt)=>{
|
|
1584
|
+
acc[opt.attributeName()] = opt.defaultValue ?? (opt.isBoolean() ? false : null);
|
|
1585
|
+
return acc;
|
|
1586
|
+
}, {})
|
|
1587
|
+
});
|
|
1902
1588
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1589
|
+
/**
|
|
1590
|
+
* Asserts that a key-value pair is valid.
|
|
1591
|
+
* @param key - The key to assert.
|
|
1592
|
+
* @param value - The preset options to validate.
|
|
1593
|
+
*/ assertValid(key, value) {
|
|
1594
|
+
this.cmd.assertValidPreset(key, value);
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Defines a property for the section.
|
|
1598
|
+
* @param key - The key of the property.
|
|
1599
|
+
* @param options - The options for the property.
|
|
1600
|
+
*/ defineProperty(key, options) {
|
|
1601
|
+
if (this.defaultValues[key]) throw new Error(`Cannot redefine preset '${key}'.`);
|
|
1602
|
+
this.defaultValues[key] = JSON.parse(JSON.stringify(options));
|
|
1905
1603
|
this.assertValid(key, options);
|
|
1906
1604
|
this.isInitialized = false;
|
|
1907
1605
|
}
|
|
1908
|
-
|
|
1606
|
+
/**
|
|
1607
|
+
* Initializes the section.
|
|
1608
|
+
* @param save - Indicates whether to save the section after initialization.
|
|
1609
|
+
* @returns A string if an error occurred during initialization, otherwise void.
|
|
1610
|
+
*/ initialize(save = false) {
|
|
1909
1611
|
if (this.isInitialized) return;
|
|
1910
|
-
const data = this.
|
|
1911
|
-
const
|
|
1912
|
-
const
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
}
|
|
1921
|
-
// merge data
|
|
1922
|
-
if (hasData) {
|
|
1923
|
-
// presets['defaults'].args = arrAssign([], this.defaultValues['defaults'].args, presets['defaults'].args)
|
|
1924
|
-
// presets['defaults'].options = objAssign({}, this.defaultValues['defaults'].options, presets['defaults'].options)
|
|
1925
|
-
// for (const preset of Object.values(presets)) {
|
|
1926
|
-
// preset.args = arrAssign([], this.defaultValues['defaults'].args, preset.args)
|
|
1927
|
-
// preset.options = objAssign({}, this.defaultValues['defaults'].options, preset.options)
|
|
1928
|
-
// preset.presets = preset.presets || this.defaultValues['defaults'].presets
|
|
1929
|
-
// // objAssign(preset.options, this.defaultValues['defaults'].options)
|
|
1930
|
-
// // preset.options = objFilter(preset.options, (_, key) => Object.hasOwn(this.defaultValues, key))
|
|
1931
|
-
// // preset.presets = preset.presets.filter((key: string) => Object.hasOwn(this.defaultValues, key))
|
|
1932
|
-
// }
|
|
1933
|
-
if (JSON.stringify(data) !== JSON.stringify(presets)) {
|
|
1934
|
-
save = true;
|
|
1612
|
+
const data = this.db.getSafe(this.prefix());
|
|
1613
|
+
const presets = objAssign({}, this.defaultValues, data || {});
|
|
1614
|
+
const presetNames = Object.keys(presets);
|
|
1615
|
+
for (const preset of Object.values(presets)){
|
|
1616
|
+
for (const pname of presetNames){
|
|
1617
|
+
if (preset.options[pname]) {
|
|
1618
|
+
preset.presets.push(pname);
|
|
1619
|
+
delete preset.options[pname];
|
|
1620
|
+
save = true;
|
|
1621
|
+
}
|
|
1935
1622
|
}
|
|
1936
1623
|
}
|
|
1937
|
-
this.
|
|
1624
|
+
this.db.set(this.prefix(), presets, save);
|
|
1938
1625
|
this.isInitialized = true;
|
|
1939
1626
|
}
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
if (
|
|
1946
|
-
this.file.config.set('disabledBuiltinPresets', disabled.concat(name), save);
|
|
1947
|
-
}
|
|
1948
|
-
async setAll(presets, save = true) {
|
|
1949
|
-
if (!presets['defaults']) throw new JsonFileError('Missing "defaults" preset');
|
|
1627
|
+
/**
|
|
1628
|
+
* Sets all the values in the section.
|
|
1629
|
+
* @param values - The values to set.
|
|
1630
|
+
* @param save - Indicates whether to save the section after setting the values.
|
|
1631
|
+
*/ async setAll(presets, save = true) {
|
|
1632
|
+
if (!presets['defaults']) presets['defaults'] = JSON.parse(JSON.stringify(this.defaultValues['defaults']));
|
|
1950
1633
|
super.setAll(presets, save);
|
|
1951
1634
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
options: getOwnAndGlobalOptions(this.file.cmd).reduce((acc, opt)=>{
|
|
1960
|
-
var _opt_defaultValue;
|
|
1961
|
-
acc[opt.attributeName()] = (_opt_defaultValue = opt.defaultValue) != null ? _opt_defaultValue : opt.isBoolean() ? false : null;
|
|
1962
|
-
return acc;
|
|
1963
|
-
}, {})
|
|
1964
|
-
});
|
|
1635
|
+
/**
|
|
1636
|
+
* Deletes the value associated with the specified key.
|
|
1637
|
+
* @param key - The key to delete.
|
|
1638
|
+
* @param save - Indicates whether to save the section after deleting the value.
|
|
1639
|
+
*/ delete(name, save = true) {
|
|
1640
|
+
if (Object.hasOwn(this.defaultValues, name)) throw new Error('Cannot delete the builtin presets.');
|
|
1641
|
+
super.delete(name, save);
|
|
1965
1642
|
}
|
|
1966
1643
|
}
|
|
1967
1644
|
|
|
1968
1645
|
/**
|
|
1969
1646
|
* A class that represents the JSON file used as a simple database.
|
|
1970
|
-
*/ class JsonFile
|
|
1647
|
+
*/ class JsonFile {
|
|
1648
|
+
/**
|
|
1649
|
+
* @param cmd The parent CommandBuilder instance.
|
|
1650
|
+
*/ constructor(cmd){
|
|
1651
|
+
this.cmd = cmd;
|
|
1652
|
+
countInstance(JsonFile);
|
|
1653
|
+
}
|
|
1654
|
+
/**
|
|
1655
|
+
* A lazy-loaded instance of the JsonDB instance containing the data.
|
|
1656
|
+
* Upon first property access, it is stored as a property on the instance.
|
|
1657
|
+
* If the command is a subcommand, the root command's JsonDB instance is returned.
|
|
1658
|
+
*/ get db() {
|
|
1659
|
+
if (this.cmd.isRoot) {
|
|
1660
|
+
return realizeLazyProperty(this, 'db', new JsonDB(this.cmd.dataFilepath, 2));
|
|
1661
|
+
} else {
|
|
1662
|
+
return this.cmd.root.db.db;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1971
1665
|
/**
|
|
1972
1666
|
* A lazy-loaded instance of the `config` section of the JSON file.
|
|
1973
1667
|
* Upon first property access, it is stored as a property on the instance.
|
|
@@ -1975,30 +1669,23 @@ const objAssign = createObjectMerger((value)=>value != null);
|
|
|
1975
1669
|
return realizeLazyProperty(this, 'config', new ConfigSection(this, 'config'));
|
|
1976
1670
|
}
|
|
1977
1671
|
/**
|
|
1672
|
+
* A lazy-loaded instance of the `appData` section of the JSON file.
|
|
1673
|
+
* Upon first property access, it is stored as a property on the instance.
|
|
1674
|
+
*/ get appData() {
|
|
1675
|
+
return realizeLazyProperty(this, 'appData', new AppDataSection(this, 'appData'));
|
|
1676
|
+
}
|
|
1677
|
+
/**
|
|
1978
1678
|
* A lazy-loaded instance of the `presets` section of the JSON file.
|
|
1979
1679
|
*/ get presets() {
|
|
1980
1680
|
return realizeLazyProperty(this, 'presets', new PresetsSection(this, 'presets'));
|
|
1981
1681
|
}
|
|
1982
|
-
/**
|
|
1983
|
-
* @param cmd The parent CommandBuilder instance.
|
|
1984
|
-
*/ constructor(cmd){
|
|
1985
|
-
super();
|
|
1986
|
-
this.cmd = cmd;
|
|
1987
|
-
this.db = new JsonDB(this);
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1990
|
-
|
|
1991
|
-
function objDestroy(obj) {
|
|
1992
|
-
for (const key of Reflect.ownKeys(obj)){
|
|
1993
|
-
Reflect.deleteProperty(obj, key);
|
|
1994
|
-
}
|
|
1995
1682
|
}
|
|
1996
1683
|
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
1684
|
+
class OptionArgumentParserSelector extends ParserSelector {
|
|
1685
|
+
constructor(builder){
|
|
1686
|
+
super(builder);
|
|
1687
|
+
countInstance(OptionArgumentParserSelector);
|
|
1688
|
+
}
|
|
2002
1689
|
custom(parser) {
|
|
2003
1690
|
const name = this.builder.$.attributeName();
|
|
2004
1691
|
this.builder.cmd.meta.optParsers[name] = parser;
|
|
@@ -2006,7 +1693,11 @@ class OptionArgumentParserSelector extends AbstractStringParserSelector {
|
|
|
2006
1693
|
}
|
|
2007
1694
|
}
|
|
2008
1695
|
|
|
2009
|
-
class OptionArgumentValidatorSelector extends
|
|
1696
|
+
class OptionArgumentValidatorSelector extends ValidatorSelector {
|
|
1697
|
+
constructor(builder){
|
|
1698
|
+
super(builder);
|
|
1699
|
+
countInstance(OptionArgumentValidatorSelector);
|
|
1700
|
+
}
|
|
2010
1701
|
custom(validator) {
|
|
2011
1702
|
const name = this.builder.$.attributeName();
|
|
2012
1703
|
const obj = this.builder.cmd.meta.optValidators;
|
|
@@ -2016,7 +1707,55 @@ class OptionArgumentValidatorSelector extends AbstractValidatorSelector {
|
|
|
2016
1707
|
}
|
|
2017
1708
|
}
|
|
2018
1709
|
|
|
2019
|
-
|
|
1710
|
+
/**
|
|
1711
|
+
* Extract the argument name from an option's 'flags' string.
|
|
1712
|
+
*/ function getArgumentName(opt) {
|
|
1713
|
+
const result = arrLast(opt.flags.trim().split(' '));
|
|
1714
|
+
if (/-/.test(result)) return undefined;
|
|
1715
|
+
return result;
|
|
1716
|
+
}
|
|
1717
|
+
/**
|
|
1718
|
+
* Check if an option has an argument.
|
|
1719
|
+
*/ function hasArgument(opt) {
|
|
1720
|
+
return /[<>[\]]/.test(opt.flags);
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Update an Option's 'flags' property from its 'short' and 'long' properties.
|
|
1724
|
+
* The flags property is not automatically updated when 'short' or 'long' are changed.
|
|
1725
|
+
*/ function renderFlags(opt) {
|
|
1726
|
+
const shortLong = [];
|
|
1727
|
+
if (opt.short) shortLong.push(opt.short);
|
|
1728
|
+
if (opt.long) shortLong.push(opt.long);
|
|
1729
|
+
const argName = getArgumentName(opt);
|
|
1730
|
+
return shortLong.join(', ') + (argName ? ' ' + argName : '');
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Set an Option's 'long' name. The 'flags' property is updated accordingly.
|
|
1734
|
+
* The '--' prefix is automatically added if not present.
|
|
1735
|
+
*/ function setLong(opt, long) {
|
|
1736
|
+
opt.long = strEnsureStartsWith(long, '--').replace(/^-+/, '--');
|
|
1737
|
+
opt.flags = renderFlags(opt);
|
|
1738
|
+
}
|
|
1739
|
+
/**
|
|
1740
|
+
* Set an Option's 'short' name. The 'flags' property is updated accordingly.
|
|
1741
|
+
* The '-' prefix is automatically added if not present.
|
|
1742
|
+
*/ function setShort(opt, short) {
|
|
1743
|
+
opt.short = strEnsureStartsWith(short, '-').replace(/^-+/, '-');
|
|
1744
|
+
opt.flags = renderFlags(opt);
|
|
1745
|
+
}
|
|
1746
|
+
const OptionHelpers = {
|
|
1747
|
+
getArgumentName,
|
|
1748
|
+
hasArgument,
|
|
1749
|
+
renderFlags,
|
|
1750
|
+
setLong,
|
|
1751
|
+
setShort
|
|
1752
|
+
};
|
|
1753
|
+
|
|
1754
|
+
class OptionReader {
|
|
1755
|
+
constructor(parent){
|
|
1756
|
+
this.parent = parent;
|
|
1757
|
+
countInstance(OptionReader);
|
|
1758
|
+
}
|
|
2020
1759
|
get $() {
|
|
2021
1760
|
return this.parent.$;
|
|
2022
1761
|
}
|
|
@@ -2029,9 +1768,6 @@ class OptionReader extends Base {
|
|
|
2029
1768
|
get optional() {
|
|
2030
1769
|
return this.$.optional;
|
|
2031
1770
|
}
|
|
2032
|
-
// get negate() {
|
|
2033
|
-
// return this.$.negate
|
|
2034
|
-
// }
|
|
2035
1771
|
get mandatory() {
|
|
2036
1772
|
return this.$.mandatory;
|
|
2037
1773
|
}
|
|
@@ -2047,9 +1783,9 @@ class OptionReader extends Base {
|
|
|
2047
1783
|
get long() {
|
|
2048
1784
|
return this.$.long;
|
|
2049
1785
|
}
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
1786
|
+
get preset() {
|
|
1787
|
+
return this.$.presetArg;
|
|
1788
|
+
}
|
|
2053
1789
|
get default() {
|
|
2054
1790
|
return this.$.defaultValue;
|
|
2055
1791
|
}
|
|
@@ -2068,37 +1804,34 @@ class OptionReader extends Base {
|
|
|
2068
1804
|
get attributeName() {
|
|
2069
1805
|
return this.$.attributeName();
|
|
2070
1806
|
}
|
|
2071
|
-
get fullDescription() {
|
|
2072
|
-
return this.$.fullDescription();
|
|
2073
|
-
}
|
|
2074
1807
|
get defaultValueDescription() {
|
|
2075
1808
|
return this.$.defaultValueDescription;
|
|
2076
1809
|
}
|
|
2077
1810
|
get hasArgument() {
|
|
2078
|
-
return
|
|
2079
|
-
}
|
|
2080
|
-
constructor(parent){
|
|
2081
|
-
super();
|
|
2082
|
-
this.parent = parent;
|
|
1811
|
+
return OptionHelpers.hasArgument(this.parent.$);
|
|
2083
1812
|
}
|
|
2084
1813
|
}
|
|
2085
1814
|
|
|
2086
1815
|
/**
|
|
2087
1816
|
* Wrapper around the @see Option class, for more intuitive construction.
|
|
2088
1817
|
* @remarks Options are one of boolean, negated, required argument, or optional argument.
|
|
2089
|
-
*/ class OptionBuilder
|
|
1818
|
+
*/ class OptionBuilder {
|
|
1819
|
+
constructor(cmd, flags){
|
|
1820
|
+
this.cmd = cmd;
|
|
1821
|
+
countInstance(OptionBuilder);
|
|
1822
|
+
this.$ = new commander.Option(flags);
|
|
1823
|
+
if (!OptionHelpers.hasArgument(this.$) && this.$.long?.startsWith('--no-')) {
|
|
1824
|
+
this.$.default(true);
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
2090
1827
|
description(string) {
|
|
2091
1828
|
this.$.description = string;
|
|
2092
1829
|
return this;
|
|
2093
1830
|
}
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
// mandatory(mandatory = true) {
|
|
2099
|
-
// this.$.makeOptionMandatory(mandatory)
|
|
2100
|
-
// return this
|
|
2101
|
-
// }
|
|
1831
|
+
mandatory(mandatory = true) {
|
|
1832
|
+
this.$.makeOptionMandatory(mandatory);
|
|
1833
|
+
return this;
|
|
1834
|
+
}
|
|
2102
1835
|
hideHelp(hide = true) {
|
|
2103
1836
|
this.$.hideHelp(hide);
|
|
2104
1837
|
return this;
|
|
@@ -2107,21 +1840,18 @@ class OptionReader extends Base {
|
|
|
2107
1840
|
this.$.hidden = hidden;
|
|
2108
1841
|
return this;
|
|
2109
1842
|
}
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
1843
|
+
preset(arg) {
|
|
1844
|
+
this.$.preset(arg);
|
|
1845
|
+
return this;
|
|
1846
|
+
}
|
|
2114
1847
|
default(value, description) {
|
|
2115
|
-
if (!optHasArgument(this.$)) {
|
|
2116
|
-
throw new Error('Cannot set default value on option without argument: ' + this.$.name());
|
|
2117
|
-
}
|
|
2118
|
-
if (!this.$.optional) {
|
|
2119
|
-
throw new Error('Cannot set default value on required option: ' + this.$.name());
|
|
2120
|
-
}
|
|
2121
1848
|
this.$.default(value, description);
|
|
2122
1849
|
return this;
|
|
2123
1850
|
}
|
|
2124
1851
|
choices(values) {
|
|
1852
|
+
if (!OptionHelpers.hasArgument(this.$)) {
|
|
1853
|
+
throw new Error('Cannot set choices on option with no argument: ' + this.$.name());
|
|
1854
|
+
}
|
|
2125
1855
|
this.$.choices(values);
|
|
2126
1856
|
return this;
|
|
2127
1857
|
}
|
|
@@ -2138,57 +1868,483 @@ class OptionReader extends Base {
|
|
|
2138
1868
|
return this;
|
|
2139
1869
|
}
|
|
2140
1870
|
short(short) {
|
|
2141
|
-
|
|
1871
|
+
OptionHelpers.setShort(this.$, short);
|
|
2142
1872
|
return this;
|
|
2143
1873
|
}
|
|
2144
1874
|
get parser() {
|
|
2145
|
-
if (this
|
|
2146
|
-
throw new Error('Cannot set parser on
|
|
1875
|
+
if (!OptionHelpers.hasArgument(this.$)) {
|
|
1876
|
+
throw new Error('Cannot set parser on option with no argument: ' + this.$.attributeName());
|
|
2147
1877
|
}
|
|
2148
1878
|
return new OptionArgumentParserSelector(this);
|
|
2149
1879
|
}
|
|
2150
1880
|
get validator() {
|
|
2151
|
-
if (this
|
|
2152
|
-
throw new Error('Cannot set validator on
|
|
1881
|
+
if (!OptionHelpers.hasArgument(this.$)) {
|
|
1882
|
+
throw new Error('Cannot set validator on option with no argument: ' + this.$.attributeName());
|
|
2153
1883
|
}
|
|
2154
1884
|
return new OptionArgumentValidatorSelector(this);
|
|
2155
1885
|
}
|
|
2156
1886
|
get get() {
|
|
2157
1887
|
return realizeLazyProperty(this, 'get', new OptionReader(this));
|
|
2158
1888
|
}
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
/**
|
|
1892
|
+
* Updates the property descriptors of the specified properties on the given object.
|
|
1893
|
+
* @param object - The object whose property descriptors are to be updated.
|
|
1894
|
+
* @param properties - An array of property names for which the descriptors are to be updated.
|
|
1895
|
+
* @param update - A function that takes a property descriptor and a property name, and returns a new property descriptor.
|
|
1896
|
+
* @throws Will throw an error if any of the specified properties do not exist on the object.
|
|
1897
|
+
* @example ```ts
|
|
1898
|
+
* const obj = { a: 1, b: 2 };
|
|
1899
|
+
* objUpdatePropertyDescriptors(obj, ['a', 'b'], (descriptor, property) => {
|
|
1900
|
+
* descriptor.writable = true;
|
|
1901
|
+
* return obj;
|
|
1902
|
+
* });
|
|
1903
|
+
* ```
|
|
1904
|
+
*/ function objUpdatePropertyDescriptors(object, properties, update) {
|
|
1905
|
+
for (const p of properties){
|
|
1906
|
+
if (!Reflect.has(object, p)) {
|
|
1907
|
+
throw new Error(`Property, '${p}' does not exist on object.`);
|
|
2166
1908
|
}
|
|
1909
|
+
const descriptor = update(Object.getOwnPropertyDescriptor(object, p), p);
|
|
1910
|
+
Object.defineProperty(object, p, descriptor);
|
|
2167
1911
|
}
|
|
2168
1912
|
}
|
|
2169
1913
|
|
|
1914
|
+
/**
|
|
1915
|
+
* Sets the specified properties of an object as non-enumerable.
|
|
1916
|
+
* @remarks This function modifies the original object by setting the specified properties as non-enumerable.
|
|
1917
|
+
* If the object or any of the property names are not valid, it throws an error.
|
|
1918
|
+
* @param object The object whose properties are to be set as non-enumerable.
|
|
1919
|
+
* @param properties The names of the properties to be set as non-enumerable.
|
|
1920
|
+
* @throws Will throw an error if any of the specified properties do not exist on the object.
|
|
1921
|
+
* @example ```ts
|
|
1922
|
+
* setNonEnumerable({ a: 1, b: 2, c: 3 }, 'a', 'b');
|
|
1923
|
+
* Object.keys({ a: 1, b: 2, c: 3 });;
|
|
1924
|
+
* //=> ['c']
|
|
1925
|
+
* ```
|
|
1926
|
+
*/ function setNonEnumerable(object, ...properties) {
|
|
1927
|
+
objUpdatePropertyDescriptors(object, properties, (descriptor)=>{
|
|
1928
|
+
descriptor.enumerable = false;
|
|
1929
|
+
return descriptor;
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
|
|
2170
1933
|
/**
|
|
2171
1934
|
* Wrapper around the @see Command class, for more intuitive construction.
|
|
2172
|
-
*/ class CommandBuilder
|
|
1935
|
+
*/ class CommandBuilder {
|
|
1936
|
+
static{
|
|
1937
|
+
this.dataDirectory = path__default["default"].join(os__default["default"].homedir(), 'config', 'cli');
|
|
1938
|
+
}
|
|
2173
1939
|
get db() {
|
|
2174
1940
|
return realizeLazyProperty(this, 'db', new JsonFile(this));
|
|
2175
1941
|
}
|
|
2176
|
-
|
|
2177
|
-
|
|
1942
|
+
constructor(name, callback, parent, isNative = false){
|
|
1943
|
+
this.features = new CommandFeatureSelector(this);
|
|
1944
|
+
this.parent = null;
|
|
1945
|
+
this.meta = new CommandBuilderMetaData();
|
|
1946
|
+
countInstance(CommandBuilder);
|
|
1947
|
+
this.meta.isNative = isNative;
|
|
1948
|
+
this.$ = new commander.Command(name);
|
|
1949
|
+
commanderBackRefs.set(this.$, this);
|
|
1950
|
+
if (parent) {
|
|
1951
|
+
this.parent = parent;
|
|
1952
|
+
this.parent.meta.subcommands.push(this);
|
|
1953
|
+
this.parent.$.addCommand(this.$);
|
|
1954
|
+
}
|
|
1955
|
+
this.initializeHelp();
|
|
1956
|
+
this.initializeActionWrapper();
|
|
1957
|
+
if (callback) callback.call(this, this);
|
|
1958
|
+
if (this.parent) {
|
|
1959
|
+
this.$.copyInheritedSettings(this.parent.$);
|
|
1960
|
+
this.features.inheritFrom(this.parent.features);
|
|
1961
|
+
this.inheritParentHiddenGlobals();
|
|
1962
|
+
}
|
|
1963
|
+
if (!this.meta.isNative) {
|
|
1964
|
+
this.assertCommandNameNotReserved(this.name);
|
|
1965
|
+
this.addUtilCommands();
|
|
1966
|
+
}
|
|
1967
|
+
if (this.features.isAutoAssignSubCommandAliasesEnabled) {
|
|
1968
|
+
this.assignSubCommandAliases();
|
|
1969
|
+
if (!this.meta.isNative) {
|
|
1970
|
+
this.assertNoDuplicateCommandNames();
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
if (this.features.isAutoAssignMissingOptionFlagsEnabled) {
|
|
1974
|
+
this.assignMissingOptionFlags();
|
|
1975
|
+
if (!this.meta.isNative) {
|
|
1976
|
+
this.assertNoDuplicateOptionNames();
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
this.meta.isInitialized = true;
|
|
1980
|
+
}
|
|
1981
|
+
setRecommended() {
|
|
1982
|
+
this.enableBuiltinOptions({
|
|
1983
|
+
debug: true,
|
|
1984
|
+
disableStderr: true,
|
|
1985
|
+
disableStdout: true
|
|
1986
|
+
});
|
|
1987
|
+
this.autoAssignMissingOptionFlags();
|
|
1988
|
+
this.autoAssignSubCommandAliases();
|
|
1989
|
+
this.presetsEnabled();
|
|
1990
|
+
}
|
|
1991
|
+
deleteDataFile() {
|
|
1992
|
+
const filepath = this.dataFilepath;
|
|
1993
|
+
if (fs__default["default"].existsSync(filepath)) fs.remove(filepath);
|
|
2178
1994
|
}
|
|
2179
1995
|
version(string) {
|
|
1996
|
+
this.assertNotInitialized();
|
|
2180
1997
|
this.$.version(string);
|
|
1998
|
+
const opt = this.options.find((o)=>o.attributeName() === 'version');
|
|
1999
|
+
if (opt) this.meta.globalOptions.push(opt);
|
|
2000
|
+
return this;
|
|
2001
|
+
}
|
|
2002
|
+
description(...lines) {
|
|
2003
|
+
this.assertNotInitialized();
|
|
2004
|
+
const description = lines.join('\n');
|
|
2005
|
+
const summary = description.split(/(\. ?|\n|$)/)[0];
|
|
2006
|
+
this.$.summary(summary + '.');
|
|
2007
|
+
this.$.description(description);
|
|
2181
2008
|
return this;
|
|
2182
2009
|
}
|
|
2183
2010
|
alias(alias) {
|
|
2184
|
-
|
|
2011
|
+
this.assertNotInitialized();
|
|
2012
|
+
this.assertCommandNameNotReserved(alias);
|
|
2185
2013
|
this.$.alias(alias);
|
|
2186
2014
|
return this;
|
|
2187
2015
|
}
|
|
2188
2016
|
aliases(...aliases) {
|
|
2189
|
-
|
|
2017
|
+
this.assertNotInitialized();
|
|
2018
|
+
aliases.forEach((alias)=>this.assertCommandNameNotReserved(alias));
|
|
2019
|
+
this.$.aliases(aliases);
|
|
2020
|
+
return this;
|
|
2021
|
+
}
|
|
2022
|
+
enableBuiltinOptions(options) {
|
|
2023
|
+
this.assertNotInitialized();
|
|
2024
|
+
if (!options || options.debug) this.globalOption('-D, --debug', 'Output debugging information.');
|
|
2025
|
+
if (!options || options.disableColor) this.globalOption('-C, --disable-color', 'Disable color in terminal output.');
|
|
2026
|
+
if (!options || options.disableStderr) this.globalOption('-E, --disable-stderr', 'Mute all output to stderr.');
|
|
2027
|
+
if (!options || options.disableStdout) this.globalOption('-O, --disable-stdout', 'Mute all output to stdout.');
|
|
2028
|
+
return this;
|
|
2029
|
+
}
|
|
2030
|
+
argument(name, cb) {
|
|
2031
|
+
this.assertNotInitialized();
|
|
2032
|
+
const ins = new ArgumentBuilder(this, name);
|
|
2033
|
+
this.$.addArgument(ins.$);
|
|
2034
|
+
if (typeof cb === 'function') {
|
|
2035
|
+
cb(ins, this);
|
|
2036
|
+
} else if (typeof cb === 'string') {
|
|
2037
|
+
ins.description(cb);
|
|
2038
|
+
}
|
|
2039
|
+
return this;
|
|
2040
|
+
}
|
|
2041
|
+
option(flags, cb) {
|
|
2042
|
+
this.assertNotInitialized();
|
|
2043
|
+
const ins = new OptionBuilder(this, flags);
|
|
2044
|
+
if (this.hasIdenticalParentOption(ins.$)) return this;
|
|
2045
|
+
this.$.addOption(ins.$);
|
|
2046
|
+
if (typeof cb === 'function') {
|
|
2047
|
+
cb(ins, this);
|
|
2048
|
+
} else if (typeof cb === 'string') {
|
|
2049
|
+
ins.description(cb);
|
|
2050
|
+
}
|
|
2051
|
+
return this;
|
|
2052
|
+
}
|
|
2053
|
+
globalOption(flags, cb) {
|
|
2054
|
+
return this.option(flags, (ins)=>{
|
|
2055
|
+
const opt = ins.$;
|
|
2056
|
+
this.meta.globalOptions.push(opt);
|
|
2057
|
+
if (typeof cb === 'function') {
|
|
2058
|
+
cb(ins, this);
|
|
2059
|
+
} else if (typeof cb === 'string') {
|
|
2060
|
+
ins.description(cb);
|
|
2061
|
+
}
|
|
2062
|
+
if (opt.hidden) this.meta.hiddenGlobalOptions.add(opt);
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
|
+
command(name, cb) {
|
|
2066
|
+
this.assertNotInitialized();
|
|
2067
|
+
new CommandBuilder(name, cb, this);
|
|
2068
|
+
return this;
|
|
2069
|
+
}
|
|
2070
|
+
nativeCommand(name, cb) {
|
|
2071
|
+
this.assertNotInitialized();
|
|
2072
|
+
new CommandBuilder(name, cb, this, true);
|
|
2073
|
+
return this;
|
|
2074
|
+
}
|
|
2075
|
+
action(fn) {
|
|
2076
|
+
this.assertNotInitialized();
|
|
2077
|
+
Object.defineProperty(this.meta, 'actionHandler', {
|
|
2078
|
+
value: fn,
|
|
2079
|
+
configurable: true
|
|
2080
|
+
});
|
|
2081
|
+
return this;
|
|
2082
|
+
}
|
|
2083
|
+
errorHandler(fn) {
|
|
2084
|
+
this.assertNotInitialized();
|
|
2085
|
+
Object.defineProperty(this.meta, 'errorHandler', {
|
|
2086
|
+
value: fn,
|
|
2087
|
+
configurable: true
|
|
2088
|
+
});
|
|
2089
|
+
return this;
|
|
2090
|
+
}
|
|
2091
|
+
appData(key, value) {
|
|
2092
|
+
this.assertNotInitialized();
|
|
2093
|
+
this.features.appData(true);
|
|
2094
|
+
this.db.appData.defineProperty(key, value);
|
|
2095
|
+
return this;
|
|
2096
|
+
}
|
|
2097
|
+
config(key, entry) {
|
|
2098
|
+
this.assertNotInitialized();
|
|
2099
|
+
this.features.config(true);
|
|
2100
|
+
this.db.config.defineProperty(key, entry);
|
|
2101
|
+
return this;
|
|
2102
|
+
}
|
|
2103
|
+
preset(name, preset) {
|
|
2104
|
+
this.assertNotInitialized();
|
|
2105
|
+
this.features.presets();
|
|
2106
|
+
this.meta.presetOptionKeys.push(name);
|
|
2107
|
+
this.db.presets.defineProperty(name, {
|
|
2108
|
+
description: preset.description,
|
|
2109
|
+
presets: preset.presets ?? [],
|
|
2110
|
+
args: preset.args ?? [],
|
|
2111
|
+
options: preset.options ?? {}
|
|
2112
|
+
});
|
|
2113
|
+
return this;
|
|
2114
|
+
}
|
|
2115
|
+
presetsEnabled(boolean = true) {
|
|
2116
|
+
this.assertNotInitialized();
|
|
2117
|
+
this.features.presets(boolean);
|
|
2118
|
+
return this;
|
|
2119
|
+
}
|
|
2120
|
+
autoAssignMissingOptionFlags(boolean = true) {
|
|
2121
|
+
this.assertNotInitialized();
|
|
2122
|
+
this.features.autoAssignMissingOptionFlags(boolean);
|
|
2123
|
+
return this;
|
|
2124
|
+
}
|
|
2125
|
+
autoAssignSubCommandAliases(boolean = true) {
|
|
2126
|
+
this.assertNotInitialized();
|
|
2127
|
+
this.features.autoAssignSubCommandAliases(boolean);
|
|
2128
|
+
return this;
|
|
2129
|
+
}
|
|
2130
|
+
allowExcessArguments(bool = true) {
|
|
2131
|
+
this.assertNotInitialized();
|
|
2132
|
+
this.$.allowExcessArguments(bool);
|
|
2133
|
+
return this;
|
|
2134
|
+
}
|
|
2135
|
+
allowUnknownOption(bool = true) {
|
|
2136
|
+
this.assertNotInitialized();
|
|
2137
|
+
this.$.allowUnknownOption(bool);
|
|
2138
|
+
return this;
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* Register callback to use as replacement for calling process.exit.
|
|
2142
|
+
*/ exitOverride(callback) {
|
|
2143
|
+
this.assertNotInitialized();
|
|
2144
|
+
this.$.exitOverride(callback);
|
|
2145
|
+
return this;
|
|
2146
|
+
}
|
|
2147
|
+
throwInsteadOfProcessExit() {
|
|
2148
|
+
this.assertNotInitialized();
|
|
2149
|
+
const onErr = (err)=>{
|
|
2150
|
+
throw err;
|
|
2151
|
+
};
|
|
2152
|
+
this.exitOverride(onErr);
|
|
2153
|
+
this.errorHandler(onErr);
|
|
2154
|
+
}
|
|
2155
|
+
/**
|
|
2156
|
+
* Add hook for life cycle event.
|
|
2157
|
+
*/ hook(event, listener) {
|
|
2158
|
+
this.assertNotInitialized();
|
|
2159
|
+
this.$.hook(event, listener);
|
|
2160
|
+
return this;
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* You can customise the help by overriding Help properties using configureHelp(),
|
|
2164
|
+
* or with a subclass of Help by overriding createHelp().
|
|
2165
|
+
*/ configureHelp(configuration) {
|
|
2166
|
+
this.assertNotInitialized();
|
|
2167
|
+
this.$.configureHelp(configuration);
|
|
2168
|
+
return this;
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Display the help or a custom message after an error occurs.
|
|
2172
|
+
*/ showHelpAfterError(displayHelp) {
|
|
2173
|
+
this.assertNotInitialized();
|
|
2174
|
+
this.$.showHelpAfterError(displayHelp);
|
|
2175
|
+
return this;
|
|
2176
|
+
}
|
|
2177
|
+
/**
|
|
2178
|
+
* Display suggestion of similar commands for unknown commands, or options for unknown options.
|
|
2179
|
+
*/ showSuggestionAfterError(displaySuggestion) {
|
|
2180
|
+
this.assertNotInitialized();
|
|
2181
|
+
this.$.showSuggestionAfterError(displaySuggestion);
|
|
2182
|
+
return this;
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* Add additional text to be displayed with the built-in help.
|
|
2186
|
+
*
|
|
2187
|
+
* Position is 'before' or 'after' to affect just this command,
|
|
2188
|
+
* and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
|
|
2189
|
+
*/ addHelpText(position, text) {
|
|
2190
|
+
this.assertNotInitialized();
|
|
2191
|
+
this.$.addHelpText(position, text);
|
|
2192
|
+
return this;
|
|
2193
|
+
}
|
|
2194
|
+
throwCommanderError(message, exitCode = 1, type = 'error') {
|
|
2195
|
+
throw new commander.CommanderError(exitCode, type, message);
|
|
2196
|
+
}
|
|
2197
|
+
hideGlobalOptions(...names) {
|
|
2198
|
+
this.assertNotInitialized();
|
|
2199
|
+
const globals = this.getGlobalOptions();
|
|
2200
|
+
names = names.length ? names : globals.map((opt)=>opt.attributeName());
|
|
2201
|
+
for (const name of names){
|
|
2202
|
+
if (!name) continue;
|
|
2203
|
+
let found = false;
|
|
2204
|
+
for (const opt of globals){
|
|
2205
|
+
if (opt.attributeName() === name) {
|
|
2206
|
+
this.meta.hiddenGlobalOptions.add(opt);
|
|
2207
|
+
found = true;
|
|
2208
|
+
break;
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
if (!found) this.throwCommanderError(`Unknown global option name: ${name} for command, ${this.name}`);
|
|
2212
|
+
}
|
|
2213
|
+
return this;
|
|
2214
|
+
}
|
|
2215
|
+
unhideGlobalOptions(...names) {
|
|
2216
|
+
this.assertNotInitialized();
|
|
2217
|
+
const globals = this.getGlobalOptions();
|
|
2218
|
+
names = names.length ? names : globals.map((opt)=>opt.attributeName());
|
|
2219
|
+
for (const name of names){
|
|
2220
|
+
if (!name) continue;
|
|
2221
|
+
let found = false;
|
|
2222
|
+
for (const opt of globals){
|
|
2223
|
+
if (opt.attributeName() === name) {
|
|
2224
|
+
this.meta.hiddenGlobalOptions.delete(opt);
|
|
2225
|
+
found = true;
|
|
2226
|
+
break;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
if (!found) this.throwCommanderError(`Unknown global option name: ${name} for command, ${this.name}`);
|
|
2230
|
+
}
|
|
2231
|
+
return this;
|
|
2232
|
+
}
|
|
2233
|
+
/**
|
|
2234
|
+
* Set the directory for searching for executable subcommands of this command.
|
|
2235
|
+
*/ executableDir(path) {
|
|
2236
|
+
this.assertNotInitialized();
|
|
2237
|
+
this.$.executableDir(path);
|
|
2238
|
+
return this;
|
|
2239
|
+
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Store option value.
|
|
2242
|
+
*/ setOptionValue(key, value) {
|
|
2243
|
+
this.assertNotInitialized();
|
|
2244
|
+
this.$.setOptionValue(key, value);
|
|
2245
|
+
return this;
|
|
2246
|
+
}
|
|
2247
|
+
/**
|
|
2248
|
+
* Store option value and where the value came from.
|
|
2249
|
+
*/ setOptionValueWithSource(key, value, source) {
|
|
2250
|
+
this.assertNotInitialized();
|
|
2251
|
+
this.$.setOptionValueWithSource(key, value, source);
|
|
2190
2252
|
return this;
|
|
2191
2253
|
}
|
|
2254
|
+
setDataFilepath(filepath) {
|
|
2255
|
+
this.assertNotInitialized();
|
|
2256
|
+
Object.defineProperty(this, 'dataFilepath', {
|
|
2257
|
+
value: filepath
|
|
2258
|
+
});
|
|
2259
|
+
if (Object.hasOwn(this, 'db') && Object.hasOwn(this.db, 'db')) {
|
|
2260
|
+
this.db.db.setFilepath(filepath);
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
/**
|
|
2264
|
+
* Display error message and exit (or call exitOverride).
|
|
2265
|
+
*/ outputError(message, options) {
|
|
2266
|
+
this.$.error(message, options);
|
|
2267
|
+
}
|
|
2268
|
+
/**
|
|
2269
|
+
* Output help information for this command.
|
|
2270
|
+
*/ outputHelp() {
|
|
2271
|
+
console.log(this.getRenderedHelp());
|
|
2272
|
+
}
|
|
2273
|
+
/**
|
|
2274
|
+
* Display error message and exit (or call exitOverride).
|
|
2275
|
+
*/ outputDebugMessage(event, getProps = ()=>({})) {
|
|
2276
|
+
OutputManager.getInstance().outputDebug(()=>({
|
|
2277
|
+
event,
|
|
2278
|
+
cmd: this.getPrefixString(),
|
|
2279
|
+
...getProps()
|
|
2280
|
+
}));
|
|
2281
|
+
}
|
|
2282
|
+
parseArguments(args) {
|
|
2283
|
+
const last = this.arguments.length - 1;
|
|
2284
|
+
return args.map((arg, i)=>{
|
|
2285
|
+
if (!arg) return arg;
|
|
2286
|
+
const parse = this.meta.argParsers[i > last ? last : i];
|
|
2287
|
+
return parse ? Array.isArray(arg) ? arg.map(parse) : parse(arg) : arg;
|
|
2288
|
+
});
|
|
2289
|
+
}
|
|
2290
|
+
/**
|
|
2291
|
+
* Parses (and validates) options using the parsers defined in the command builder.
|
|
2292
|
+
*/ parseOptions(opts) {
|
|
2293
|
+
for (const [key, value] of Object.entries(opts)){
|
|
2294
|
+
const parse = this.meta.optParsers[key];
|
|
2295
|
+
opts[key] = parse ? Array.isArray(value) ? value.map(parse) : parse(value) : value;
|
|
2296
|
+
}
|
|
2297
|
+
return opts;
|
|
2298
|
+
}
|
|
2299
|
+
/**
|
|
2300
|
+
* Validate ALREADY PARSED args using the validators defined in the command builder.
|
|
2301
|
+
*/ assertValidArguments(parsedArgs) {
|
|
2302
|
+
const last = this.arguments.length - 1;
|
|
2303
|
+
parsedArgs.forEach((arg, i)=>{
|
|
2304
|
+
if (arg == null) return;
|
|
2305
|
+
const index = i > last ? last : i;
|
|
2306
|
+
const validators = this.meta.argValidators[index];
|
|
2307
|
+
if (!validators) return;
|
|
2308
|
+
for (const isValid of validators){
|
|
2309
|
+
ensureThat(arg, isValid, {
|
|
2310
|
+
Err: commander.InvalidArgumentError
|
|
2311
|
+
});
|
|
2312
|
+
}
|
|
2313
|
+
});
|
|
2314
|
+
return parsedArgs;
|
|
2315
|
+
}
|
|
2316
|
+
/**
|
|
2317
|
+
* Validate ALREADY PARSED options using the validators defined in the command builder.
|
|
2318
|
+
*/ assertValidOptions(parsedOptions) {
|
|
2319
|
+
for (const [key, value] of Object.entries(parsedOptions)){
|
|
2320
|
+
if (!this.meta.optValidators[key]) continue;
|
|
2321
|
+
if (value == null) continue;
|
|
2322
|
+
for (const isValid of this.meta.optValidators[key]){
|
|
2323
|
+
ensureThat(value, isValid);
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
return parsedOptions;
|
|
2327
|
+
}
|
|
2328
|
+
assertValidPreset(key, preset) {
|
|
2329
|
+
const { description, presets, args, options } = preset;
|
|
2330
|
+
ensureThat(key, isStringWithNoSpacesOrDashes);
|
|
2331
|
+
ensureThat(description, isString);
|
|
2332
|
+
ensureThat(presets, isStringArray);
|
|
2333
|
+
ensureThat(args, isArray);
|
|
2334
|
+
this.assertPresetArgsOptional(args);
|
|
2335
|
+
this.assertValidArguments(args);
|
|
2336
|
+
ensureThat(options, isObject);
|
|
2337
|
+
this.assertValidOptions(options);
|
|
2338
|
+
}
|
|
2339
|
+
get name() {
|
|
2340
|
+
return this.$.name();
|
|
2341
|
+
}
|
|
2342
|
+
/**
|
|
2343
|
+
* Get the command at the root of the command tree.
|
|
2344
|
+
*/ get root() {
|
|
2345
|
+
if (this.isRoot) return this;
|
|
2346
|
+
return this.getAncestors().pop();
|
|
2347
|
+
}
|
|
2192
2348
|
get isRoot() {
|
|
2193
2349
|
return !this.parent;
|
|
2194
2350
|
}
|
|
@@ -2198,268 +2354,744 @@ class OptionReader extends Base {
|
|
|
2198
2354
|
get options() {
|
|
2199
2355
|
return this.$.options;
|
|
2200
2356
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
if (!options || options.debug) this.globalOption('-D, --debug', 'Output debugging information.');
|
|
2204
|
-
if (!options || options.disableColor) this.globalOption('-C, --disable-color', 'Disable color in terminal output.');
|
|
2205
|
-
if (!options || options.disableStderr) this.globalOption('-E, --disable-stderr', 'Mute all output to stderr.');
|
|
2206
|
-
if (!options || options.disableStdout) this.globalOption('-O, --disable-stdout', 'Mute all output to stdout.');
|
|
2357
|
+
get commander() {
|
|
2358
|
+
return this.$;
|
|
2207
2359
|
}
|
|
2208
|
-
|
|
2209
|
-
this
|
|
2360
|
+
get hasGrandChildren() {
|
|
2361
|
+
return this.meta.subcommands.some((sub)=>!!sub.meta.subcommands.length);
|
|
2210
2362
|
}
|
|
2211
2363
|
/**
|
|
2212
|
-
*
|
|
2213
|
-
*/
|
|
2214
|
-
this
|
|
2364
|
+
* Returns whether a command's last argument is variadic.
|
|
2365
|
+
*/ get isLastArgVariadic() {
|
|
2366
|
+
if (!this.arguments.length) return false;
|
|
2367
|
+
return arrLast(this.arguments).variadic;
|
|
2215
2368
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
const summary = description.split(/(\. ?|\n|$)/)[0];
|
|
2219
|
-
this.$.summary(summary + '.');
|
|
2220
|
-
this.$.description(description);
|
|
2221
|
-
return this;
|
|
2369
|
+
get dataFilepath() {
|
|
2370
|
+
return path__default["default"].join(CommandBuilder.dataDirectory, this.root.name + '.json');
|
|
2222
2371
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2372
|
+
/**
|
|
2373
|
+
* Get the executable search directory.
|
|
2374
|
+
*/ getExecutableDir() {
|
|
2375
|
+
return this.$.executableDir();
|
|
2226
2376
|
}
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2377
|
+
/**
|
|
2378
|
+
* Retrieve option value.
|
|
2379
|
+
*/ getOptionValue(key) {
|
|
2380
|
+
return this.$.getOptionValue(key);
|
|
2230
2381
|
}
|
|
2231
2382
|
/**
|
|
2232
|
-
*
|
|
2233
|
-
*/
|
|
2234
|
-
this.$.
|
|
2235
|
-
return this;
|
|
2383
|
+
* Get source of option value.
|
|
2384
|
+
*/ getOptionValueSource(key) {
|
|
2385
|
+
return this.$.getOptionValueSource(key);
|
|
2236
2386
|
}
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2387
|
+
/**
|
|
2388
|
+
* Get source of option value. See also .optsWithGlobals().
|
|
2389
|
+
*/ getOptionValueSourceWithGlobals(key) {
|
|
2390
|
+
return this.$.getOptionValueSourceWithGlobals(key);
|
|
2391
|
+
}
|
|
2392
|
+
getActionHandler() {
|
|
2393
|
+
return this.meta.actionHandler;
|
|
2394
|
+
}
|
|
2395
|
+
getDescription() {
|
|
2396
|
+
return this.$.description();
|
|
2397
|
+
}
|
|
2398
|
+
getSummary() {
|
|
2399
|
+
return this.$.summary();
|
|
2400
|
+
}
|
|
2401
|
+
getVersion() {
|
|
2402
|
+
return this.$.version();
|
|
2403
|
+
}
|
|
2404
|
+
getAlias() {
|
|
2405
|
+
return this.$.alias();
|
|
2406
|
+
}
|
|
2407
|
+
getAliases() {
|
|
2408
|
+
return this.$.aliases();
|
|
2240
2409
|
}
|
|
2241
2410
|
/**
|
|
2242
|
-
*
|
|
2243
|
-
*/
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
}, getProps()));
|
|
2411
|
+
* Get a commands prefix array based on all its parent/ancestor commands.
|
|
2412
|
+
*/ getPrefixArray() {
|
|
2413
|
+
return this.getAncestors({
|
|
2414
|
+
includeSelf: true
|
|
2415
|
+
}).reverse().map((node)=>node.name);
|
|
2248
2416
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2417
|
+
/**
|
|
2418
|
+
* Get a commands prefix string based on all its parent/ancestor commands.
|
|
2419
|
+
*/ getPrefixString() {
|
|
2420
|
+
return this.getPrefixArray().join(' ');
|
|
2421
|
+
}
|
|
2422
|
+
getGlobalOptions() {
|
|
2423
|
+
const result = [];
|
|
2424
|
+
for (const anc of this.getAncestors({
|
|
2425
|
+
includeSelf: true
|
|
2426
|
+
}).reverse()){
|
|
2427
|
+
for (const gopt of anc.meta.globalOptions){
|
|
2428
|
+
if (!this.meta.hiddenGlobalOptions.has(gopt)) {
|
|
2429
|
+
result.push(gopt);
|
|
2260
2430
|
}
|
|
2261
2431
|
}
|
|
2262
|
-
if (!found) throw new Error(`Unknown global option name: ${name} for command, ${this.name}`);
|
|
2263
2432
|
}
|
|
2264
|
-
return
|
|
2433
|
+
return result;
|
|
2265
2434
|
}
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
this.meta.hiddenGlobalOptions.delete(opt);
|
|
2275
|
-
found = true;
|
|
2276
|
-
break;
|
|
2277
|
-
}
|
|
2278
|
-
}
|
|
2279
|
-
if (!found) throw new Error(`Unknown global option name: ${name} for command, ${this.name}`);
|
|
2435
|
+
getOwnAndGlobalOptions() {
|
|
2436
|
+
return this.options.concat(this.getGlobalOptions());
|
|
2437
|
+
}
|
|
2438
|
+
*getChildrenIterator(options) {
|
|
2439
|
+
if (options?.includeSelf) yield this;
|
|
2440
|
+
for (const sub of this.meta.subcommands){
|
|
2441
|
+
yield sub;
|
|
2442
|
+
yield* sub.getChildrenIterator();
|
|
2280
2443
|
}
|
|
2281
|
-
return this;
|
|
2282
2444
|
}
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2445
|
+
getChildren(options) {
|
|
2446
|
+
return [
|
|
2447
|
+
...this.getChildrenIterator(options)
|
|
2448
|
+
];
|
|
2449
|
+
}
|
|
2450
|
+
*getAncestorsIterator(options) {
|
|
2451
|
+
if (options?.includeSelf) yield this;
|
|
2452
|
+
let node = this.parent;
|
|
2453
|
+
while(node){
|
|
2454
|
+
yield node;
|
|
2455
|
+
node = node.parent;
|
|
2290
2456
|
}
|
|
2291
|
-
objDestroy(ins);
|
|
2292
|
-
return this;
|
|
2293
2457
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2458
|
+
/**
|
|
2459
|
+
* Get a command's ancestors, optionally starting from the command itself.
|
|
2460
|
+
*/ getAncestors(options) {
|
|
2461
|
+
return [
|
|
2462
|
+
...this.getAncestorsIterator(options)
|
|
2463
|
+
];
|
|
2464
|
+
}
|
|
2465
|
+
*getSiblingsIterator() {
|
|
2466
|
+
if (!this.parent) return;
|
|
2467
|
+
for (const sub of this.parent.meta.subcommands){
|
|
2468
|
+
if (sub === this) continue;
|
|
2469
|
+
yield sub;
|
|
2301
2470
|
}
|
|
2302
|
-
objDestroy(ins);
|
|
2303
|
-
return this;
|
|
2304
2471
|
}
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
} else if (typeof cb === 'string') {
|
|
2312
|
-
ins.description(cb);
|
|
2313
|
-
}
|
|
2314
|
-
if (opt.hidden) this.meta.hiddenGlobalOptions.add(opt);
|
|
2315
|
-
});
|
|
2472
|
+
/**
|
|
2473
|
+
* Returns an array of sibling CommandBuilder objects.
|
|
2474
|
+
*/ getSiblings() {
|
|
2475
|
+
return [
|
|
2476
|
+
...this.getSiblingsIterator()
|
|
2477
|
+
];
|
|
2316
2478
|
}
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2479
|
+
getClosestNonNativeParent() {
|
|
2480
|
+
for (const anc of this.getAncestorsIterator({
|
|
2481
|
+
includeSelf: true
|
|
2482
|
+
})){
|
|
2483
|
+
if (!anc.meta.isNative) return anc;
|
|
2484
|
+
}
|
|
2485
|
+
this.throwCommanderError('No non-native parent found');
|
|
2320
2486
|
}
|
|
2321
|
-
|
|
2322
|
-
return this
|
|
2323
|
-
ins.meta.isNative = true;
|
|
2324
|
-
if (cb) cb(ins);
|
|
2325
|
-
});
|
|
2487
|
+
getRenderedHelp() {
|
|
2488
|
+
return this.$.helpInformation();
|
|
2326
2489
|
}
|
|
2327
|
-
|
|
2328
|
-
this.
|
|
2329
|
-
return this;
|
|
2490
|
+
getOptsWithGlobalsParsed() {
|
|
2491
|
+
return this.parseOptions(this.$.optsWithGlobals());
|
|
2330
2492
|
}
|
|
2331
|
-
|
|
2332
|
-
this.
|
|
2333
|
-
this.
|
|
2334
|
-
|
|
2493
|
+
getParsedValidArgsOptsWithPresets() {
|
|
2494
|
+
const [presetArgs, presetOpts, presetOrder] = this.getPresetArgsAndOpts();
|
|
2495
|
+
const args = this.getParsedValidArgsWithPresets(presetArgs);
|
|
2496
|
+
const opts = this.getParsedValidOptsWithPresets(presetOpts);
|
|
2497
|
+
this.debugLogArgsOpts(args, opts, presetArgs, presetOpts, presetOrder);
|
|
2498
|
+
return [
|
|
2499
|
+
args,
|
|
2500
|
+
opts
|
|
2501
|
+
];
|
|
2335
2502
|
}
|
|
2336
|
-
|
|
2337
|
-
this.
|
|
2338
|
-
|
|
2339
|
-
this.
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2503
|
+
getParsedValidArgsWithPresets(presetArgs) {
|
|
2504
|
+
const result = arrAssign([], ...presetArgs, this.parseArguments(this.$.args));
|
|
2505
|
+
this.combineVariadicArgs(result);
|
|
2506
|
+
this.assertValidArguments(result);
|
|
2507
|
+
return this.padArgsWithUndefinedUntilExpectedLength(result);
|
|
2508
|
+
}
|
|
2509
|
+
getParsedValidOptsWithPresets(presetOpts) {
|
|
2510
|
+
const parsed = this.getOptsWithGlobalsParsed();
|
|
2511
|
+
const opts = presetOpts.length ? objAssign({}, ...presetOpts, parsed) : parsed;
|
|
2512
|
+
this.deleteOptionsWithDefaultOrNoValue(opts);
|
|
2513
|
+
this.assertValidOptions(opts);
|
|
2514
|
+
return opts;
|
|
2515
|
+
}
|
|
2516
|
+
getPresetArgsAndOpts() {
|
|
2517
|
+
if (!this.features.isPresetsEnabled) return [
|
|
2518
|
+
[],
|
|
2519
|
+
[],
|
|
2520
|
+
[]
|
|
2521
|
+
];
|
|
2522
|
+
const presets = this.db.presets.getAll();
|
|
2523
|
+
const opts = this.$.optsWithGlobals();
|
|
2524
|
+
const selectedPresets = Object.keys(presets).filter((name)=>opts[name] === true);
|
|
2525
|
+
const presetOrder = Object.keys(opts).filter((key)=>selectedPresets.includes(key));
|
|
2526
|
+
const presetArgs = presetOrder.map((name)=>presets[name].args);
|
|
2527
|
+
const presetOpts = presetOrder.map((name)=>presets[name].options);
|
|
2528
|
+
return [
|
|
2529
|
+
presetArgs,
|
|
2530
|
+
presetOpts,
|
|
2531
|
+
presetOrder
|
|
2532
|
+
];
|
|
2533
|
+
}
|
|
2534
|
+
combineVariadicArgs(result) {
|
|
2535
|
+
if (this.isLastArgVariadic && result.length && !Array.isArray(arrLast(result))) {
|
|
2536
|
+
const rest = result.splice(this.arguments.length - 1);
|
|
2537
|
+
result.push(rest.filter((arg)=>arg != null));
|
|
2538
|
+
}
|
|
2539
|
+
return result;
|
|
2540
|
+
}
|
|
2541
|
+
debugLogArgsOpts(args, opts, presetArgs, presetOpts, presetOrder) {
|
|
2542
|
+
if (opts['debug']) {
|
|
2543
|
+
if (this.features.isPresetsEnabled) {
|
|
2544
|
+
this.outputDebugMessage('parsePresets', ()=>({
|
|
2545
|
+
presetOrder,
|
|
2546
|
+
presetArgs,
|
|
2547
|
+
presetOpts
|
|
2548
|
+
}));
|
|
2549
|
+
}
|
|
2550
|
+
this.outputDebugMessage('parseArgsOpts', ()=>{
|
|
2551
|
+
return {
|
|
2552
|
+
args,
|
|
2553
|
+
opts,
|
|
2554
|
+
command: [
|
|
2555
|
+
this.root.name,
|
|
2556
|
+
...this.meta.rawArgs
|
|
2557
|
+
].join(' ')
|
|
2558
|
+
};
|
|
2559
|
+
});
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
deleteOptionsWithDefaultOrNoValue(opts) {
|
|
2563
|
+
const names = new Set(this.getOwnAndGlobalOptions().map((o)=>o.attributeName()));
|
|
2564
|
+
for (const [key, value] of Object.entries(opts)){
|
|
2565
|
+
if (!names.has(key) || value === false || value == null) {
|
|
2566
|
+
setNonEnumerable(opts, key);
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
for (const key of this.meta.presetOptionKeys){
|
|
2570
|
+
if (Object.hasOwn(opts, key)) {
|
|
2571
|
+
setNonEnumerable(opts, key);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
return opts;
|
|
2575
|
+
}
|
|
2576
|
+
handleOutputOptions() {
|
|
2577
|
+
const opts = this.$.optsWithGlobals();
|
|
2578
|
+
const om = OutputManager.getInstance().reset();
|
|
2579
|
+
if (opts['disableColor']) om.colors.enabled = false;
|
|
2580
|
+
if (opts['disableStderr']) om.stderr.disable();
|
|
2581
|
+
if (opts['disableStdout']) om.stdout.disable();
|
|
2582
|
+
if (opts['debug']) {
|
|
2583
|
+
om.debug.enable();
|
|
2584
|
+
om.drainDebugMessageQueue();
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
padArgsWithUndefinedUntilExpectedLength(args) {
|
|
2588
|
+
while(args.length < this.arguments.length)args.push(undefined);
|
|
2589
|
+
return args;
|
|
2590
|
+
}
|
|
2591
|
+
assertPresetArgsOptional(args) {
|
|
2592
|
+
args.forEach((arg, i)=>{
|
|
2593
|
+
if (arg != null && i < this.arguments.length && this.arguments[i].required) {
|
|
2594
|
+
this.throwCommanderError(`Cannot preset required arguments.`);
|
|
2595
|
+
}
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2598
|
+
addUtilCommands() {
|
|
2599
|
+
if (!this.hasGrandChildren && !this.features.isConfigEnabled && !this.features.isPresetsEnabled && !this.features.isAppDataEnabled) {
|
|
2600
|
+
return;
|
|
2601
|
+
}
|
|
2602
|
+
this.nativeCommand('util', (u)=>{
|
|
2603
|
+
const cmd = u.getClosestNonNativeParent();
|
|
2604
|
+
u.alias('u');
|
|
2605
|
+
u.description('Utility commands.');
|
|
2606
|
+
if (cmd.features.isConfigEnabled) {
|
|
2607
|
+
u.nativeCommand('config', createConfigCommand);
|
|
2608
|
+
}
|
|
2609
|
+
if (cmd.features.isPresetsEnabled && cmd.meta.hasCustomActionHandler) {
|
|
2610
|
+
u.nativeCommand('presets', createPresetsCommand);
|
|
2611
|
+
}
|
|
2612
|
+
if (cmd.hasGrandChildren) {
|
|
2613
|
+
u.nativeCommand('list', createUtilListCommand);
|
|
2614
|
+
}
|
|
2615
|
+
if (cmd.features.isConfigEnabled || cmd.features.isPresetsEnabled || cmd.features.isAppDataEnabled) {
|
|
2616
|
+
u.nativeCommand('filepath', createUtilFilepathCommand);
|
|
2617
|
+
}
|
|
2618
|
+
function createUtilFilepathCommand(f) {
|
|
2619
|
+
f.alias('f');
|
|
2620
|
+
f.description('Print filepath to JSON file containing user data, eg. config and presets.');
|
|
2621
|
+
f.action(async ()=>console.log(cmd.dataFilepath));
|
|
2622
|
+
}
|
|
2623
|
+
function createUtilListCommand(l) {
|
|
2624
|
+
l.alias('l');
|
|
2625
|
+
l.description('List nested subcommands.');
|
|
2626
|
+
l.option('--all', 'Include utility commands.');
|
|
2627
|
+
l.action(async (opts)=>{
|
|
2628
|
+
const filter = opts.all ? undefined : (prefix)=>{
|
|
2629
|
+
return !/ (config|presets|util)( .+)?$/gi.test(prefix);
|
|
2630
|
+
};
|
|
2631
|
+
const table = [];
|
|
2632
|
+
for (const c of cmd.getChildrenIterator({
|
|
2633
|
+
includeSelf: true
|
|
2634
|
+
})){
|
|
2635
|
+
const prefix = c.getPrefixString();
|
|
2636
|
+
if (filter && !filter(prefix)) continue;
|
|
2637
|
+
table.push([
|
|
2638
|
+
prefix,
|
|
2639
|
+
c.getSummary()
|
|
2640
|
+
]);
|
|
2641
|
+
}
|
|
2642
|
+
const ansi = table.map((row)=>{
|
|
2643
|
+
const arr = row[0].split(' ');
|
|
2644
|
+
const last = arr.pop();
|
|
2645
|
+
let col = colors__default["default"].magenta;
|
|
2646
|
+
if (row[1].startsWith('[Preset]')) {
|
|
2647
|
+
col = colors__default["default"].green;
|
|
2648
|
+
} else if (/ (util|config|presets) /.test(row[0])) {
|
|
2649
|
+
col = colors__default["default"].gray;
|
|
2650
|
+
} else if (/ (util|config|presets)/.test(row[0])) {
|
|
2651
|
+
col = colors__default["default"].dim;
|
|
2652
|
+
}
|
|
2653
|
+
row[0] = arr.map(colors__default["default"].dim).concat(col(last)).join(' ');
|
|
2654
|
+
return row;
|
|
2655
|
+
});
|
|
2656
|
+
console.log(formatTableForTerminal(ansi, [
|
|
2657
|
+
'Command',
|
|
2658
|
+
'Summary'
|
|
2659
|
+
]));
|
|
2660
|
+
});
|
|
2661
|
+
}
|
|
2662
|
+
function createPresetsCommand(p) {
|
|
2663
|
+
const db = cmd.db.presets;
|
|
2664
|
+
p.alias('p');
|
|
2665
|
+
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.');
|
|
2666
|
+
p.nativeCommand('edit', (e)=>{
|
|
2667
|
+
e.alias('e');
|
|
2668
|
+
e.description('Edit as JSON in a text editor.');
|
|
2669
|
+
e.option('--editor [cmd]', 'The command to launch your preferred text editor.');
|
|
2670
|
+
e.action(async (opts)=>{
|
|
2671
|
+
db.edit(opts.editor);
|
|
2672
|
+
console.info(db.getAll());
|
|
2673
|
+
});
|
|
2674
|
+
});
|
|
2675
|
+
p.nativeCommand('list', (l)=>{
|
|
2676
|
+
l.alias('l');
|
|
2677
|
+
l.description('List all presets.');
|
|
2678
|
+
l.action(async ()=>console.dir(db.getAll(), {
|
|
2679
|
+
depth: null
|
|
2680
|
+
}));
|
|
2681
|
+
});
|
|
2682
|
+
for (const [key, preset] of Object.entries(db.getAll())){
|
|
2683
|
+
if (key === 'defaults') continue;
|
|
2684
|
+
cmd.option(`--${key}`, (o)=>{
|
|
2685
|
+
o.description('[Preset]: ' + preset.description);
|
|
2686
|
+
const implied = {
|
|
2687
|
+
defaults: true
|
|
2688
|
+
};
|
|
2689
|
+
const recurse = (preset)=>{
|
|
2690
|
+
if (implied[preset]) return;
|
|
2691
|
+
implied[preset] = true;
|
|
2692
|
+
db.get(preset).presets.forEach((k)=>recurse(k));
|
|
2693
|
+
};
|
|
2694
|
+
recurse(key);
|
|
2695
|
+
o.implies(implied);
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
function createConfigCommand(c) {
|
|
2700
|
+
const db = cmd.db.config;
|
|
2701
|
+
c.alias('c');
|
|
2702
|
+
c.description('Manage configuration file.');
|
|
2703
|
+
c.nativeCommand('edit', (e)=>{
|
|
2704
|
+
e.alias('e');
|
|
2705
|
+
e.description('Edit as JSON in a text editor.');
|
|
2706
|
+
e.option('--editor [cmd]', 'The command to launch your preferred text editor.');
|
|
2707
|
+
e.action(async (opts)=>{
|
|
2708
|
+
db.edit(opts.editor);
|
|
2709
|
+
console.info(db.getAll());
|
|
2710
|
+
});
|
|
2711
|
+
});
|
|
2712
|
+
c.nativeCommand('list', (l)=>{
|
|
2713
|
+
l.alias('l');
|
|
2714
|
+
l.description('Print entire config with details.');
|
|
2715
|
+
l.action(async ()=>{
|
|
2716
|
+
const result = db.keys.map((key)=>({
|
|
2717
|
+
key,
|
|
2718
|
+
description: db.descriptions[key],
|
|
2719
|
+
value: db.get(key),
|
|
2720
|
+
defaultValue: db.defaultValues
|
|
2721
|
+
}));
|
|
2722
|
+
console.dir(result, {
|
|
2723
|
+
depth: null
|
|
2724
|
+
});
|
|
2725
|
+
});
|
|
2726
|
+
});
|
|
2727
|
+
c.nativeCommand('get', (g)=>{
|
|
2728
|
+
g.alias('g');
|
|
2729
|
+
g.description('Print value(s) from the config.');
|
|
2730
|
+
g.argument('[key]', 'The key to print the value of. Omit to print all values.');
|
|
2731
|
+
g.action(async (key)=>console.log(key ? db.get(key) : db.getAll()));
|
|
2732
|
+
});
|
|
2733
|
+
c.nativeCommand('set', (s)=>{
|
|
2734
|
+
s.alias('s');
|
|
2735
|
+
s.description('Set a value in the config.');
|
|
2736
|
+
s.argument('<key>', 'The key to set the value of.');
|
|
2737
|
+
s.argument('<value>', 'The new value.');
|
|
2738
|
+
s.action(async (key, val)=>{
|
|
2739
|
+
const parse = db.parsers[key];
|
|
2740
|
+
const value = typeof parse === 'function' ? parse(val) : val;
|
|
2741
|
+
db.set(key, value);
|
|
2742
|
+
console.info({
|
|
2743
|
+
[key]: value
|
|
2744
|
+
});
|
|
2745
|
+
});
|
|
2746
|
+
});
|
|
2747
|
+
c.nativeCommand('reset', (r)=>{
|
|
2748
|
+
r.alias('r');
|
|
2749
|
+
r.description('Reset to defaults.');
|
|
2750
|
+
r.argument('[key]', 'The key for which to reset the value. Omit to reset entire config.');
|
|
2751
|
+
r.action(async (key)=>{
|
|
2752
|
+
if (key) db.reset(key);
|
|
2753
|
+
else db.resetAll();
|
|
2754
|
+
console.info(db.getAll());
|
|
2755
|
+
});
|
|
2756
|
+
});
|
|
2757
|
+
/*
|
|
2758
|
+
config.option('--editor [cmd]', (o) => {
|
|
2759
|
+
o.description('The command to launch your preferred text editor.')
|
|
2760
|
+
})
|
|
2761
|
+
config.argument('[action]', (a) => {
|
|
2762
|
+
a.description('The action to perform.')
|
|
2763
|
+
a.choices(['edit', 'list', 'get', 'set', 'reset'])
|
|
2764
|
+
a.default('edit')
|
|
2765
|
+
})
|
|
2766
|
+
config.argument('[key]', (a) => {
|
|
2767
|
+
a.description('Property key (if applicable)')
|
|
2768
|
+
})
|
|
2769
|
+
config.argument('[value]', (a) => {
|
|
2770
|
+
a.description('Value to set (if applicable)')
|
|
2771
|
+
})
|
|
2772
|
+
config.action(
|
|
2773
|
+
async (action: string, key: string, value: string, opts: { editor: string }, config: CommandBuilder) => {
|
|
2774
|
+
const cmd = config.getClosestNonNativeParent()
|
|
2775
|
+
const cfg = cmd.db.config
|
|
2776
|
+
if (!action || action === 'edit') {
|
|
2777
|
+
cfg.edit(opts.editor)
|
|
2778
|
+
return console.info(cfg.getAll())
|
|
2779
|
+
} else if (action === 'list') {
|
|
2780
|
+
return console.dir(
|
|
2781
|
+
cfg.keys.map((key: string) => {
|
|
2782
|
+
return {
|
|
2783
|
+
key,
|
|
2784
|
+
description: cfg.descriptions[key],
|
|
2785
|
+
value: cfg.get(key),
|
|
2786
|
+
defaultValue: cfg.defaultValues,
|
|
2787
|
+
}
|
|
2788
|
+
})
|
|
2789
|
+
)
|
|
2790
|
+
} else if (action === 'get') {
|
|
2791
|
+
if (key) return console.log(cfg.get(key))
|
|
2792
|
+
else return console.log(cfg.getAll())
|
|
2793
|
+
} else if (action === 'set') {
|
|
2794
|
+
const from = cfg.get(key)
|
|
2795
|
+
const parse = cfg.parsers[key]
|
|
2796
|
+
const to = typeof parse === 'function' ? cfg.parsers[key](value) : value
|
|
2797
|
+
cfg.set(key, to)
|
|
2798
|
+
return console.info({ changed: key, from, to })
|
|
2799
|
+
} else if (action === 'reset') {
|
|
2800
|
+
if (key) cfg.reset(key)
|
|
2801
|
+
else cfg.resetAll()
|
|
2802
|
+
return console.info(cfg.getAll())
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
)*/ }
|
|
2344
2806
|
});
|
|
2345
|
-
return this;
|
|
2346
2807
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2808
|
+
/**
|
|
2809
|
+
* Makes aliases for the command.
|
|
2810
|
+
* The idea is to be able to navigate the command tree by only typing the first letter(s) of the command names.
|
|
2811
|
+
*
|
|
2812
|
+
* Example: A command 'cola' would get these aliases: ['c', 'co', 'col'].
|
|
2813
|
+
* However, if there are namespace clashes with sibling subcommands that start with the same letter,
|
|
2814
|
+
* eg. like 'cola' and 'coal' where the first two letters clash, cola's aliases are reduced to only ['col'] and similarly for 'coal'.
|
|
2815
|
+
*
|
|
2816
|
+
* This method creates the aliases, ensuring there are no clashes with sublings, why it is important that the
|
|
2817
|
+
* entire command tree is built before invoking this method.
|
|
2818
|
+
*/ assignSubCommandAliases() {
|
|
2819
|
+
if (this.getAlias() || this.name.length <= 1) return this;
|
|
2820
|
+
const sibAliases = this.getSiblings().map((sib)=>sib.getAliases()).flat();
|
|
2821
|
+
for(let i = 0; i < this.name.length - 1; i++){
|
|
2822
|
+
let cmdAlias = this.name.substring(0, i + 1);
|
|
2823
|
+
let isClash = arrSome(sibAliases, (sibAlias)=>{
|
|
2824
|
+
return cmdAlias === sibAlias;
|
|
2351
2825
|
});
|
|
2352
|
-
|
|
2826
|
+
if (isClash && i === 0) {
|
|
2827
|
+
cmdAlias = cmdAlias.charAt(0).toUpperCase();
|
|
2828
|
+
isClash = arrSome(sibAliases, (sibAlias)=>{
|
|
2829
|
+
return cmdAlias === sibAlias;
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
if (isClash) continue;
|
|
2833
|
+
this.alias(cmdAlias);
|
|
2834
|
+
return this;
|
|
2835
|
+
}
|
|
2836
|
+
return this;
|
|
2353
2837
|
}
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2838
|
+
/**
|
|
2839
|
+
* Automatically set 'short' and 'long' names to options that don't have one assigned yet.
|
|
2840
|
+
*
|
|
2841
|
+
* First, it tries to assign a short name based on the first letter of the option's attribute name
|
|
2842
|
+
* Both lower and upper case are tried. If these is not available, the next letter of the option name is tried.
|
|
2843
|
+
*
|
|
2844
|
+
* If none of the letters of the option name are available, the option is skipped until all other
|
|
2845
|
+
* options have had letters from their names attempted assigned.
|
|
2846
|
+
* Those that remain are assigned the first available letter of the alphabet + 0-9.
|
|
2847
|
+
* If there are 64 options for the command and no more alphanumeric characters are available,
|
|
2848
|
+
* the option is not assigned a short name.
|
|
2849
|
+
*/ assignMissingOptionFlags() {
|
|
2850
|
+
const taken = new Set();
|
|
2851
|
+
for (const anc of this.getAncestorsIterator({
|
|
2852
|
+
includeSelf: true
|
|
2853
|
+
})){
|
|
2854
|
+
anc.options.forEach((opt)=>{
|
|
2855
|
+
if (!opt.short) return;
|
|
2856
|
+
taken.add(opt.short.replace(/^-/g, ''));
|
|
2857
|
+
});
|
|
2858
|
+
}
|
|
2859
|
+
const failed = new Set();
|
|
2860
|
+
// assign letter from option name
|
|
2861
|
+
this.options.forEach((opt)=>{
|
|
2862
|
+
if (opt.short) return;
|
|
2863
|
+
const name = opt.attributeName();
|
|
2864
|
+
for(let c = 0; c < name.length; c++){
|
|
2865
|
+
let char = name.charAt(c).toLowerCase();
|
|
2866
|
+
if (taken.has(char)) {
|
|
2867
|
+
char = char.toUpperCase();
|
|
2868
|
+
if (taken.has(char)) continue;
|
|
2869
|
+
}
|
|
2870
|
+
OptionHelpers.setShort(opt, char);
|
|
2871
|
+
taken.add(char);
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
failed.add(opt);
|
|
2875
|
+
});
|
|
2876
|
+
// assign random alphanumeric character.
|
|
2877
|
+
const name = 'abcdefghijklmnopqrstuvwxyz1234567890';
|
|
2878
|
+
failed.forEach((opt)=>{
|
|
2879
|
+
for(let c = 0; c < name.length; c++){
|
|
2880
|
+
let char = name.charAt(c);
|
|
2881
|
+
if (taken.has(char)) {
|
|
2882
|
+
char = char.toUpperCase();
|
|
2883
|
+
if (taken.has(char)) continue;
|
|
2884
|
+
}
|
|
2885
|
+
OptionHelpers.setShort(opt, char);
|
|
2886
|
+
taken.add(char);
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
});
|
|
2363
2890
|
}
|
|
2364
|
-
|
|
2365
|
-
(()=>
|
|
2366
|
-
|
|
2367
|
-
}
|
|
2368
|
-
|
|
2369
|
-
return new CommandBuilder(name, callback);
|
|
2370
|
-
}
|
|
2371
|
-
class CommandReader extends Base {
|
|
2372
|
-
get action() {
|
|
2373
|
-
return this.cmd.$.builder.meta.actionHandler;
|
|
2891
|
+
assertNoDuplicateCommandNames() {
|
|
2892
|
+
const names = this.$.commands.map((sub)=>sub.aliases().concat(sub.name())).flat();
|
|
2893
|
+
if (names.length !== new Set(names).size) {
|
|
2894
|
+
this.throwCommanderError(`Duplicate subcommand names/aliases found for command, ${this.name}: ${names.join(', ')}`);
|
|
2895
|
+
}
|
|
2374
2896
|
}
|
|
2375
|
-
|
|
2376
|
-
|
|
2897
|
+
hasIdenticalParentOption(option) {
|
|
2898
|
+
const flags = option.flags;
|
|
2899
|
+
for (const anc of this.getAncestorsIterator({
|
|
2900
|
+
includeSelf: true
|
|
2901
|
+
})){
|
|
2902
|
+
for (const opt of anc.$.options){
|
|
2903
|
+
if (flags === opt.flags) {
|
|
2904
|
+
return true;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
return false;
|
|
2377
2909
|
}
|
|
2378
|
-
|
|
2379
|
-
|
|
2910
|
+
assertNoDuplicateOptionNames() {
|
|
2911
|
+
const throwErr = (cmd, opt, anc)=>{
|
|
2912
|
+
this.throwCommanderError(`Duplicate option names > cmd: ${cmd.name}, ${anc ? `anc: ${anc.name}, ` : ''}opt: ${opt}`);
|
|
2913
|
+
};
|
|
2914
|
+
const set = new Set();
|
|
2915
|
+
for (const opt of this.options){
|
|
2916
|
+
if (opt.name() === 'help') continue;
|
|
2917
|
+
if (opt.short) {
|
|
2918
|
+
if (set.has(opt.short)) throwErr(this, opt.short);
|
|
2919
|
+
set.add(opt.short);
|
|
2920
|
+
}
|
|
2921
|
+
if (opt.long) {
|
|
2922
|
+
if (set.has(opt.long)) throwErr(this, opt.long);
|
|
2923
|
+
set.add(opt.long);
|
|
2924
|
+
}
|
|
2925
|
+
if (opt.attributeName()) {
|
|
2926
|
+
if (set.has(opt.attributeName())) throwErr(this, opt.attributeName());
|
|
2927
|
+
set.add(opt.attributeName());
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
for (const anc of this.getAncestorsIterator()){
|
|
2931
|
+
for (const opt of anc.$.options){
|
|
2932
|
+
if (opt.short && set.has(opt.short)) {
|
|
2933
|
+
if (opt.short !== 'V') continue;
|
|
2934
|
+
throwErr(this, opt.short, anc);
|
|
2935
|
+
}
|
|
2936
|
+
if (opt.long && set.has(opt.long)) {
|
|
2937
|
+
throwErr(this, opt.long, anc);
|
|
2938
|
+
}
|
|
2939
|
+
if (opt.attributeName() && set.has(opt.attributeName())) {
|
|
2940
|
+
throwErr(this, opt.attributeName(), anc);
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2380
2944
|
}
|
|
2381
|
-
|
|
2382
|
-
|
|
2945
|
+
initializeActionWrapper() {
|
|
2946
|
+
this.$.action(()=>{
|
|
2947
|
+
const isAsync = isAsyncFunction__default["default"](this.meta.actionHandler) || /^\(.+\) ?=> ?tslib_1\.__awaiter\(/.test(this.meta.actionHandler.toString().trim());
|
|
2948
|
+
if (isAsync) {
|
|
2949
|
+
try {
|
|
2950
|
+
this.handleOutputOptions();
|
|
2951
|
+
const [args, opts] = this.getParsedValidArgsOptsWithPresets();
|
|
2952
|
+
if (opts['help']) return Promise.resolve(this.outputHelp());
|
|
2953
|
+
return Promise.resolve(this.meta.actionHandler.call(this, ...args, opts, this));
|
|
2954
|
+
} catch (error) {
|
|
2955
|
+
this.meta.errorHandler.call(this, error, this);
|
|
2956
|
+
return Promise.reject(error);
|
|
2957
|
+
}
|
|
2958
|
+
} else {
|
|
2959
|
+
try {
|
|
2960
|
+
this.handleOutputOptions();
|
|
2961
|
+
const [args, opts] = this.getParsedValidArgsOptsWithPresets();
|
|
2962
|
+
if (opts['help']) return this.outputHelp();
|
|
2963
|
+
this.meta.actionHandler.call(this, ...args, opts, this);
|
|
2964
|
+
} catch (error) {
|
|
2965
|
+
this.meta.errorHandler.call(this, error, this);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
});
|
|
2383
2969
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
2970
|
+
initializeHelp() {
|
|
2971
|
+
if (this.isRoot) this.globalOption('-h, --help', 'show help');
|
|
2972
|
+
this.$.addHelpCommand('?', 'show help');
|
|
2973
|
+
this.$.configureHelp(DefaultHelpConfig);
|
|
2386
2974
|
}
|
|
2387
|
-
|
|
2388
|
-
|
|
2975
|
+
inheritParentHiddenGlobals() {
|
|
2976
|
+
if (!this.parent) return;
|
|
2977
|
+
for (const opt of this.parent.meta.hiddenGlobalOptions){
|
|
2978
|
+
this.meta.hiddenGlobalOptions.add(opt);
|
|
2979
|
+
}
|
|
2389
2980
|
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2981
|
+
assertCommandNameNotReserved(name) {
|
|
2982
|
+
if (this.meta.isNative) return;
|
|
2983
|
+
if (name === 'u' || name === 'util') {
|
|
2984
|
+
this.throwCommanderError(`Name '${name}' is reserved and is not available as name or alias.`);
|
|
2985
|
+
}
|
|
2392
2986
|
}
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
this.cmd = cmd;
|
|
2987
|
+
assertNotInitialized() {
|
|
2988
|
+
if (this.meta.isInitialized) this.throwCommanderError('Command already initialized: ' + this.name);
|
|
2396
2989
|
}
|
|
2397
2990
|
}
|
|
2991
|
+
process.argv = splitCombinedArgvShorts(process.argv.slice());
|
|
2398
2992
|
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
* @param command The command to check for.
|
|
2402
|
-
*/ async function commandExists(command) {
|
|
2403
|
-
return await lookpath.lookpath(command) !== undefined;
|
|
2404
|
-
}
|
|
2405
|
-
|
|
2406
|
-
/**
|
|
2407
|
-
* Get the absolute file path of given command or undefined it does not exist in the PATH.
|
|
2408
|
-
* @param command The command to check for.
|
|
2409
|
-
*/ async function commandLocation(command) {
|
|
2410
|
-
return await lookpath.lookpath(command);
|
|
2411
|
-
}
|
|
2412
|
-
|
|
2413
|
-
function errorToString(error) {
|
|
2414
|
-
const name = error instanceof Error ? error.name : 'Error';
|
|
2415
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
2416
|
-
return name + ': ' + msg;
|
|
2993
|
+
function CLI(name, callback) {
|
|
2994
|
+
return ()=>new CommandBuilder(name, callback).commander;
|
|
2417
2995
|
}
|
|
2418
2996
|
|
|
2419
2997
|
/**
|
|
2420
|
-
*
|
|
2421
|
-
*
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2998
|
+
* Reads a file and returns the file's contents.
|
|
2999
|
+
*
|
|
3000
|
+
* Identical to fs.readFileSync, except that:
|
|
3001
|
+
* - it uses utf8 encoding by default
|
|
3002
|
+
* - if operation fails, returns undefined instead of throwing
|
|
3003
|
+
*
|
|
3004
|
+
* @param filepath - The path to the file.
|
|
3005
|
+
* @param encoding - The encoding to use when reading the file.
|
|
3006
|
+
* @returns The file's contents or undefined if the file does not exist.
|
|
3007
|
+
*/ function readFileSafeSync(filepath, encoding = 'utf8') {
|
|
3008
|
+
try {
|
|
3009
|
+
return fs__default["default"].readFileSync(filepath, encoding);
|
|
3010
|
+
} catch (error) {
|
|
3011
|
+
return undefined;
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
function execInherit(command) {
|
|
3016
|
+
return new Promise((resolve, reject)=>{
|
|
3017
|
+
try {
|
|
3018
|
+
const buffer = child_process.execSync(command, {
|
|
3019
|
+
stdio: 'inherit'
|
|
3020
|
+
});
|
|
3021
|
+
const string = buffer && buffer.toString ? buffer.toString().trim() : '';
|
|
3022
|
+
resolve(string);
|
|
3023
|
+
} catch (error) {
|
|
3024
|
+
const oError = error instanceof Error ? error : new Error(String(error));
|
|
3025
|
+
reject(oError);
|
|
2440
3026
|
}
|
|
2441
|
-
}
|
|
3027
|
+
});
|
|
2442
3028
|
}
|
|
2443
3029
|
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
3030
|
+
/**
|
|
3031
|
+
* Checks if the given string is in lower case.
|
|
3032
|
+
* @param input The string to be checked.
|
|
3033
|
+
* @example ```ts
|
|
3034
|
+
* strIsLowerCase('hello');
|
|
3035
|
+
* //=> true
|
|
3036
|
+
* strIsLowerCase('Hello');
|
|
3037
|
+
* //=> false
|
|
3038
|
+
* ```
|
|
3039
|
+
*/ function strIsLowerCase(input) {
|
|
3040
|
+
return input === input.toLowerCase();
|
|
2448
3041
|
}
|
|
2449
3042
|
|
|
2450
3043
|
/**
|
|
2451
|
-
*
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
3044
|
+
* Checks if the given string is in upper case.
|
|
3045
|
+
* @param input The string to be checked.
|
|
3046
|
+
* @example ```ts
|
|
3047
|
+
* strIsUpperCase('HELLO');;
|
|
3048
|
+
* //=> true
|
|
3049
|
+
* strIsUpperCase('HEllo');;
|
|
3050
|
+
* //=> false
|
|
3051
|
+
* ```
|
|
3052
|
+
*/ function strIsUpperCase(input) {
|
|
3053
|
+
return input === input.toUpperCase();
|
|
2455
3054
|
}
|
|
2456
3055
|
|
|
2457
3056
|
/**
|
|
2458
|
-
*
|
|
2459
|
-
*
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
3057
|
+
* Returns an array of words in the string
|
|
3058
|
+
* @param word The camel case word to split.
|
|
3059
|
+
* @throws Throws an error if the input is not a string.
|
|
3060
|
+
* @param input input string
|
|
3061
|
+
* @example ```ts
|
|
3062
|
+
* strSplitCamelCase('someCamel10Case')
|
|
3063
|
+
* //=> ['some', 'Camel10', 'Case']
|
|
3064
|
+
* ```
|
|
3065
|
+
*/ function strSplitCamelCase(word) {
|
|
3066
|
+
if (!word) return [];
|
|
3067
|
+
if (word.length <= 2) return [
|
|
3068
|
+
word
|
|
3069
|
+
];
|
|
3070
|
+
const result = [];
|
|
3071
|
+
const lastCharIndex = word.length - 1;
|
|
3072
|
+
let lastSplitIndex = 0;
|
|
3073
|
+
let foundCamelCase = false;
|
|
3074
|
+
for(let i = 1; i < word.length; i++){
|
|
3075
|
+
if (isWordSplitIndex(word, i)) {
|
|
3076
|
+
const sub = word.substring(lastSplitIndex, i);
|
|
3077
|
+
if (sub) {
|
|
3078
|
+
result.push(sub);
|
|
3079
|
+
lastSplitIndex = i;
|
|
3080
|
+
foundCamelCase = true;
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
if (foundCamelCase && i === lastCharIndex) {
|
|
3084
|
+
const sub = word.substring(lastSplitIndex);
|
|
3085
|
+
if (sub) result.push(sub);
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
if (!foundCamelCase) result.push(word);
|
|
3089
|
+
return result;
|
|
3090
|
+
}
|
|
3091
|
+
const regInteger = /\d+/g;
|
|
3092
|
+
const regSpecial = /[^\w]+/g;
|
|
3093
|
+
function isWordSplitIndex(word, index) {
|
|
3094
|
+
return strIsLowerCase(word[index - 1]) && strIsUpperCase(word[index]) && !regInteger.test(word[index - 1]) && !regInteger.test(word[index]) && !regSpecial.test(word[index - 1]) && !regSpecial.test(word[index]);
|
|
2463
3095
|
}
|
|
2464
3096
|
|
|
2465
3097
|
/**
|
|
@@ -2492,33 +3124,6 @@ function getChildren(cmd, options) {
|
|
|
2492
3124
|
};
|
|
2493
3125
|
}
|
|
2494
3126
|
|
|
2495
|
-
/**
|
|
2496
|
-
* Creates a function that validates if the length of the input is equal to the specified length.
|
|
2497
|
-
* The returned function accepts any value with a 'name' property and is named 'isLengthOf' concatenated with the specified length.
|
|
2498
|
-
* @param length - The length to validate against.
|
|
2499
|
-
* @throws if length is not an integer.
|
|
2500
|
-
*/ function createLengthValidator(length) {
|
|
2501
|
-
util.assertThat(length, Number.isInteger);
|
|
2502
|
-
return util.funSetName('isLengthOf' + length, function(input) {
|
|
2503
|
-
return input.length === length;
|
|
2504
|
-
});
|
|
2505
|
-
}
|
|
2506
|
-
|
|
2507
|
-
/**
|
|
2508
|
-
* Creates a parser function that parses a delimited string into a list of typed values.
|
|
2509
|
-
* The parsers array corresponds to the ordering of the expected input values.
|
|
2510
|
-
*
|
|
2511
|
-
* @param delimiter - The delimiter used to split the string into individual values.
|
|
2512
|
-
* @param parsers - An array of functions used to parse each individual value in the string.
|
|
2513
|
-
* @returns A function that takes a delimited string and returns an array of typed values.
|
|
2514
|
-
* @template T - The type of the values in the list.
|
|
2515
|
-
*/ function createTupleListParser(delimiter, parsers) {
|
|
2516
|
-
const isValidLength = createLengthValidator(parsers.length);
|
|
2517
|
-
return function parseList(string) {
|
|
2518
|
-
return util.assertThat(string.split(delimiter).map((str)=>str.trim()), isValidLength).map((str, i)=>parsers[i](str));
|
|
2519
|
-
};
|
|
2520
|
-
}
|
|
2521
|
-
|
|
2522
3127
|
/**
|
|
2523
3128
|
* Parses a string into a boolean.
|
|
2524
3129
|
*
|
|
@@ -2545,138 +3150,107 @@ function isBoolean(value) {
|
|
|
2545
3150
|
return typeof value === 'boolean';
|
|
2546
3151
|
}
|
|
2547
3152
|
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
function
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
}
|
|
2563
|
-
|
|
2564
|
-
function isNumericString(string) {
|
|
2565
|
-
return /^-?[0-9,.]+$/.test(string.trim());
|
|
2566
|
-
}
|
|
2567
|
-
|
|
3153
|
+
Object.defineProperty(exports, 'removeFile', {
|
|
3154
|
+
enumerable: true,
|
|
3155
|
+
get: function () { return fs.remove; }
|
|
3156
|
+
});
|
|
3157
|
+
Object.defineProperty(exports, 'writeFileSafeSync', {
|
|
3158
|
+
enumerable: true,
|
|
3159
|
+
get: function () { return fs.outputFileSync; }
|
|
3160
|
+
});
|
|
3161
|
+
Object.defineProperty(exports, 'writeFileSync', {
|
|
3162
|
+
enumerable: true,
|
|
3163
|
+
get: function () { return fs.writeFileSync; }
|
|
3164
|
+
});
|
|
3165
|
+
Object.defineProperty(exports, 'writeJsonFileSafe', {
|
|
3166
|
+
enumerable: true,
|
|
3167
|
+
get: function () { return fs.outputJson; }
|
|
3168
|
+
});
|
|
2568
3169
|
exports.AbstractJsonFileSection = AbstractJsonFileSection;
|
|
2569
|
-
exports.
|
|
2570
|
-
exports.AbstractValidatorSelector = AbstractValidatorSelector;
|
|
3170
|
+
exports.AppDataSection = AppDataSection;
|
|
2571
3171
|
exports.ArgumentBuilder = ArgumentBuilder;
|
|
2572
3172
|
exports.ArgumentParserSelector = ArgumentParserSelector;
|
|
2573
3173
|
exports.ArgumentReader = ArgumentReader;
|
|
2574
3174
|
exports.ArgumentValidatorSelector = ArgumentValidatorSelector;
|
|
2575
|
-
exports.Base = Base;
|
|
2576
3175
|
exports.CLI = CLI;
|
|
2577
3176
|
exports.CommandBuilder = CommandBuilder;
|
|
2578
3177
|
exports.CommandBuilderMetaData = CommandBuilderMetaData;
|
|
2579
3178
|
exports.CommandFeatureSelector = CommandFeatureSelector;
|
|
2580
|
-
exports.CommandReader = CommandReader;
|
|
2581
3179
|
exports.ConfigSection = ConfigSection;
|
|
3180
|
+
exports.DefaultHelpConfig = DefaultHelpConfig;
|
|
2582
3181
|
exports.ErrorParser = ErrorParser;
|
|
2583
3182
|
exports.JsonDB = JsonDB;
|
|
2584
3183
|
exports.JsonFile = JsonFile;
|
|
2585
|
-
exports.JsonFileError = JsonFileError;
|
|
2586
3184
|
exports.MethodDisabler = MethodDisabler;
|
|
2587
3185
|
exports.OptionArgumentParserSelector = OptionArgumentParserSelector;
|
|
2588
3186
|
exports.OptionArgumentValidatorSelector = OptionArgumentValidatorSelector;
|
|
2589
3187
|
exports.OptionBuilder = OptionBuilder;
|
|
3188
|
+
exports.OptionHelpers = OptionHelpers;
|
|
2590
3189
|
exports.OptionReader = OptionReader;
|
|
2591
3190
|
exports.OutputManager = OutputManager;
|
|
3191
|
+
exports.ParserSelector = ParserSelector;
|
|
2592
3192
|
exports.PresetsSection = PresetsSection;
|
|
2593
|
-
exports.
|
|
2594
|
-
exports.addConfigCommands = addConfigCommands;
|
|
2595
|
-
exports.addPresetsCommands = addPresetsCommands;
|
|
2596
|
-
exports.addUtilCommands = addUtilCommands;
|
|
3193
|
+
exports.ValidatorSelector = ValidatorSelector;
|
|
2597
3194
|
exports.arrAssign = arrAssign;
|
|
2598
|
-
exports.
|
|
2599
|
-
exports.
|
|
2600
|
-
exports.
|
|
2601
|
-
exports.
|
|
2602
|
-
exports.assertValidArguments = assertValidArguments;
|
|
2603
|
-
exports.assertValidOptions = assertValidOptions;
|
|
2604
|
-
exports.assertValidPreset = assertValidPreset;
|
|
2605
|
-
exports.autoAssignMissingOptionFlags = autoAssignMissingOptionFlags;
|
|
2606
|
-
exports.autoAssignSubCommandAliases = autoAssignSubCommandAliases;
|
|
2607
|
-
exports.combineVariadicArgs = combineVariadicArgs;
|
|
2608
|
-
exports.commandExists = commandExists;
|
|
2609
|
-
exports.commandLocation = commandLocation;
|
|
2610
|
-
exports.configureHelp = configureHelp;
|
|
3195
|
+
exports.arrLast = arrLast;
|
|
3196
|
+
exports.arrSome = arrSome;
|
|
3197
|
+
exports.commanderBackRefs = commanderBackRefs;
|
|
3198
|
+
exports.countInstance = countInstance;
|
|
2611
3199
|
exports.createArrayMerger = createArrayMerger;
|
|
2612
3200
|
exports.createBooleanParser = createBooleanParser;
|
|
2613
|
-
exports.createConfig = createConfig;
|
|
2614
|
-
exports.createLengthValidator = createLengthValidator;
|
|
2615
3201
|
exports.createObjectMerger = createObjectMerger;
|
|
2616
|
-
exports.createPresets = createPresets;
|
|
2617
|
-
exports.createTupleListParser = createTupleListParser;
|
|
2618
3202
|
exports.createTypedArrayValidator = createTypedArrayValidator;
|
|
2619
3203
|
exports.createTypedListParser = createTypedListParser;
|
|
2620
|
-
exports.
|
|
2621
|
-
exports.
|
|
2622
|
-
exports.ensureBackRefToCommandBuilder = ensureBackRefToCommandBuilder;
|
|
3204
|
+
exports.defaultOpenInEditorCommand = defaultOpenInEditorCommand;
|
|
3205
|
+
exports.ensureThat = ensureThat;
|
|
2623
3206
|
exports.errParseStack = errParseStack;
|
|
2624
3207
|
exports.errPrettyStack = errPrettyStack;
|
|
2625
3208
|
exports.errToObject = errToObject;
|
|
2626
|
-
exports.
|
|
2627
|
-
exports.escapeShellCommandArgument = escapeShellCommandArgument;
|
|
2628
|
-
exports.forEachChildRecursive = forEachChildRecursive;
|
|
3209
|
+
exports.execInherit = execInherit;
|
|
2629
3210
|
exports.formatTableForTerminal = formatTableForTerminal;
|
|
2630
|
-
exports.
|
|
2631
|
-
exports.
|
|
2632
|
-
exports.getChildren = getChildren;
|
|
2633
|
-
exports.getClosestNonNativeParent = getClosestNonNativeParent;
|
|
2634
|
-
exports.getGlobalOptions = getGlobalOptions;
|
|
2635
|
-
exports.getJsonFilepath = getJsonFilepath;
|
|
2636
|
-
exports.getOptionArgumentName = getOptionArgumentName;
|
|
2637
|
-
exports.getOwnAndGlobalOptions = getOwnAndGlobalOptions;
|
|
2638
|
-
exports.getPresetArgsAndOpts = getPresetArgsAndOpts;
|
|
2639
|
-
exports.getRootCommand = getRootCommand;
|
|
2640
|
-
exports.getSiblings = getSiblings;
|
|
2641
|
-
exports.handleError = handleError;
|
|
2642
|
-
exports.handleOutputOptions = handleOutputOptions;
|
|
2643
|
-
exports.hasVariadicArguments = hasVariadicArguments;
|
|
2644
|
-
exports.initializeCommand = initializeCommand;
|
|
3211
|
+
exports.funSetName = funSetName;
|
|
3212
|
+
exports.getTempDataPath = getTempDataPath;
|
|
2645
3213
|
exports.isArray = isArray;
|
|
2646
3214
|
exports.isBoolean = isBoolean;
|
|
3215
|
+
exports.isFunction = isFunction;
|
|
2647
3216
|
exports.isInteger = isInteger;
|
|
2648
|
-
exports.isIntegerArray = isIntegerArray;
|
|
2649
3217
|
exports.isNamedFunction = isNamedFunction;
|
|
2650
3218
|
exports.isNamedFunctionArray = isNamedFunctionArray;
|
|
2651
|
-
exports.
|
|
2652
|
-
exports.
|
|
2653
|
-
exports.
|
|
2654
|
-
exports.
|
|
3219
|
+
exports.isOSX = isOSX;
|
|
3220
|
+
exports.isObject = isObject;
|
|
3221
|
+
exports.isPlainObject = isPlainObject;
|
|
3222
|
+
exports.isPrimitive = isPrimitive;
|
|
2655
3223
|
exports.isString = isString;
|
|
2656
3224
|
exports.isStringArray = isStringArray;
|
|
2657
3225
|
exports.isStringWithNoSpacesOrDashes = isStringWithNoSpacesOrDashes;
|
|
3226
|
+
exports.isValidNumber = isValidNumber;
|
|
3227
|
+
exports.isVsCodeInstalled = isVsCodeInstalled;
|
|
3228
|
+
exports.isWindows = isWindows;
|
|
2658
3229
|
exports.objAssign = objAssign;
|
|
2659
|
-
exports.
|
|
2660
|
-
exports.optHasArgument = optHasArgument;
|
|
2661
|
-
exports.optsWithGlobalsParsed = optsWithGlobalsParsed;
|
|
2662
|
-
exports.padArgsWithUndefinedUntilExpectedLength = padArgsWithUndefinedUntilExpectedLength;
|
|
2663
|
-
exports.parseArguments = parseArguments;
|
|
3230
|
+
exports.objUpdatePropertyDescriptors = objUpdatePropertyDescriptors;
|
|
2664
3231
|
exports.parseBoolean = parseBoolean;
|
|
2665
3232
|
exports.parseInteger = parseInteger;
|
|
2666
3233
|
exports.parseNumber = parseNumber;
|
|
2667
|
-
exports.parseOptions = parseOptions;
|
|
2668
3234
|
exports.parseString = parseString;
|
|
2669
|
-
exports.
|
|
2670
|
-
exports.
|
|
2671
|
-
exports.
|
|
2672
|
-
exports.
|
|
2673
|
-
exports.
|
|
2674
|
-
exports.
|
|
3235
|
+
exports.printCounts = printCounts;
|
|
3236
|
+
exports.promptUserEditInTextEditorSync = promptUserEditInTextEditorSync;
|
|
3237
|
+
exports.promptUserEditJsonInTextEditorSync = promptUserEditJsonInTextEditorSync;
|
|
3238
|
+
exports.readFileSafeSync = readFileSafeSync;
|
|
3239
|
+
exports.readFileSync = readFileSync;
|
|
3240
|
+
exports.readJsonFileSafeSync = readJsonFileSafeSync;
|
|
2675
3241
|
exports.realizeLazyProperty = realizeLazyProperty;
|
|
2676
|
-
exports.
|
|
2677
|
-
exports.
|
|
2678
|
-
exports.setOptionShortName = setOptionShortName;
|
|
3242
|
+
exports.regexEscapeString = regexEscapeString;
|
|
3243
|
+
exports.setNonEnumerable = setNonEnumerable;
|
|
2679
3244
|
exports.splitCombinedArgvShorts = splitCombinedArgvShorts;
|
|
2680
|
-
exports.
|
|
2681
|
-
exports.
|
|
2682
|
-
exports.
|
|
3245
|
+
exports.strEnsureStartsWith = strEnsureStartsWith;
|
|
3246
|
+
exports.strFirstCharToUpperCase = strFirstCharToUpperCase;
|
|
3247
|
+
exports.strIsLowerCase = strIsLowerCase;
|
|
3248
|
+
exports.strIsUpperCase = strIsUpperCase;
|
|
3249
|
+
exports.strSplitCamelCase = strSplitCamelCase;
|
|
3250
|
+
exports.tempFileSync = tempFileSync;
|
|
3251
|
+
Object.keys(commander).forEach(function (k) {
|
|
3252
|
+
if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
|
|
3253
|
+
enumerable: true,
|
|
3254
|
+
get: function () { return commander[k]; }
|
|
3255
|
+
});
|
|
3256
|
+
});
|