@oclif/core 3.0.0-beta.2 → 3.0.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +10 -6
  2. package/flush.js +1 -1
  3. package/handle.js +1 -1
  4. package/lib/args.d.ts +1 -1
  5. package/lib/args.js +17 -18
  6. package/lib/cli-ux/action/base.d.ts +3 -5
  7. package/lib/cli-ux/action/base.js +32 -26
  8. package/lib/cli-ux/action/simple.js +13 -18
  9. package/lib/cli-ux/action/spinner.d.ts +4 -2
  10. package/lib/cli-ux/action/spinner.js +27 -19
  11. package/lib/cli-ux/action/spinners.js +1 -1
  12. package/lib/cli-ux/action/types.d.ts +5 -0
  13. package/lib/cli-ux/action/types.js +2 -0
  14. package/lib/cli-ux/config.d.ts +0 -1
  15. package/lib/cli-ux/config.js +17 -21
  16. package/lib/cli-ux/exit.d.ts +1 -1
  17. package/lib/cli-ux/exit.js +4 -1
  18. package/lib/cli-ux/flush.d.ts +1 -0
  19. package/lib/cli-ux/flush.js +28 -0
  20. package/lib/cli-ux/index.d.ts +10 -30
  21. package/lib/cli-ux/index.js +32 -75
  22. package/lib/cli-ux/list.js +3 -3
  23. package/lib/cli-ux/prompt.js +32 -22
  24. package/lib/cli-ux/stream.js +1 -0
  25. package/lib/cli-ux/styled/index.d.ts +5 -6
  26. package/lib/cli-ux/styled/index.js +11 -11
  27. package/lib/cli-ux/styled/json.js +8 -5
  28. package/lib/cli-ux/styled/object.js +7 -9
  29. package/lib/cli-ux/styled/table.d.ts +4 -4
  30. package/lib/cli-ux/styled/table.js +61 -64
  31. package/lib/cli-ux/styled/tree.js +1 -3
  32. package/lib/cli-ux/wait.js +3 -5
  33. package/lib/command.d.ts +15 -19
  34. package/lib/command.js +117 -96
  35. package/lib/config/config.d.ts +16 -23
  36. package/lib/config/config.js +180 -334
  37. package/lib/config/index.d.ts +1 -1
  38. package/lib/config/index.js +1 -2
  39. package/lib/config/plugin-loader.d.ts +30 -0
  40. package/lib/config/plugin-loader.js +145 -0
  41. package/lib/config/plugin.d.ts +6 -11
  42. package/lib/config/plugin.js +112 -78
  43. package/lib/config/ts-node.d.ts +2 -1
  44. package/lib/config/ts-node.js +64 -51
  45. package/lib/config/util.d.ts +1 -11
  46. package/lib/config/util.js +6 -59
  47. package/lib/errors/config.js +1 -1
  48. package/lib/errors/errors/cli.d.ts +1 -1
  49. package/lib/errors/errors/cli.js +18 -14
  50. package/lib/errors/errors/exit.d.ts +0 -3
  51. package/lib/errors/errors/exit.js +1 -1
  52. package/lib/errors/errors/module-load.d.ts +0 -3
  53. package/lib/errors/errors/module-load.js +1 -1
  54. package/lib/errors/errors/pretty-print.js +11 -9
  55. package/lib/errors/handle.d.ts +12 -2
  56. package/lib/errors/handle.js +28 -18
  57. package/lib/errors/index.d.ts +2 -2
  58. package/lib/errors/index.js +20 -19
  59. package/lib/errors/logger.js +9 -8
  60. package/lib/execute.d.ts +49 -0
  61. package/lib/execute.js +63 -0
  62. package/lib/flags.d.ts +102 -31
  63. package/lib/flags.js +81 -46
  64. package/lib/help/command.d.ts +2 -0
  65. package/lib/help/command.js +68 -53
  66. package/lib/help/docopts.js +9 -13
  67. package/lib/help/formatter.d.ts +1 -1
  68. package/lib/help/formatter.js +35 -24
  69. package/lib/help/index.d.ts +7 -3
  70. package/lib/help/index.js +77 -55
  71. package/lib/help/root.js +7 -9
  72. package/lib/help/util.d.ts +1 -7
  73. package/lib/help/util.js +8 -28
  74. package/lib/index.d.ts +19 -18
  75. package/lib/index.js +36 -48
  76. package/lib/interfaces/config.d.ts +30 -30
  77. package/lib/interfaces/errors.d.ts +1 -1
  78. package/lib/interfaces/hooks.d.ts +3 -3
  79. package/lib/interfaces/index.d.ts +14 -14
  80. package/lib/interfaces/parser.d.ts +188 -116
  81. package/lib/interfaces/pjson.d.ts +2 -1
  82. package/lib/interfaces/plugin.d.ts +10 -1
  83. package/lib/main.d.ts +0 -48
  84. package/lib/main.js +11 -66
  85. package/lib/module-loader.d.ts +68 -79
  86. package/lib/module-loader.js +183 -150
  87. package/lib/parser/errors.d.ts +3 -3
  88. package/lib/parser/errors.js +17 -10
  89. package/lib/parser/help.js +5 -5
  90. package/lib/parser/parse.d.ts +3 -0
  91. package/lib/parser/parse.js +114 -115
  92. package/lib/parser/validate.js +45 -25
  93. package/lib/performance.d.ts +5 -1
  94. package/lib/performance.js +40 -19
  95. package/lib/util/aggregate-flags.d.ts +2 -0
  96. package/lib/util/aggregate-flags.js +13 -0
  97. package/lib/util/cache-command.d.ts +3 -0
  98. package/lib/util/cache-command.js +109 -0
  99. package/lib/util/cache-default-value.d.ts +2 -0
  100. package/lib/util/cache-default-value.js +28 -0
  101. package/lib/util/ensure-arg-object.d.ts +12 -0
  102. package/lib/util/ensure-arg-object.js +14 -0
  103. package/lib/util/fs.d.ts +7 -0
  104. package/lib/util/fs.js +54 -0
  105. package/lib/util/os.d.ts +19 -0
  106. package/lib/util/os.js +28 -0
  107. package/lib/{util.d.ts → util/util.d.ts} +6 -15
  108. package/lib/util/util.js +98 -0
  109. package/package.json +32 -34
  110. package/lib/cli-ux/action/pride-spinner.d.ts +0 -4
  111. package/lib/cli-ux/action/pride-spinner.js +0 -30
  112. package/lib/util.js +0 -126
