@oclif/core 3.0.0-beta.18 → 3.0.0-beta.19
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/lib/args.js +4 -4
- package/lib/cli-ux/action/base.js +1 -0
- package/lib/cli-ux/action/spinner.js +3 -5
- package/lib/cli-ux/action/spinners.js +1 -1
- package/lib/cli-ux/config.js +7 -6
- package/lib/cli-ux/flush.js +2 -2
- package/lib/cli-ux/index.js +1 -1
- package/lib/cli-ux/list.js +3 -3
- package/lib/cli-ux/prompt.js +8 -3
- package/lib/cli-ux/styled/object.js +2 -2
- package/lib/cli-ux/styled/table.js +23 -20
- package/lib/cli-ux/wait.js +1 -1
- package/lib/command.js +9 -9
- package/lib/config/config.d.ts +8 -8
- package/lib/config/config.js +45 -39
- package/lib/config/plugin-loader.js +7 -7
- package/lib/config/plugin.js +26 -23
- package/lib/config/ts-node.js +8 -10
- package/lib/config/util.js +2 -2
- package/lib/errors/errors/cli.js +1 -0
- package/lib/errors/errors/pretty-print.js +2 -1
- package/lib/errors/handle.js +2 -1
- package/lib/errors/logger.js +2 -2
- package/lib/flags.d.ts +4 -4
- package/lib/flags.js +3 -3
- package/lib/help/command.js +43 -32
- package/lib/help/docopts.js +5 -5
- package/lib/help/formatter.js +7 -7
- package/lib/help/index.js +39 -42
- package/lib/help/root.js +2 -7
- package/lib/help/util.js +1 -1
- package/lib/interfaces/hooks.d.ts +3 -3
- package/lib/interfaces/index.d.ts +1 -1
- package/lib/interfaces/parser.d.ts +15 -15
- package/lib/interfaces/pjson.d.ts +1 -1
- package/lib/module-loader.d.ts +8 -8
- package/lib/module-loader.js +12 -9
- package/lib/parser/errors.d.ts +1 -1
- package/lib/parser/errors.js +9 -9
- package/lib/parser/help.js +2 -3
- package/lib/parser/parse.js +64 -43
- package/lib/parser/validate.js +37 -21
- package/lib/performance.js +9 -6
- package/lib/util/aggregate-flags.js +1 -3
- package/lib/util/cache-command.js +28 -20
- package/lib/util/index.js +4 -6
- package/package.json +13 -11
package/lib/module-loader.js
CHANGED
|
@@ -33,6 +33,7 @@ async function load(config, modulePath) {
|
|
|
33
33
|
let filePath;
|
|
34
34
|
let isESM;
|
|
35
35
|
try {
|
|
36
|
+
;
|
|
36
37
|
({ isESM, filePath } = resolvePath(config, modulePath));
|
|
37
38
|
return isESM ? await import((0, node_url_1.pathToFileURL)(filePath).href) : require(filePath);
|
|
38
39
|
}
|
|
@@ -65,6 +66,7 @@ async function loadWithData(config, modulePath) {
|
|
|
65
66
|
let filePath;
|
|
66
67
|
let isESM;
|
|
67
68
|
try {
|
|
69
|
+
;
|
|
68
70
|
({ isESM, filePath } = resolvePath(config, modulePath));
|
|
69
71
|
const module = isESM ? await import((0, node_url_1.pathToFileURL)(filePath).href) : require(filePath);
|
|
70
72
|
return { isESM, module, filePath };
|
|
@@ -114,14 +116,14 @@ async function loadWithDataFromManifest(cached, modulePath) {
|
|
|
114
116
|
}
|
|
115
117
|
exports.loadWithDataFromManifest = loadWithDataFromManifest;
|
|
116
118
|
/**
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
* For `.js` files uses `getPackageType` to determine if `type` is set to `module` in associated `package.json`. If
|
|
120
|
+
* the `modulePath` provided ends in `.mjs` it is assumed to be ESM.
|
|
121
|
+
*
|
|
122
|
+
* @param {string} filePath - File path to test.
|
|
123
|
+
*
|
|
124
|
+
* @returns {boolean} The modulePath is an ES Module.
|
|
125
|
+
* @see https://www.npmjs.com/package/get-package-type
|
|
126
|
+
*/
|
|
125
127
|
function isPathModule(filePath) {
|
|
126
128
|
const extension = (0, node_path_1.extname)(filePath).toLowerCase();
|
|
127
129
|
switch (extension) {
|
|
@@ -160,7 +162,8 @@ function resolvePath(config, modulePath) {
|
|
|
160
162
|
isESM = isPathModule(filePath);
|
|
161
163
|
}
|
|
162
164
|
catch {
|
|
163
|
-
filePath =
|
|
165
|
+
filePath =
|
|
166
|
+
(isPlugin(config) ? (0, ts_node_1.tsPath)(config.root, modulePath, config) : (0, ts_node_1.tsPath)(config.root, modulePath)) ?? modulePath;
|
|
164
167
|
let fileExists = false;
|
|
165
168
|
let isDirectory = false;
|
|
166
169
|
if ((0, node_fs_1.existsSync)(filePath)) {
|
package/lib/parser/errors.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare class InvalidArgsSpecError extends CLIParseError {
|
|
|
22
22
|
}
|
|
23
23
|
export declare class RequiredArgsError extends CLIParseError {
|
|
24
24
|
args: Arg<any>[];
|
|
25
|
-
constructor({ args, parse, flagsWithMultiple }: CLIParseErrorOptions & {
|
|
25
|
+
constructor({ args, parse, flagsWithMultiple, }: CLIParseErrorOptions & {
|
|
26
26
|
args: Arg<any>[];
|
|
27
27
|
flagsWithMultiple?: string[];
|
|
28
28
|
});
|
package/lib/parser/errors.js
CHANGED
|
@@ -6,7 +6,7 @@ const errors_1 = require("../errors");
|
|
|
6
6
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
7
|
const help_1 = require("./help");
|
|
8
8
|
const list_1 = require("../cli-ux/list");
|
|
9
|
-
const
|
|
9
|
+
const index_1 = require("../util/index");
|
|
10
10
|
var errors_2 = require("../errors");
|
|
11
11
|
Object.defineProperty(exports, "CLIError", { enumerable: true, get: function () { return errors_2.CLIError; } });
|
|
12
12
|
class CLIParseError extends errors_1.CLIError {
|
|
@@ -22,9 +22,9 @@ class InvalidArgsSpecError extends CLIParseError {
|
|
|
22
22
|
args;
|
|
23
23
|
constructor({ args, parse }) {
|
|
24
24
|
let message = 'Invalid argument spec';
|
|
25
|
-
const namedArgs = Object.values(args).filter(a => a.name);
|
|
25
|
+
const namedArgs = Object.values(args).filter((a) => a.name);
|
|
26
26
|
if (namedArgs.length > 0) {
|
|
27
|
-
const list = (0, list_1.renderList)(namedArgs.map(a => [`${a.name} (${a.required ? 'required' : 'optional'})`, a.description]));
|
|
27
|
+
const list = (0, list_1.renderList)(namedArgs.map((a) => [`${a.name} (${a.required ? 'required' : 'optional'})`, a.description]));
|
|
28
28
|
message += `:\n${list}`;
|
|
29
29
|
}
|
|
30
30
|
super({ parse, message });
|
|
@@ -34,15 +34,15 @@ class InvalidArgsSpecError extends CLIParseError {
|
|
|
34
34
|
exports.InvalidArgsSpecError = InvalidArgsSpecError;
|
|
35
35
|
class RequiredArgsError extends CLIParseError {
|
|
36
36
|
args;
|
|
37
|
-
constructor({ args, parse, flagsWithMultiple }) {
|
|
37
|
+
constructor({ args, parse, flagsWithMultiple, }) {
|
|
38
38
|
let message = `Missing ${args.length} required arg${args.length === 1 ? '' : 's'}`;
|
|
39
|
-
const namedArgs = args.filter(a => a.name);
|
|
39
|
+
const namedArgs = args.filter((a) => a.name);
|
|
40
40
|
if (namedArgs.length > 0) {
|
|
41
|
-
const list = (0, list_1.renderList)(namedArgs.map(a => [a.name, a.description]));
|
|
41
|
+
const list = (0, list_1.renderList)(namedArgs.map((a) => [a.name, a.description]));
|
|
42
42
|
message += `:\n${list}`;
|
|
43
43
|
}
|
|
44
44
|
if (flagsWithMultiple?.length) {
|
|
45
|
-
const flags = flagsWithMultiple.map(f => `--${f}`).join(', ');
|
|
45
|
+
const flags = flagsWithMultiple.map((f) => `--${f}`).join(', ');
|
|
46
46
|
message += `\n\nNote: ${flags} allow${flagsWithMultiple.length === 1 ? 's' : ''} multiple values. Because of this you need to provide all arguments before providing ${flagsWithMultiple.length === 1 ? 'that flag' : 'those flags'}.`;
|
|
47
47
|
message += '\nAlternatively, you can use "--" to signify the end of the flags and the beginning of arguments.';
|
|
48
48
|
}
|
|
@@ -95,8 +95,8 @@ class ArgInvalidOptionError extends CLIParseError {
|
|
|
95
95
|
exports.ArgInvalidOptionError = ArgInvalidOptionError;
|
|
96
96
|
class FailedFlagValidationError extends CLIParseError {
|
|
97
97
|
constructor({ parse, failed }) {
|
|
98
|
-
const reasons = failed.map(r => r.reason);
|
|
99
|
-
const deduped = (0,
|
|
98
|
+
const reasons = failed.map((r) => r.reason);
|
|
99
|
+
const deduped = (0, index_1.uniq)(reasons);
|
|
100
100
|
const errString = deduped.length === 1 ? 'error' : 'errors';
|
|
101
101
|
const message = `The following ${errString} occurred:\n ${chalk_1.default.dim(deduped.join('\n '))}`;
|
|
102
102
|
super({ parse, message });
|
package/lib/parser/help.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.flagUsages = exports.flagUsage = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
6
|
-
const
|
|
6
|
+
const index_1 = require("../util/index");
|
|
7
7
|
function flagUsage(flag, options = {}) {
|
|
8
8
|
const label = [];
|
|
9
9
|
if (flag.helpLabel) {
|
|
@@ -26,7 +26,6 @@ exports.flagUsage = flagUsage;
|
|
|
26
26
|
function flagUsages(flags, options = {}) {
|
|
27
27
|
if (flags.length === 0)
|
|
28
28
|
return [];
|
|
29
|
-
return (0,
|
|
30
|
-
.map(f => flagUsage(f, options));
|
|
29
|
+
return (0, index_1.sortBy)(flags, (f) => [f.char ? -1 : 1, f.char, f.name]).map((f) => flagUsage(f, options));
|
|
31
30
|
}
|
|
32
31
|
exports.flagUsages = flagUsages;
|
package/lib/parser/parse.js
CHANGED
|
@@ -3,13 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Parser = void 0;
|
|
4
4
|
/* eslint-disable no-await-in-loop */
|
|
5
5
|
const errors_1 = require("./errors");
|
|
6
|
-
const
|
|
6
|
+
const index_1 = require("../util/index");
|
|
7
7
|
const node_readline_1 = require("node:readline");
|
|
8
8
|
let debug;
|
|
9
9
|
try {
|
|
10
|
-
debug =
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
debug =
|
|
11
|
+
process.env.CLI_FLAGS_DEBUG === '1'
|
|
12
|
+
? require('debug')('../parser')
|
|
13
|
+
: () => {
|
|
14
|
+
// noop
|
|
15
|
+
};
|
|
13
16
|
}
|
|
14
17
|
catch {
|
|
15
18
|
debug = () => {
|
|
@@ -25,7 +28,7 @@ const readStdin = async () => {
|
|
|
25
28
|
// Because of this, we have to set a timeout to prevent the process from hanging.
|
|
26
29
|
if (stdin.isTTY)
|
|
27
30
|
return null;
|
|
28
|
-
return new Promise(resolve => {
|
|
31
|
+
return new Promise((resolve) => {
|
|
29
32
|
let result = '';
|
|
30
33
|
const ac = new AbortController();
|
|
31
34
|
const { signal } = ac;
|
|
@@ -35,7 +38,7 @@ const readStdin = async () => {
|
|
|
35
38
|
output: stdout,
|
|
36
39
|
terminal: false,
|
|
37
40
|
});
|
|
38
|
-
rl.on('line', line => {
|
|
41
|
+
rl.on('line', (line) => {
|
|
39
42
|
result += line;
|
|
40
43
|
});
|
|
41
44
|
rl.once('close', () => {
|
|
@@ -72,8 +75,8 @@ class Parser {
|
|
|
72
75
|
this.context = input.context ?? {};
|
|
73
76
|
this.argv = [...input.argv];
|
|
74
77
|
this._setNames();
|
|
75
|
-
this.booleanFlags = (0,
|
|
76
|
-
this.flagAliases = Object.fromEntries(Object.values(input.flags).flatMap(flag =>
|
|
78
|
+
this.booleanFlags = (0, index_1.pickBy)(input.flags, (f) => f.type === 'boolean');
|
|
79
|
+
this.flagAliases = Object.fromEntries(Object.values(input.flags).flatMap((flag) => [...(flag.aliases ?? []), ...(flag.charAliases ?? [])].map((a) => [a, flag])));
|
|
77
80
|
}
|
|
78
81
|
async parse() {
|
|
79
82
|
this._debugInput();
|
|
@@ -94,13 +97,13 @@ class Parser {
|
|
|
94
97
|
}
|
|
95
98
|
const flag = this.input.flags[name];
|
|
96
99
|
if (flag.type === 'option') {
|
|
97
|
-
if (!flag.multiple && this.raw.some(o => o.type === 'flag' && o.flag === name)) {
|
|
100
|
+
if (!flag.multiple && this.raw.some((o) => o.type === 'flag' && o.flag === name)) {
|
|
98
101
|
throw new errors_1.CLIError(`Flag --${name} can only be specified once`);
|
|
99
102
|
}
|
|
100
103
|
this.currentFlag = flag;
|
|
101
104
|
const input = isLong || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
|
|
102
105
|
// if the value ends up being one of the command's flags, the user didn't provide an input
|
|
103
|
-
if (
|
|
106
|
+
if (typeof input !== 'string' || this.findFlag(input).name) {
|
|
104
107
|
throw new errors_1.CLIError(`Flag --${name} expects a value`);
|
|
105
108
|
}
|
|
106
109
|
this.raw.push({ type: 'flag', flag: flag.name, input });
|
|
@@ -187,41 +190,50 @@ class Parser {
|
|
|
187
190
|
}
|
|
188
191
|
};
|
|
189
192
|
/* Could add a valueFunction (if there is a value/env/default) and could metadata.
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
* Value function can be resolved later.
|
|
194
|
+
*/
|
|
192
195
|
const addValueFunction = (fws) => {
|
|
193
196
|
const tokenLength = fws.tokens?.length;
|
|
194
197
|
// user provided some input
|
|
195
198
|
if (tokenLength) {
|
|
196
199
|
// boolean
|
|
197
|
-
if (fws.inputFlag.flag.type === 'boolean' && (0,
|
|
200
|
+
if (fws.inputFlag.flag.type === 'boolean' && (0, index_1.last)(fws.tokens)?.input) {
|
|
198
201
|
return {
|
|
199
202
|
...fws,
|
|
200
|
-
valueFunction: async (i) => parseFlagOrThrowError((0,
|
|
203
|
+
valueFunction: async (i) => parseFlagOrThrowError((0, index_1.last)(i.tokens)?.input !== `--no-${i.inputFlag.name}`, i.inputFlag.flag, this.context, (0, index_1.last)(i.tokens)),
|
|
201
204
|
};
|
|
202
205
|
}
|
|
203
206
|
// multiple with custom delimiter
|
|
204
207
|
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.delimiter && fws.inputFlag.flag.multiple) {
|
|
205
208
|
return {
|
|
206
209
|
...fws,
|
|
207
|
-
valueFunction: async (i) => (await Promise.all((
|
|
210
|
+
valueFunction: async (i) => (await Promise.all((i.tokens ?? [])
|
|
211
|
+
.flatMap((token) => token.input.split(i.inputFlag.flag.delimiter ?? ','))
|
|
208
212
|
// trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
|
|
209
|
-
.map(v => v
|
|
210
|
-
.
|
|
213
|
+
.map((v) => v
|
|
214
|
+
.trim()
|
|
215
|
+
.replace(/^"(.*)"$/, '$1')
|
|
216
|
+
.replace(/^'(.*)'$/, '$1'))
|
|
217
|
+
.map(async (v) => parseFlagOrThrowError(v, i.inputFlag.flag, this.context, {
|
|
218
|
+
...(0, index_1.last)(i.tokens),
|
|
219
|
+
input: v,
|
|
220
|
+
}))))
|
|
221
|
+
// eslint-disable-next-line unicorn/no-await-expression-member
|
|
222
|
+
.map((v) => validateOptions(i.inputFlag.flag, v)),
|
|
211
223
|
};
|
|
212
224
|
}
|
|
213
225
|
// multiple in the oclif-core style
|
|
214
226
|
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.multiple) {
|
|
215
227
|
return {
|
|
216
228
|
...fws,
|
|
217
|
-
valueFunction: async (i) => Promise.all((fws.tokens ?? []).map(token => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, token.input), i.inputFlag.flag, this.context, token))),
|
|
229
|
+
valueFunction: async (i) => Promise.all((fws.tokens ?? []).map((token) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, token.input), i.inputFlag.flag, this.context, token))),
|
|
218
230
|
};
|
|
219
231
|
}
|
|
220
232
|
// simple option flag
|
|
221
233
|
if (fws.inputFlag.flag.type === 'option') {
|
|
222
234
|
return {
|
|
223
235
|
...fws,
|
|
224
|
-
valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, (0,
|
|
236
|
+
valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, (0, index_1.last)(fws.tokens)?.input), i.inputFlag.flag, this.context, (0, index_1.last)(fws.tokens)),
|
|
225
237
|
};
|
|
226
238
|
}
|
|
227
239
|
}
|
|
@@ -237,7 +249,7 @@ class Parser {
|
|
|
237
249
|
if (fws.inputFlag.flag.type === 'boolean') {
|
|
238
250
|
return {
|
|
239
251
|
...fws,
|
|
240
|
-
valueFunction: async (i) => (0,
|
|
252
|
+
valueFunction: async (i) => (0, index_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false'),
|
|
241
253
|
};
|
|
242
254
|
}
|
|
243
255
|
}
|
|
@@ -245,7 +257,8 @@ class Parser {
|
|
|
245
257
|
// eslint-disable-next-line no-constant-binary-expression, valid-typeof
|
|
246
258
|
if (typeof fws.inputFlag.flag.default !== undefined) {
|
|
247
259
|
return {
|
|
248
|
-
...fws,
|
|
260
|
+
...fws,
|
|
261
|
+
metadata: { setFromDefault: true },
|
|
249
262
|
valueFunction: typeof fws.inputFlag.flag.default === 'function'
|
|
250
263
|
? (i, allFlags = {}) => fws.inputFlag.flag.default({ options: i.inputFlag.flag, flags: allFlags })
|
|
251
264
|
: async () => fws.inputFlag.flag.default,
|
|
@@ -257,17 +270,19 @@ class Parser {
|
|
|
257
270
|
const addHelpFunction = (fws) => {
|
|
258
271
|
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.defaultHelp) {
|
|
259
272
|
return {
|
|
260
|
-
...fws,
|
|
261
|
-
|
|
262
|
-
? (i, flags, ...context) =>
|
|
273
|
+
...fws,
|
|
274
|
+
helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function'
|
|
275
|
+
? (i, flags, ...context) =>
|
|
263
276
|
// @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
|
|
264
|
-
|
|
277
|
+
i.inputFlag.flag.defaultHelp({ options: i.inputFlag, flags }, ...context)
|
|
278
|
+
: // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
|
|
279
|
+
(i) => i.inputFlag.flag.defaultHelp,
|
|
265
280
|
};
|
|
266
281
|
}
|
|
267
282
|
return fws;
|
|
268
283
|
};
|
|
269
284
|
const addDefaultHelp = async (fwsArray) => {
|
|
270
|
-
const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter(fws => !fws.metadata?.setFromDefault));
|
|
285
|
+
const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter((fws) => !fws.metadata?.setFromDefault));
|
|
271
286
|
return Promise.all(fwsArray.map(async (fws) => {
|
|
272
287
|
try {
|
|
273
288
|
if (fws.helpFunction) {
|
|
@@ -286,26 +301,32 @@ class Parser {
|
|
|
286
301
|
return fws;
|
|
287
302
|
}));
|
|
288
303
|
};
|
|
289
|
-
const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.filter(fws => fws.value !== undefined)
|
|
290
|
-
.map(fws => [fws.inputFlag.name, fws.value]));
|
|
304
|
+
const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.filter((fws) => fws.value !== undefined).map((fws) => [fws.inputFlag.name, fws.value]));
|
|
291
305
|
const flagTokenMap = this.mapAndValidateFlags();
|
|
292
306
|
const flagsWithValues = await Promise.all(Object.entries(this.input.flags)
|
|
293
307
|
// we check them if they have a token, or might have env, default, or defaultHelp. Also include booleans so they get their default value
|
|
294
|
-
.filter(([name, flag]) => flag.type === 'boolean' ||
|
|
308
|
+
.filter(([name, flag]) => flag.type === 'boolean' ||
|
|
309
|
+
flag.env ||
|
|
310
|
+
flag.default !== undefined ||
|
|
311
|
+
'defaultHelp' in flag ||
|
|
312
|
+
flagTokenMap.has(name))
|
|
295
313
|
// match each possible flag to its token, if there is one
|
|
296
314
|
.map(([name, flag]) => ({ inputFlag: { name, flag }, tokens: flagTokenMap.get(name) }))
|
|
297
|
-
.map(fws => addValueFunction(fws))
|
|
298
|
-
.filter(fws => fws.valueFunction !== undefined)
|
|
299
|
-
.map(fws => addHelpFunction(fws))
|
|
315
|
+
.map((fws) => addValueFunction(fws))
|
|
316
|
+
.filter((fws) => fws.valueFunction !== undefined)
|
|
317
|
+
.map((fws) => addHelpFunction(fws))
|
|
300
318
|
// we can't apply the default values until all the other flags are resolved because `flag.default` can reference other flags
|
|
301
319
|
.map(async (fws) => (fws.metadata?.setFromDefault ? fws : { ...fws, value: await fws.valueFunction?.(fws) })));
|
|
302
|
-
const valueReference = fwsArrayToObject(flagsWithValues.filter(fws => !fws.metadata?.setFromDefault));
|
|
303
|
-
const flagsWithAllValues = await Promise.all(flagsWithValues
|
|
304
|
-
|
|
305
|
-
|
|
320
|
+
const valueReference = fwsArrayToObject(flagsWithValues.filter((fws) => !fws.metadata?.setFromDefault));
|
|
321
|
+
const flagsWithAllValues = await Promise.all(flagsWithValues.map(async (fws) => fws.metadata?.setFromDefault ? { ...fws, value: await fws.valueFunction?.(fws, valueReference) } : fws));
|
|
322
|
+
const finalFlags = flagsWithAllValues.some((fws) => typeof fws.helpFunction === 'function')
|
|
323
|
+
? await addDefaultHelp(flagsWithAllValues)
|
|
324
|
+
: flagsWithAllValues;
|
|
306
325
|
return {
|
|
307
326
|
flags: fwsArrayToObject(finalFlags),
|
|
308
|
-
metadata: {
|
|
327
|
+
metadata: {
|
|
328
|
+
flags: Object.fromEntries(finalFlags.filter((fws) => fws.metadata).map((fws) => [fws.inputFlag.name, fws.metadata])),
|
|
329
|
+
},
|
|
309
330
|
};
|
|
310
331
|
}
|
|
311
332
|
async _args() {
|
|
@@ -315,7 +336,7 @@ class Parser {
|
|
|
315
336
|
let stdinRead = false;
|
|
316
337
|
const ctx = this.context;
|
|
317
338
|
for (const [name, arg] of Object.entries(this.input.args)) {
|
|
318
|
-
const token = tokens.find(t => t.arg === name);
|
|
339
|
+
const token = tokens.find((t) => t.arg === name);
|
|
319
340
|
ctx.token = token;
|
|
320
341
|
if (token) {
|
|
321
342
|
if (arg.options && !arg.options.includes(token.input)) {
|
|
@@ -374,11 +395,11 @@ class Parser {
|
|
|
374
395
|
if (Object.keys(this.input.flags).length === 0)
|
|
375
396
|
return;
|
|
376
397
|
debug('available flags: %s', Object.keys(this.input.flags)
|
|
377
|
-
.map(f => `--${f}`)
|
|
398
|
+
.map((f) => `--${f}`)
|
|
378
399
|
.join(' '));
|
|
379
400
|
}
|
|
380
401
|
get _argTokens() {
|
|
381
|
-
return this.raw.filter(o => o.type === 'arg');
|
|
402
|
+
return this.raw.filter((o) => o.type === 'arg');
|
|
382
403
|
}
|
|
383
404
|
_setNames() {
|
|
384
405
|
for (const k of Object.keys(this.input.flags)) {
|
|
@@ -390,7 +411,7 @@ class Parser {
|
|
|
390
411
|
}
|
|
391
412
|
mapAndValidateFlags() {
|
|
392
413
|
const flagTokenMap = new Map();
|
|
393
|
-
for (const token of this.raw.filter(o => o.type === 'flag')) {
|
|
414
|
+
for (const token of this.raw.filter((o) => o.type === 'flag')) {
|
|
394
415
|
// fail fast if there are any invalid flags
|
|
395
416
|
if (!(token.flag in this.input.flags)) {
|
|
396
417
|
throw new errors_1.CLIError(`Unexpected flag ${token.flag}`);
|
|
@@ -418,12 +439,12 @@ class Parser {
|
|
|
418
439
|
if (this.flagAliases[char]) {
|
|
419
440
|
return this.flagAliases[char].name;
|
|
420
441
|
}
|
|
421
|
-
return Object.keys(this.input.flags).find(k =>
|
|
442
|
+
return Object.keys(this.input.flags).find((k) => this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined);
|
|
422
443
|
}
|
|
423
444
|
findFlag(arg) {
|
|
424
445
|
const isLong = arg.startsWith('--');
|
|
425
446
|
const short = isLong ? false : arg.startsWith('-');
|
|
426
|
-
const name = isLong ? this.findLongFlag(arg) :
|
|
447
|
+
const name = isLong ? this.findLongFlag(arg) : short ? this.findShortFlag(arg) : undefined;
|
|
427
448
|
return { name, isLong };
|
|
428
449
|
}
|
|
429
450
|
}
|
package/lib/parser/validate.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validate = void 0;
|
|
4
4
|
const errors_1 = require("./errors");
|
|
5
|
-
const
|
|
5
|
+
const index_1 = require("../util/index");
|
|
6
6
|
async function validate(parse) {
|
|
7
7
|
let cachedResolvedFlags;
|
|
8
8
|
function validateArgs() {
|
|
@@ -40,10 +40,10 @@ async function validate(parse) {
|
|
|
40
40
|
const promises = Object.entries(parse.input.flags).flatMap(([name, flag]) => {
|
|
41
41
|
if (parse.output.flags[name] !== undefined) {
|
|
42
42
|
return [
|
|
43
|
-
...flag.relationships ? validateRelationships(name, flag) : [],
|
|
44
|
-
...flag.dependsOn ? [validateDependsOn(name, flag.dependsOn)] : [],
|
|
45
|
-
...flag.exclusive ? [validateExclusive(name, flag.exclusive)] : [],
|
|
46
|
-
...flag.exactlyOne ? [validateExactlyOne(name, flag.exactlyOne)] : [],
|
|
43
|
+
...(flag.relationships ? validateRelationships(name, flag) : []),
|
|
44
|
+
...(flag.dependsOn ? [validateDependsOn(name, flag.dependsOn)] : []),
|
|
45
|
+
...(flag.exclusive ? [validateExclusive(name, flag.exclusive)] : []),
|
|
46
|
+
...(flag.exactlyOne ? [validateExactlyOne(name, flag.exactlyOne)] : []),
|
|
47
47
|
];
|
|
48
48
|
}
|
|
49
49
|
if (flag.required) {
|
|
@@ -54,8 +54,8 @@ async function validate(parse) {
|
|
|
54
54
|
}
|
|
55
55
|
return [];
|
|
56
56
|
});
|
|
57
|
-
const results =
|
|
58
|
-
const failed = results.filter(r => r.status === 'failed');
|
|
57
|
+
const results = await Promise.all(promises);
|
|
58
|
+
const failed = results.filter((r) => r.status === 'failed');
|
|
59
59
|
if (failed.length > 0)
|
|
60
60
|
throw new errors_1.FailedFlagValidationError({ parse, failed });
|
|
61
61
|
}
|
|
@@ -70,19 +70,19 @@ async function validate(parse) {
|
|
|
70
70
|
return result ? [flag.name, parse.output.flags[flag.name]] : null;
|
|
71
71
|
});
|
|
72
72
|
const resolved = await Promise.all(promises);
|
|
73
|
-
cachedResolvedFlags = Object.fromEntries(resolved.filter(r => r !== null));
|
|
73
|
+
cachedResolvedFlags = Object.fromEntries(resolved.filter((r) => r !== null));
|
|
74
74
|
return cachedResolvedFlags;
|
|
75
75
|
}
|
|
76
|
-
const getPresentFlags = (flags) => Object.keys(flags).filter(key => key !== undefined);
|
|
76
|
+
const getPresentFlags = (flags) => Object.keys(flags).filter((key) => key !== undefined);
|
|
77
77
|
function validateAcrossFlags(flag) {
|
|
78
78
|
const base = { name: flag.name, validationFn: 'validateAcrossFlags' };
|
|
79
79
|
const intersection = Object.entries(parse.input.flags)
|
|
80
|
-
.map(entry => entry[0]) // array of flag names
|
|
81
|
-
.filter(flagName => parse.output.flags[flagName] !== undefined) // with values
|
|
82
|
-
.filter(flagName => flag.exactlyOne && flag.exactlyOne.includes(flagName)); // and in the exactlyOne list
|
|
80
|
+
.map((entry) => entry[0]) // array of flag names
|
|
81
|
+
.filter((flagName) => parse.output.flags[flagName] !== undefined) // with values
|
|
82
|
+
.filter((flagName) => flag.exactlyOne && flag.exactlyOne.includes(flagName)); // and in the exactlyOne list
|
|
83
83
|
if (intersection.length === 0) {
|
|
84
84
|
// the command's exactlyOne may or may not include itself, so we'll use Set to add + de-dupe
|
|
85
|
-
const deduped = (0,
|
|
85
|
+
const deduped = (0, index_1.uniq)(flag.exactlyOne?.map((flag) => `--${flag}`) ?? []).join(', ');
|
|
86
86
|
const reason = `Exactly one of the following must be provided: ${deduped}`;
|
|
87
87
|
return { ...base, status: 'failed', reason };
|
|
88
88
|
}
|
|
@@ -100,7 +100,11 @@ async function validate(parse) {
|
|
|
100
100
|
continue;
|
|
101
101
|
if (parse.output.flags[flag] !== undefined) {
|
|
102
102
|
const flagValue = parse.output.metadata.flags?.[flag]?.defaultHelp ?? parse.output.flags[flag];
|
|
103
|
-
return {
|
|
103
|
+
return {
|
|
104
|
+
...base,
|
|
105
|
+
status: 'failed',
|
|
106
|
+
reason: `--${flag}=${flagValue} cannot also be provided when using --${name}`,
|
|
107
|
+
};
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
110
|
return { ...base, status: 'success' };
|
|
@@ -119,10 +123,16 @@ async function validate(parse) {
|
|
|
119
123
|
async function validateDependsOn(name, flags) {
|
|
120
124
|
const base = { name, validationFn: 'validateDependsOn' };
|
|
121
125
|
const resolved = await resolveFlags(flags);
|
|
122
|
-
const foundAll = Object.values(resolved).every(val => val !== undefined);
|
|
126
|
+
const foundAll = Object.values(resolved).every((val) => val !== undefined);
|
|
123
127
|
if (!foundAll) {
|
|
124
|
-
const formattedFlags = Object.keys(resolved)
|
|
125
|
-
|
|
128
|
+
const formattedFlags = Object.keys(resolved)
|
|
129
|
+
.map((f) => `--${f}`)
|
|
130
|
+
.join(', ');
|
|
131
|
+
return {
|
|
132
|
+
...base,
|
|
133
|
+
status: 'failed',
|
|
134
|
+
reason: `All of the following must be provided when using --${name}: ${formattedFlags}`,
|
|
135
|
+
};
|
|
126
136
|
}
|
|
127
137
|
return { ...base, status: 'success' };
|
|
128
138
|
}
|
|
@@ -131,13 +141,19 @@ async function validate(parse) {
|
|
|
131
141
|
const resolved = await resolveFlags(flags);
|
|
132
142
|
const foundAtLeastOne = Object.values(resolved).some(Boolean);
|
|
133
143
|
if (!foundAtLeastOne) {
|
|
134
|
-
const formattedFlags = Object.keys(resolved)
|
|
135
|
-
|
|
144
|
+
const formattedFlags = Object.keys(resolved)
|
|
145
|
+
.map((f) => `--${f}`)
|
|
146
|
+
.join(', ');
|
|
147
|
+
return {
|
|
148
|
+
...base,
|
|
149
|
+
status: 'failed',
|
|
150
|
+
reason: `One of the following must be provided when using --${name}: ${formattedFlags}`,
|
|
151
|
+
};
|
|
136
152
|
}
|
|
137
153
|
return { ...base, status: 'success' };
|
|
138
154
|
}
|
|
139
155
|
function validateRelationships(name, flag) {
|
|
140
|
-
return (
|
|
156
|
+
return (flag.relationships ?? []).map((relationship) => {
|
|
141
157
|
switch (relationship.type) {
|
|
142
158
|
case 'all': {
|
|
143
159
|
return validateDependsOn(name, relationship.flags);
|
|
@@ -152,7 +168,7 @@ async function validate(parse) {
|
|
|
152
168
|
throw new Error(`Unknown relationship type: ${relationship.type}`);
|
|
153
169
|
}
|
|
154
170
|
}
|
|
155
|
-
})
|
|
171
|
+
});
|
|
156
172
|
}
|
|
157
173
|
validateArgs();
|
|
158
174
|
return validateFlags();
|
package/lib/performance.js
CHANGED
|
@@ -50,7 +50,7 @@ class Performance {
|
|
|
50
50
|
throw new Error('Perf results not available. Did you forget to call await Performance.collect()?');
|
|
51
51
|
}
|
|
52
52
|
static getResult(name) {
|
|
53
|
-
return Performance.results.find(r => r.name === name);
|
|
53
|
+
return Performance.results.find((r) => r.name === name);
|
|
54
54
|
}
|
|
55
55
|
static get highlights() {
|
|
56
56
|
if (!Performance.enabled)
|
|
@@ -86,11 +86,11 @@ class Performance {
|
|
|
86
86
|
const markers = Object.values(Performance.markers);
|
|
87
87
|
if (markers.length === 0)
|
|
88
88
|
return;
|
|
89
|
-
for (const marker of markers.filter(m => !m.stopped)) {
|
|
89
|
+
for (const marker of markers.filter((m) => !m.stopped)) {
|
|
90
90
|
marker.stop();
|
|
91
91
|
}
|
|
92
|
-
return new Promise(resolve => {
|
|
93
|
-
const perfObserver = new node_perf_hooks_1.PerformanceObserver(items => {
|
|
92
|
+
return new Promise((resolve) => {
|
|
93
|
+
const perfObserver = new node_perf_hooks_1.PerformanceObserver((items) => {
|
|
94
94
|
for (const entry of items.getEntries()) {
|
|
95
95
|
if (Performance.markers[entry.name]) {
|
|
96
96
|
const marker = Performance.markers[entry.name];
|
|
@@ -104,8 +104,11 @@ class Performance {
|
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
const command = Performance.results.find(r => r.name.startsWith('config.runCommand'));
|
|
108
|
-
const commandLoadTime = command
|
|
107
|
+
const command = Performance.results.find((r) => r.name.startsWith('config.runCommand'));
|
|
108
|
+
const commandLoadTime = command
|
|
109
|
+
? Performance.getResult(`plugin.findCommand#${command.details.plugin}.${command.details.command}`)
|
|
110
|
+
?.duration ?? 0
|
|
111
|
+
: 0;
|
|
109
112
|
const pluginLoadTimes = Object.fromEntries(Performance.results
|
|
110
113
|
.filter(({ name }) => name.startsWith('plugin.load#'))
|
|
111
114
|
.sort((a, b) => b.duration - a.duration)
|
|
@@ -8,8 +8,6 @@ const json = (0, flags_1.boolean)({
|
|
|
8
8
|
});
|
|
9
9
|
function aggregateFlags(flags, baseFlags, enableJsonFlag) {
|
|
10
10
|
const combinedFlags = { ...baseFlags, ...flags };
|
|
11
|
-
return (enableJsonFlag
|
|
12
|
-
? { json, ...combinedFlags }
|
|
13
|
-
: combinedFlags);
|
|
11
|
+
return (enableJsonFlag ? { json, ...combinedFlags } : combinedFlags);
|
|
14
12
|
}
|
|
15
13
|
exports.aggregateFlags = aggregateFlags;
|