@@ -16,4 +16,7 @@ export declare class Parser<T extends ParserInput, TFlags extends OutputFlags<T[
16
16
  private get _argTokens();
17
17
  private _setNames;
18
18
  private mapAndValidateFlags;
19
+ private findLongFlag;
20
+ private findShortFlag;
21
+ private findFlag;
19
22
  }
@@ -3,43 +3,23 @@ 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 readline = require("readline");
7
- const util_1 = require("../util");
6
+ const util_1 = require("../util/util");
7
+ const node_readline_1 = require("node:readline");
8
8
  let debug;
9
9
  try {
10
- // eslint-disable-next-line no-negated-condition
11
- debug = process.env.CLI_FLAGS_DEBUG !== '1' ? () => { } : require('debug')('../parser');
10
+ debug =
11
+ process.env.CLI_FLAGS_DEBUG === '1'
12
+ ? require('debug')('../parser')
13
+ : () => {
14
+ // noop
15
+ };
12
16
  }
13
17
  catch {
14
- debug = () => { };
18
+ debug = () => {
19
+ // noop
20
+ };
15
21
  }
16
- /**
17
- * Support reading from stdin in Node 14 and older.
18
- *
19
- * This generally works for Node 14 and older EXCEPT when it's being
20
- * run from another process, in which case it will hang indefinitely. Because
21
- * of that issue we updated this to use AbortController but since AbortController
22
- * is only available in Node 16 and newer, we have to keep this legacy version.
23
- *
24
- * See these issues for more details on the hanging indefinitely bug:
25
- * https://github.com/oclif/core/issues/330
26
- * https://github.com/oclif/core/pull/363
27
- *
28
- * @returns Promise<string | null>
29
- */
30
- const readStdinLegacy = async () => {
31
- const { stdin } = process;
32
- let result;
33
- if (stdin.isTTY)
34
- return null;
35
- result = '';
36
- stdin.setEncoding('utf8');
37
- for await (const chunk of stdin) {
38
- result += chunk;
39
- }
40
- return result;
41
- };
42
- const readStdinWithTimeout = async () => {
22
+ const readStdin = async () => {
43
23
  const { stdin, stdout } = process;
44
24
  // process.stdin.isTTY is true whenever it's running in a terminal.
45
25
  // process.stdin.isTTY is undefined when it's running in a pipe, e.g. echo 'foo' | my-cli command
@@ -48,17 +28,17 @@ const readStdinWithTimeout = async () => {
48
28
  // Because of this, we have to set a timeout to prevent the process from hanging.
49
29
  if (stdin.isTTY)
50
30
  return null;
51
- return new Promise(resolve => {
31
+ return new Promise((resolve) => {
52
32
  let result = '';
53
33
  const ac = new AbortController();
54
- const signal = ac.signal;
34
+ const { signal } = ac;
55
35
  const timeout = setTimeout(() => ac.abort(), 100);
56
- const rl = readline.createInterface({
36
+ const rl = (0, node_readline_1.createInterface)({
57
37
  input: stdin,
58
38
  output: stdout,
59
39
  terminal: false,
60
40
  });
61
- rl.on('line', line => {
41
+ rl.on('line', (line) => {
62
42
  result += line;
63
43
  });
64
44
  rl.once('close', () => {
@@ -74,58 +54,34 @@ const readStdinWithTimeout = async () => {
74
54
  }, { once: true });
75
55
  });
76
56
  };
77
- const readStdin = async () => {
78
- const { stdin, version } = process;
79
- debug('stdin.isTTY', stdin.isTTY);
80
- const nodeMajorVersion = Number(version.split('.')[0].replace(/^v/, ''));
81
- debug('node version', nodeMajorVersion);
82
- return nodeMajorVersion > 14 ? readStdinWithTimeout() : readStdinLegacy();
83
- };
84
57
  function isNegativeNumber(input) {
85
58
  return /^-\d/g.test(input);
86
59
  }
60
+ const validateOptions = (flag, input) => {
61
+ if (flag.options && !flag.options.includes(input))
62
+ throw new errors_1.FlagInvalidOptionError(flag, input);
63
+ return input;
64
+ };
87
65
  class Parser {
66
+ input;
67
+ argv;
68
+ raw = [];
69
+ booleanFlags;
70
+ flagAliases;
71
+ context;
72
+ currentFlag;
88
73
  constructor(input) {
89
74
  this.input = input;
90
- this.raw = [];
91
75
  this.context = input.context ?? {};
92
76
  this.argv = [...input.argv];
93
77
  this._setNames();
94
- this.booleanFlags = (0, util_1.pickBy)(input.flags, f => f.type === 'boolean');
95
- this.flagAliases = Object.fromEntries(Object.values(input.flags).flatMap(flag => {
96
- return (flag.aliases ?? []).map(a => [a, flag]);
97
- }));
78
+ this.booleanFlags = (0, util_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])));
98
80
  }
99
81
  async parse() {
100
82
  this._debugInput();
101
- const findLongFlag = (arg) => {
102
- const name = arg.slice(2);
103
- if (this.input.flags[name]) {
104
- return name;
105
- }
106
- if (this.flagAliases[name]) {
107
- return this.flagAliases[name].name;
108
- }
109
- if (arg.startsWith('--no-')) {
110
- const flag = this.booleanFlags[arg.slice(5)];
111
- if (flag && flag.allowNo)
112
- return flag.name;
113
- }
114
- };
115
- const findShortFlag = ([_, char]) => {
116
- if (this.flagAliases[char]) {
117
- return this.flagAliases[char].name;
118
- }
119
- return Object.keys(this.input.flags).find(k => (this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined));
120
- };
121
- const findFlag = (arg) => {
122
- const isLong = arg.startsWith('--');
123
- const short = isLong ? false : arg.startsWith('-');
124
- const name = isLong ? findLongFlag(arg) : (short ? findShortFlag(arg) : undefined);
125
- return { name, isLong };
126
- };
127
83
  const parseFlag = (arg) => {
128
- const { name, isLong } = findFlag(arg);
84
+ const { name, isLong } = this.findFlag(arg);
129
85
  if (!name) {
130
86
  const i = arg.indexOf('=');
131
87
  if (i !== -1) {
@@ -141,13 +97,16 @@ class Parser {
141
97
  }
142
98
  const flag = this.input.flags[name];
143
99
  if (flag.type === 'option') {
100
+ if (!flag.multiple && this.raw.some((o) => o.type === 'flag' && o.flag === name)) {
101
+ throw new errors_1.CLIError(`Flag --${name} can only be specified once`);
102
+ }
144
103
  this.currentFlag = flag;
145
104
  const input = isLong || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
146
105
  // if the value ends up being one of the command's flags, the user didn't provide an input
147
- if ((typeof input !== 'string') || findFlag(input).name) {
106
+ if (typeof input !== 'string' || this.findFlag(input).name) {
148
107
  throw new errors_1.CLIError(`Flag --${name} expects a value`);
149
108
  }
150
- this.raw.push({ type: 'flag', flag: flag.name, input: input });
109
+ this.raw.push({ type: 'flag', flag: flag.name, input });
151
110
  }
152
111
  else {
153
112
  this.raw.push({ type: 'flag', flag: flag.name, input: arg });
@@ -207,11 +166,6 @@ class Parser {
207
166
  };
208
167
  }
209
168
  async _flags() {
210
- const validateOptions = (flag, input) => {
211
- if (flag.options && !flag.options.includes(input))
212
- throw new errors_1.FlagInvalidOptionError(flag, input);
213
- return input;
214
- };
215
169
  const parseFlagOrThrowError = async (input, flag, context, token) => {
216
170
  if (!flag.parse)
217
171
  return input;
@@ -236,8 +190,8 @@ class Parser {
236
190
  }
237
191
  };
238
192
  /* Could add a valueFunction (if there is a value/env/default) and could metadata.
239
- * Value function can be resolved later.
240
- */
193
+ * Value function can be resolved later.
194
+ */
241
195
  const addValueFunction = (fws) => {
242
196
  const tokenLength = fws.tokens?.length;
243
197
  // user provided some input
@@ -252,17 +206,27 @@ class Parser {
252
206
  // multiple with custom delimiter
253
207
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.delimiter && fws.inputFlag.flag.multiple) {
254
208
  return {
255
- ...fws, valueFunction: async (i) => (await Promise.all(((i.tokens ?? []).flatMap(token => token.input.split(i.inputFlag.flag.delimiter)))
209
+ ...fws,
210
+ valueFunction: async (i) => (await Promise.all((i.tokens ?? [])
211
+ .flatMap((token) => token.input.split(i.inputFlag.flag.delimiter ?? ','))
256
212
  // trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
257
- .map(v => v.trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'))
258
- .map(async (v) => parseFlagOrThrowError(v, i.inputFlag.flag, this.context, { ...(0, util_1.last)(i.tokens), input: v })))).map(v => validateOptions(i.inputFlag.flag, v)),
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, util_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)),
259
223
  };
260
224
  }
261
225
  // multiple in the oclif-core style
262
226
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.multiple) {
263
227
  return {
264
228
  ...fws,
265
- 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))),
266
230
  };
267
231
  }
268
232
  // simple option flag
@@ -285,17 +249,19 @@ class Parser {
285
249
  if (fws.inputFlag.flag.type === 'boolean') {
286
250
  return {
287
251
  ...fws,
288
- valueFunction: async (i) => Promise.resolve((0, util_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false')),
252
+ valueFunction: async (i) => (0, util_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false'),
289
253
  };
290
254
  }
291
255
  }
292
256
  // no input, but flag has default value
257
+ // eslint-disable-next-line no-constant-binary-expression, valid-typeof
293
258
  if (typeof fws.inputFlag.flag.default !== undefined) {
294
259
  return {
295
- ...fws, metadata: { setFromDefault: true },
296
- valueFunction: typeof fws.inputFlag.flag.default === 'function' ?
297
- (i, allFlags = {}) => fws.inputFlag.flag.default({ options: i.inputFlag.flag, flags: allFlags }) :
298
- async () => fws.inputFlag.flag.default,
260
+ ...fws,
261
+ metadata: { setFromDefault: true },
262
+ valueFunction: typeof fws.inputFlag.flag.default === 'function'
263
+ ? (i, allFlags = {}) => fws.inputFlag.flag.default({ options: i.inputFlag.flag, flags: allFlags })
264
+ : async () => fws.inputFlag.flag.default,
299
265
  };
300
266
  }
301
267
  // base case (no value function)
@@ -304,17 +270,19 @@ class Parser {
304
270
  const addHelpFunction = (fws) => {
305
271
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.defaultHelp) {
306
272
  return {
307
- ...fws, helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function' ?
308
- // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
309
- (i, flags, ...context) => i.inputFlag.flag.defaultHelp({ options: i.inputFlag, flags }, ...context) :
273
+ ...fws,
274
+ helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function'
275
+ ? (i, flags, ...context) =>
310
276
  // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
311
- (i) => i.inputFlag.flag.defaultHelp,
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,
312
280
  };
313
281
  }
314
282
  return fws;
315
283
  };
316
284
  const addDefaultHelp = async (fwsArray) => {
317
- const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter(fws => !fws.metadata?.setFromDefault));
285
+ const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter((fws) => !fws.metadata?.setFromDefault));
318
286
  return Promise.all(fwsArray.map(async (fws) => {
319
287
  try {
320
288
  if (fws.helpFunction) {
@@ -333,27 +301,32 @@ class Parser {
333
301
  return fws;
334
302
  }));
335
303
  };
336
- const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.filter(fws => fws.value !== undefined)
337
- .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]));
338
305
  const flagTokenMap = this.mapAndValidateFlags();
339
306
  const flagsWithValues = await Promise.all(Object.entries(this.input.flags)
340
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
341
- .filter(([name, flag]) => flag.type === 'boolean' || flag.env || flag.default !== undefined || 'defaultHelp' in flag || flagTokenMap.has(name))
308
+ .filter(([name, flag]) => flag.type === 'boolean' ||
309
+ flag.env ||
310
+ flag.default !== undefined ||
311
+ 'defaultHelp' in flag ||
312
+ flagTokenMap.has(name))
342
313
  // match each possible flag to its token, if there is one
343
314
  .map(([name, flag]) => ({ inputFlag: { name, flag }, tokens: flagTokenMap.get(name) }))
344
- .map(fws => addValueFunction(fws))
345
- .filter(fws => fws.valueFunction !== undefined)
346
- .map(fws => addHelpFunction(fws))
315
+ .map((fws) => addValueFunction(fws))
316
+ .filter((fws) => fws.valueFunction !== undefined)
317
+ .map((fws) => addHelpFunction(fws))
347
318
  // we can't apply the default values until all the other flags are resolved because `flag.default` can reference other flags
348
319
  .map(async (fws) => (fws.metadata?.setFromDefault ? fws : { ...fws, value: await fws.valueFunction?.(fws) })));
349
- const valueReference = fwsArrayToObject(flagsWithValues.filter(fws => !fws.metadata?.setFromDefault));
350
- const flagsWithAllValues = await Promise.all(flagsWithValues
351
- .map(async (fws) => (fws.metadata?.setFromDefault ? { ...fws, value: await fws.valueFunction?.(fws, valueReference) } : fws)));
352
- const finalFlags = (flagsWithAllValues.some(fws => typeof fws.helpFunction === 'function')) ? await addDefaultHelp(flagsWithAllValues) : flagsWithAllValues;
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;
353
325
  return {
354
- // @ts-ignore original version returned an any. Not sure how to get to the return type for `flags` prop
355
326
  flags: fwsArrayToObject(finalFlags),
356
- metadata: { flags: Object.fromEntries(finalFlags.filter(fws => fws.metadata).map(fws => [fws.inputFlag.name, fws.metadata])) },
327
+ metadata: {
328
+ flags: Object.fromEntries(finalFlags.filter((fws) => fws.metadata).map((fws) => [fws.inputFlag.name, fws.metadata])),
329
+ },
357
330
  };
358
331
  }
359
332
  async _args() {
@@ -363,7 +336,7 @@ class Parser {
363
336
  let stdinRead = false;
364
337
  const ctx = this.context;
365
338
  for (const [name, arg] of Object.entries(this.input.args)) {
366
- const token = tokens.find(t => t.arg === name);
339
+ const token = tokens.find((t) => t.arg === name);
367
340
  ctx.token = token;
368
341
  if (token) {
369
342
  if (arg.options && !arg.options.includes(token.input)) {
@@ -400,7 +373,7 @@ class Parser {
400
373
  continue;
401
374
  argv.push(token.input);
402
375
  }
403
- return { argv, args: args };
376
+ return { argv, args };
404
377
  }
405
378
  _debugOutput(args, flags, argv) {
406
379
  if (argv.length > 0) {
@@ -422,11 +395,11 @@ class Parser {
422
395
  if (Object.keys(this.input.flags).length === 0)
423
396
  return;
424
397
  debug('available flags: %s', Object.keys(this.input.flags)
425
- .map(f => `--${f}`)
398
+ .map((f) => `--${f}`)
426
399
  .join(' '));
427
400
  }
428
401
  get _argTokens() {
429
- return this.raw.filter(o => o.type === 'arg');
402
+ return this.raw.filter((o) => o.type === 'arg');
430
403
  }
431
404
  _setNames() {
432
405
  for (const k of Object.keys(this.input.flags)) {
@@ -438,7 +411,7 @@ class Parser {
438
411
  }
439
412
  mapAndValidateFlags() {
440
413
  const flagTokenMap = new Map();
441
- for (const token of this.raw.filter(o => o.type === 'flag')) {
414
+ for (const token of this.raw.filter((o) => o.type === 'flag')) {
442
415
  // fail fast if there are any invalid flags
443
416
  if (!(token.flag in this.input.flags)) {
444
417
  throw new errors_1.CLIError(`Unexpected flag ${token.flag}`);
@@ -448,5 +421,31 @@ class Parser {
448
421
  }
449
422
  return flagTokenMap;
450
423
  }
424
+ findLongFlag(arg) {
425
+ const name = arg.slice(2);
426
+ if (this.input.flags[name]) {
427
+ return name;
428
+ }
429
+ if (this.flagAliases[name]) {
430
+ return this.flagAliases[name].name;
431
+ }
432
+ if (arg.startsWith('--no-')) {
433
+ const flag = this.booleanFlags[arg.slice(5)];
434
+ if (flag && flag.allowNo)
435
+ return flag.name;
436
+ }
437
+ }
438
+ findShortFlag([_, char]) {
439
+ if (this.flagAliases[char]) {
440
+ return this.flagAliases[char].name;
441
+ }
442
+ return Object.keys(this.input.flags).find((k) => this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined);
443
+ }
444
+ findFlag(arg) {
445
+ const isLong = arg.startsWith('--');
446
+ const short = isLong ? false : arg.startsWith('-');
447
+ const name = isLong ? this.findLongFlag(arg) : short ? this.findShortFlag(arg) : undefined;
448
+ return { name, isLong };
449
+ }
451
450
  }
452
451
  exports.Parser = Parser;
@@ -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 util_1 = require("../config/util");
5
+ const util_1 = require("../util/util");
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 = (await Promise.all(promises));
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, util_1.uniq)(flag.exactlyOne?.map(flag => `--${flag}`) ?? []).join(', ');
85
+ const deduped = (0, util_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 { ...base, status: 'failed', reason: `--${flag}=${flagValue} cannot also be provided when using --${name}` };
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).map(f => `--${f}`).join(', ');
125
- return { ...base, status: 'failed', reason: `All of the following must be provided when using --${name}: ${formattedFlags}` };
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,24 +141,34 @@ 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).map(f => `--${f}`).join(', ');
135
- return { ...base, status: 'failed', reason: `One of the following must be provided when using --${name}: ${formattedFlags}` };
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 ((flag.relationships ?? []).map(relationship => {
156
+ return (flag.relationships ?? []).map((relationship) => {
141
157
  switch (relationship.type) {
142
- case 'all':
158
+ case 'all': {
143
159
  return validateDependsOn(name, relationship.flags);
144
- case 'some':
160
+ }
161
+ case 'some': {
145
162
  return validateSome(name, relationship.flags);
146
- case 'none':
163
+ }
164
+ case 'none': {
147
165
  return validateExclusive(name, relationship.flags);
148
- default:
166
+ }
167
+ default: {
149
168
  throw new Error(`Unknown relationship type: ${relationship.type}`);
169
+ }
150
170
  }
151
- }));
171
+ });
152
172
  }
153
173
  validateArgs();
154
174
  return validateFlags();
@@ -12,7 +12,11 @@ type PerfHighlights = {
12
12
  runTime: number;
13
13
  initTime: number;
14
14
  commandLoadTime: number;
15
- pluginLoadTimes: Record<string, number>;
15
+ commandRunTime: number;
16
+ pluginLoadTimes: Record<string, {
17
+ duration: number;
18
+ details: Details;
19
+ }>;
16
20
  corePluginsLoadTime: number;
17
21
  userPluginsLoadTime: number;
18
22
  linkedPluginsLoadTime: number;