@oclif/core 3.0.0-beta.17 → 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.
Files changed (69) hide show
  1. package/lib/args.js +4 -4
  2. package/lib/cli-ux/action/base.js +8 -7
  3. package/lib/cli-ux/action/simple.js +1 -4
  4. package/lib/cli-ux/action/spinner.js +8 -7
  5. package/lib/cli-ux/action/spinners.js +1 -1
  6. package/lib/cli-ux/config.js +11 -12
  7. package/lib/cli-ux/exit.js +3 -0
  8. package/lib/cli-ux/flush.js +7 -6
  9. package/lib/cli-ux/index.js +2 -2
  10. package/lib/cli-ux/list.js +3 -3
  11. package/lib/cli-ux/prompt.js +8 -3
  12. package/lib/cli-ux/stream.js +1 -0
  13. package/lib/cli-ux/styled/json.js +5 -3
  14. package/lib/cli-ux/styled/object.js +2 -2
  15. package/lib/cli-ux/styled/table.js +26 -20
  16. package/lib/cli-ux/styled/tree.js +1 -3
  17. package/lib/cli-ux/wait.js +1 -1
  18. package/lib/command.d.ts +6 -14
  19. package/lib/command.js +86 -73
  20. package/lib/config/config.d.ts +8 -9
  21. package/lib/config/config.js +85 -199
  22. package/lib/config/index.d.ts +0 -1
  23. package/lib/config/index.js +1 -3
  24. package/lib/config/plugin-loader.js +12 -11
  25. package/lib/config/plugin.d.ts +1 -0
  26. package/lib/config/plugin.js +54 -34
  27. package/lib/config/ts-node.js +17 -13
  28. package/lib/config/util.d.ts +0 -6
  29. package/lib/config/util.js +3 -15
  30. package/lib/errors/errors/cli.js +4 -1
  31. package/lib/errors/errors/exit.js +1 -1
  32. package/lib/errors/errors/module-load.js +1 -1
  33. package/lib/errors/errors/pretty-print.js +2 -1
  34. package/lib/errors/handle.js +4 -3
  35. package/lib/errors/logger.js +5 -4
  36. package/lib/flags.d.ts +6 -6
  37. package/lib/flags.js +3 -3
  38. package/lib/help/command.js +46 -32
  39. package/lib/help/docopts.js +8 -5
  40. package/lib/help/formatter.js +19 -8
  41. package/lib/help/index.d.ts +5 -1
  42. package/lib/help/index.js +70 -49
  43. package/lib/help/root.js +7 -9
  44. package/lib/help/util.d.ts +1 -7
  45. package/lib/help/util.js +2 -22
  46. package/lib/index.d.ts +2 -2
  47. package/lib/index.js +2 -3
  48. package/lib/interfaces/hooks.d.ts +3 -3
  49. package/lib/interfaces/index.d.ts +1 -1
  50. package/lib/interfaces/parser.d.ts +19 -18
  51. package/lib/interfaces/pjson.d.ts +1 -1
  52. package/lib/interfaces/plugin.d.ts +5 -0
  53. package/lib/module-loader.d.ts +8 -8
  54. package/lib/module-loader.js +13 -10
  55. package/lib/parser/errors.d.ts +1 -1
  56. package/lib/parser/errors.js +15 -9
  57. package/lib/parser/help.js +2 -3
  58. package/lib/parser/parse.js +72 -44
  59. package/lib/parser/validate.js +37 -21
  60. package/lib/performance.js +20 -9
  61. package/lib/util/aggregate-flags.d.ts +2 -0
  62. package/lib/util/aggregate-flags.js +13 -0
  63. package/lib/util/cache-command.d.ts +3 -0
  64. package/lib/util/cache-command.js +108 -0
  65. package/lib/util/cache-default-value.d.ts +2 -0
  66. package/lib/util/cache-default-value.js +28 -0
  67. package/lib/{util.d.ts → util/index.d.ts} +7 -2
  68. package/lib/{util.js → util/index.js} +15 -20
  69. package/package.json +19 -13
@@ -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 util_1 = require("../util");
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 = process.env.CLI_FLAGS_DEBUG === '1' ? require('debug')('../parser') : () => {
11
- // noop
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', () => {
@@ -60,14 +63,20 @@ const validateOptions = (flag, input) => {
60
63
  return input;
61
64
  };
62
65
  class Parser {
66
+ input;
67
+ argv;
68
+ raw = [];
69
+ booleanFlags;
70
+ flagAliases;
71
+ context;
72
+ currentFlag;
63
73
  constructor(input) {
64
74
  this.input = input;
65
- this.raw = [];
66
75
  this.context = input.context ?? {};
67
76
  this.argv = [...input.argv];
68
77
  this._setNames();
69
- this.booleanFlags = (0, util_1.pickBy)(input.flags, f => f.type === 'boolean');
70
- this.flagAliases = Object.fromEntries(Object.values(input.flags).flatMap(flag => ([...flag.aliases ?? [], ...flag.charAliases ?? []]).map(a => [a, 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])));
71
80
  }
72
81
  async parse() {
73
82
  this._debugInput();
@@ -88,13 +97,13 @@ class Parser {
88
97
  }
89
98
  const flag = this.input.flags[name];
90
99
  if (flag.type === 'option') {
91
- 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)) {
92
101
  throw new errors_1.CLIError(`Flag --${name} can only be specified once`);
93
102
  }
94
103
  this.currentFlag = flag;
95
104
  const input = isLong || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
96
105
  // if the value ends up being one of the command's flags, the user didn't provide an input
97
- if ((typeof input !== 'string') || this.findFlag(input).name) {
106
+ if (typeof input !== 'string' || this.findFlag(input).name) {
98
107
  throw new errors_1.CLIError(`Flag --${name} expects a value`);
99
108
  }
100
109
  this.raw.push({ type: 'flag', flag: flag.name, input });
@@ -181,40 +190,50 @@ class Parser {
181
190
  }
182
191
  };
183
192
  /* Could add a valueFunction (if there is a value/env/default) and could metadata.
184
- * Value function can be resolved later.
185
- */
193
+ * Value function can be resolved later.
194
+ */
186
195
  const addValueFunction = (fws) => {
187
196
  const tokenLength = fws.tokens?.length;
188
197
  // user provided some input
189
198
  if (tokenLength) {
190
199
  // boolean
191
- if (fws.inputFlag.flag.type === 'boolean' && (0, util_1.last)(fws.tokens)?.input) {
200
+ if (fws.inputFlag.flag.type === 'boolean' && (0, index_1.last)(fws.tokens)?.input) {
192
201
  return {
193
202
  ...fws,
194
- valueFunction: async (i) => parseFlagOrThrowError((0, util_1.last)(i.tokens)?.input !== `--no-${i.inputFlag.name}`, i.inputFlag.flag, this.context, (0, util_1.last)(i.tokens)),
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)),
195
204
  };
196
205
  }
197
206
  // multiple with custom delimiter
198
207
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.delimiter && fws.inputFlag.flag.multiple) {
199
208
  return {
200
- ...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 ?? ','))
201
212
  // trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
202
- .map(v => v.trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'))
203
- .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, 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)),
204
223
  };
205
224
  }
206
225
  // multiple in the oclif-core style
207
226
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.multiple) {
208
227
  return {
209
228
  ...fws,
210
- 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))),
211
230
  };
212
231
  }
213
232
  // simple option flag
214
233
  if (fws.inputFlag.flag.type === 'option') {
215
234
  return {
216
235
  ...fws,
217
- valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, (0, util_1.last)(fws.tokens)?.input), i.inputFlag.flag, this.context, (0, util_1.last)(fws.tokens)),
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)),
218
237
  };
219
238
  }
220
239
  }
@@ -230,7 +249,7 @@ class Parser {
230
249
  if (fws.inputFlag.flag.type === 'boolean') {
231
250
  return {
232
251
  ...fws,
233
- valueFunction: async (i) => (0, util_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false'),
252
+ valueFunction: async (i) => (0, index_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false'),
234
253
  };
235
254
  }
236
255
  }
@@ -238,7 +257,8 @@ class Parser {
238
257
  // eslint-disable-next-line no-constant-binary-expression, valid-typeof
239
258
  if (typeof fws.inputFlag.flag.default !== undefined) {
240
259
  return {
241
- ...fws, metadata: { setFromDefault: true },
260
+ ...fws,
261
+ metadata: { setFromDefault: true },
242
262
  valueFunction: typeof fws.inputFlag.flag.default === 'function'
243
263
  ? (i, allFlags = {}) => fws.inputFlag.flag.default({ options: i.inputFlag.flag, flags: allFlags })
244
264
  : async () => fws.inputFlag.flag.default,
@@ -250,17 +270,19 @@ class Parser {
250
270
  const addHelpFunction = (fws) => {
251
271
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.defaultHelp) {
252
272
  return {
253
- ...fws, helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function'
254
- // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
255
- ? (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) =>
256
276
  // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
257
- : (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,
258
280
  };
259
281
  }
260
282
  return fws;
261
283
  };
262
284
  const addDefaultHelp = async (fwsArray) => {
263
- const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter(fws => !fws.metadata?.setFromDefault));
285
+ const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter((fws) => !fws.metadata?.setFromDefault));
264
286
  return Promise.all(fwsArray.map(async (fws) => {
265
287
  try {
266
288
  if (fws.helpFunction) {
@@ -279,26 +301,32 @@ class Parser {
279
301
  return fws;
280
302
  }));
281
303
  };
282
- const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.filter(fws => fws.value !== undefined)
283
- .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]));
284
305
  const flagTokenMap = this.mapAndValidateFlags();
285
306
  const flagsWithValues = await Promise.all(Object.entries(this.input.flags)
286
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
287
- .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))
288
313
  // match each possible flag to its token, if there is one
289
314
  .map(([name, flag]) => ({ inputFlag: { name, flag }, tokens: flagTokenMap.get(name) }))
290
- .map(fws => addValueFunction(fws))
291
- .filter(fws => fws.valueFunction !== undefined)
292
- .map(fws => addHelpFunction(fws))
315
+ .map((fws) => addValueFunction(fws))
316
+ .filter((fws) => fws.valueFunction !== undefined)
317
+ .map((fws) => addHelpFunction(fws))
293
318
  // we can't apply the default values until all the other flags are resolved because `flag.default` can reference other flags
294
319
  .map(async (fws) => (fws.metadata?.setFromDefault ? fws : { ...fws, value: await fws.valueFunction?.(fws) })));
295
- const valueReference = fwsArrayToObject(flagsWithValues.filter(fws => !fws.metadata?.setFromDefault));
296
- const flagsWithAllValues = await Promise.all(flagsWithValues
297
- .map(async (fws) => (fws.metadata?.setFromDefault ? { ...fws, value: await fws.valueFunction?.(fws, valueReference) } : fws)));
298
- 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;
299
325
  return {
300
326
  flags: fwsArrayToObject(finalFlags),
301
- 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
+ },
302
330
  };
303
331
  }
304
332
  async _args() {
@@ -308,7 +336,7 @@ class Parser {
308
336
  let stdinRead = false;
309
337
  const ctx = this.context;
310
338
  for (const [name, arg] of Object.entries(this.input.args)) {
311
- const token = tokens.find(t => t.arg === name);
339
+ const token = tokens.find((t) => t.arg === name);
312
340
  ctx.token = token;
313
341
  if (token) {
314
342
  if (arg.options && !arg.options.includes(token.input)) {
@@ -367,11 +395,11 @@ class Parser {
367
395
  if (Object.keys(this.input.flags).length === 0)
368
396
  return;
369
397
  debug('available flags: %s', Object.keys(this.input.flags)
370
- .map(f => `--${f}`)
398
+ .map((f) => `--${f}`)
371
399
  .join(' '));
372
400
  }
373
401
  get _argTokens() {
374
- return this.raw.filter(o => o.type === 'arg');
402
+ return this.raw.filter((o) => o.type === 'arg');
375
403
  }
376
404
  _setNames() {
377
405
  for (const k of Object.keys(this.input.flags)) {
@@ -383,7 +411,7 @@ class Parser {
383
411
  }
384
412
  mapAndValidateFlags() {
385
413
  const flagTokenMap = new Map();
386
- for (const token of this.raw.filter(o => o.type === 'flag')) {
414
+ for (const token of this.raw.filter((o) => o.type === 'flag')) {
387
415
  // fail fast if there are any invalid flags
388
416
  if (!(token.flag in this.input.flags)) {
389
417
  throw new errors_1.CLIError(`Unexpected flag ${token.flag}`);
@@ -411,12 +439,12 @@ class Parser {
411
439
  if (this.flagAliases[char]) {
412
440
  return this.flagAliases[char].name;
413
441
  }
414
- return Object.keys(this.input.flags).find(k => (this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined));
442
+ return Object.keys(this.input.flags).find((k) => this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined);
415
443
  }
416
444
  findFlag(arg) {
417
445
  const isLong = arg.startsWith('--');
418
446
  const short = isLong ? false : arg.startsWith('-');
419
- const name = isLong ? this.findLongFlag(arg) : (short ? this.findShortFlag(arg) : undefined);
447
+ const name = isLong ? this.findLongFlag(arg) : short ? this.findShortFlag(arg) : undefined;
420
448
  return { name, isLong };
421
449
  }
422
450
  }
@@ -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("../util");
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 = (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, 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 { ...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,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).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
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();
@@ -4,10 +4,17 @@ exports.Performance = void 0;
4
4
  const node_perf_hooks_1 = require("node:perf_hooks");
5
5
  const settings_1 = require("./settings");
6
6
  class Marker {
7
+ name;
8
+ details;
9
+ module;
10
+ method;
11
+ scope;
12
+ stopped = false;
13
+ startMarker;
14
+ stopMarker;
7
15
  constructor(name, details = {}) {
8
16
  this.name = name;
9
17
  this.details = details;
10
- this.stopped = false;
11
18
  this.startMarker = `${this.name}-start`;
12
19
  this.stopMarker = `${this.name}-stop`;
13
20
  const [caller, scope] = name.split('#');
@@ -29,6 +36,9 @@ class Marker {
29
36
  }
30
37
  }
31
38
  class Performance {
39
+ static markers = {};
40
+ static _results = [];
41
+ static _highlights;
32
42
  static get enabled() {
33
43
  return settings_1.settings.performanceEnabled ?? false;
34
44
  }
@@ -40,7 +50,7 @@ class Performance {
40
50
  throw new Error('Perf results not available. Did you forget to call await Performance.collect()?');
41
51
  }
42
52
  static getResult(name) {
43
- return Performance.results.find(r => r.name === name);
53
+ return Performance.results.find((r) => r.name === name);
44
54
  }
45
55
  static get highlights() {
46
56
  if (!Performance.enabled)
@@ -76,11 +86,11 @@ class Performance {
76
86
  const markers = Object.values(Performance.markers);
77
87
  if (markers.length === 0)
78
88
  return;
79
- for (const marker of markers.filter(m => !m.stopped)) {
89
+ for (const marker of markers.filter((m) => !m.stopped)) {
80
90
  marker.stop();
81
91
  }
82
- return new Promise(resolve => {
83
- const perfObserver = new node_perf_hooks_1.PerformanceObserver(items => {
92
+ return new Promise((resolve) => {
93
+ const perfObserver = new node_perf_hooks_1.PerformanceObserver((items) => {
84
94
  for (const entry of items.getEntries()) {
85
95
  if (Performance.markers[entry.name]) {
86
96
  const marker = Performance.markers[entry.name];
@@ -94,8 +104,11 @@ class Performance {
94
104
  });
95
105
  }
96
106
  }
97
- const command = Performance.results.find(r => r.name.startsWith('config.runCommand'));
98
- const commandLoadTime = command ? Performance.getResult(`plugin.findCommand#${command.details.plugin}.${command.details.command}`)?.duration ?? 0 : 0;
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;
99
112
  const pluginLoadTimes = Object.fromEntries(Performance.results
100
113
  .filter(({ name }) => name.startsWith('plugin.load#'))
101
114
  .sort((a, b) => b.duration - a.duration)
@@ -185,5 +198,3 @@ class Performance {
185
198
  }
186
199
  }
187
200
  exports.Performance = Performance;
188
- Performance.markers = {};
189
- Performance._results = [];
@@ -0,0 +1,2 @@
1
+ import { FlagInput, FlagOutput } from '../interfaces/parser';
2
+ export declare function aggregateFlags<F extends FlagOutput, B extends FlagOutput>(flags: FlagInput<F> | undefined, baseFlags: FlagInput<B> | undefined, enableJsonFlag: boolean | undefined): FlagInput<F>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.aggregateFlags = void 0;
4
+ const flags_1 = require("../flags");
5
+ const json = (0, flags_1.boolean)({
6
+ description: 'Format output as json.',
7
+ helpGroup: 'GLOBAL',
8
+ });
9
+ function aggregateFlags(flags, baseFlags, enableJsonFlag) {
10
+ const combinedFlags = { ...baseFlags, ...flags };
11
+ return (enableJsonFlag ? { json, ...combinedFlags } : combinedFlags);
12
+ }
13
+ exports.aggregateFlags = aggregateFlags;
@@ -0,0 +1,3 @@
1
+ import { Command } from '../command';
2
+ import { Plugin as IPlugin } from '../interfaces/plugin';
3
+ export declare function cacheCommand(uncachedCmd: Command.Class, plugin?: IPlugin, respectNoCacheDefault?: boolean): Promise<Command.Cached>;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cacheCommand = void 0;
4
+ const index_1 = require("./index");
5
+ const aggregate_flags_1 = require("./aggregate-flags");
6
+ const cache_default_value_1 = require("./cache-default-value");
7
+ // In order to collect static properties up the inheritance chain, we need to recursively
8
+ // access the prototypes until there's nothing left. This allows us to combine baseFlags
9
+ // and flags as well as add in the json flag if enableJsonFlag is enabled.
10
+ function mergePrototype(result, cmd) {
11
+ const proto = Object.getPrototypeOf(cmd);
12
+ const filteredProto = (0, index_1.pickBy)(proto, (v) => v !== undefined);
13
+ return Object.keys(proto).length > 0 ? mergePrototype({ ...filteredProto, ...result }, proto) : result;
14
+ }
15
+ async function cacheFlags(cmdFlags, respectNoCacheDefault) {
16
+ const promises = Object.entries(cmdFlags).map(async ([name, flag]) => [
17
+ name,
18
+ {
19
+ name,
20
+ char: flag.char,
21
+ summary: flag.summary,
22
+ hidden: flag.hidden,
23
+ required: flag.required,
24
+ helpLabel: flag.helpLabel,
25
+ helpGroup: flag.helpGroup,
26
+ description: flag.description,
27
+ dependsOn: flag.dependsOn,
28
+ relationships: flag.relationships,
29
+ exclusive: flag.exclusive,
30
+ deprecated: flag.deprecated,
31
+ deprecateAliases: flag.deprecateAliases,
32
+ aliases: flag.aliases,
33
+ charAliases: flag.charAliases,
34
+ noCacheDefault: flag.noCacheDefault,
35
+ ...(flag.type === 'boolean'
36
+ ? {
37
+ allowNo: flag.allowNo,
38
+ type: flag.type,
39
+ }
40
+ : {
41
+ type: flag.type,
42
+ helpValue: flag.helpValue,
43
+ multiple: flag.multiple,
44
+ options: flag.options,
45
+ delimiter: flag.delimiter,
46
+ default: await (0, cache_default_value_1.cacheDefaultValue)(flag, respectNoCacheDefault),
47
+ hasDynamicHelp: typeof flag.defaultHelp === 'function',
48
+ }),
49
+ },
50
+ ]);
51
+ return Object.fromEntries(await Promise.all(promises));
52
+ }
53
+ async function cacheArgs(cmdArgs, respectNoCacheDefault) {
54
+ const promises = Object.entries(cmdArgs).map(async ([name, arg]) => [
55
+ name,
56
+ {
57
+ name,
58
+ description: arg.description,
59
+ required: arg.required,
60
+ options: arg.options,
61
+ default: await (0, cache_default_value_1.cacheDefaultValue)(arg, respectNoCacheDefault),
62
+ hidden: arg.hidden,
63
+ noCacheDefault: arg.noCacheDefault,
64
+ },
65
+ ]);
66
+ return Object.fromEntries(await Promise.all(promises));
67
+ }
68
+ async function cacheCommand(uncachedCmd, plugin, respectNoCacheDefault = false) {
69
+ const cmd = mergePrototype(uncachedCmd, uncachedCmd);
70
+ const flags = await cacheFlags((0, aggregate_flags_1.aggregateFlags)(cmd.flags, cmd.baseFlags, cmd.enableJsonFlag), respectNoCacheDefault);
71
+ const args = await cacheArgs((0, index_1.ensureArgObject)(cmd.args), respectNoCacheDefault);
72
+ const stdProperties = {
73
+ id: cmd.id,
74
+ summary: cmd.summary,
75
+ description: cmd.description,
76
+ strict: cmd.strict,
77
+ usage: cmd.usage,
78
+ pluginName: plugin && plugin.name,
79
+ pluginAlias: plugin && plugin.alias,
80
+ pluginType: plugin && plugin.type,
81
+ hidden: cmd.hidden,
82
+ state: cmd.state,
83
+ aliases: cmd.aliases || [],
84
+ examples: cmd.examples || cmd.example,
85
+ deprecationOptions: cmd.deprecationOptions,
86
+ deprecateAliases: cmd.deprecateAliases,
87
+ flags,
88
+ args,
89
+ hasDynamicHelp: Object.values(flags).some((f) => f.hasDynamicHelp),
90
+ };
91
+ // do not include these properties in manifest
92
+ const ignoreCommandProperties = [
93
+ 'plugin',
94
+ '_flags',
95
+ '_enableJsonFlag',
96
+ '_globalFlags',
97
+ '_baseFlags',
98
+ 'baseFlags',
99
+ '_--',
100
+ '_base',
101
+ ];
102
+ // Add in any additional properties that are not standard command properties.
103
+ const stdKeysAndIgnored = new Set([...Object.keys(stdProperties), ...ignoreCommandProperties]);
104
+ const keysToAdd = Object.keys(cmd).filter((property) => !stdKeysAndIgnored.has(property));
105
+ const additionalProperties = Object.fromEntries(keysToAdd.map((key) => [key, cmd[key]]));
106
+ return { ...stdProperties, ...additionalProperties };
107
+ }
108
+ exports.cacheCommand = cacheCommand;
@@ -0,0 +1,2 @@
1
+ import { Arg, OptionFlag } from '../interfaces/parser';
2
+ export declare const cacheDefaultValue: (flagOrArg: OptionFlag<any> | Arg<any>, respectNoCacheDefault: boolean) => Promise<any>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cacheDefaultValue = void 0;
4
+ // when no manifest exists, the default is calculated. This may throw, so we need to catch it
5
+ const cacheDefaultValue = async (flagOrArg, respectNoCacheDefault) => {
6
+ if (respectNoCacheDefault && flagOrArg.noCacheDefault)
7
+ return;
8
+ // Prefer the defaultHelp function (returns a friendly string for complex types)
9
+ if (typeof flagOrArg.defaultHelp === 'function') {
10
+ try {
11
+ return await flagOrArg.defaultHelp({ options: flagOrArg, flags: {} });
12
+ }
13
+ catch {
14
+ return;
15
+ }
16
+ }
17
+ // if not specified, try the default function
18
+ if (typeof flagOrArg.default === 'function') {
19
+ try {
20
+ return await flagOrArg.default({ options: flagOrArg, flags: {} });
21
+ }
22
+ catch { }
23
+ }
24
+ else {
25
+ return flagOrArg.default;
26
+ }
27
+ };
28
+ exports.cacheDefaultValue = cacheDefaultValue;
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
- import { ArgInput } from './interfaces/parser';
3
- import { Command } from './command';
2
+ import { ArgInput } from '../interfaces/parser';
3
+ import { Command } from '../command';
4
4
  export declare function pickBy<T extends {
5
5
  [s: string]: T[keyof T];
6
6
  } | ArrayLike<T[keyof T]>>(obj: T, fn: (i: T[keyof T]) => boolean): Partial<T>;
@@ -52,4 +52,9 @@ export declare function getPlatform(): NodeJS.Platform;
52
52
  export declare function readJson<T = unknown>(path: string): Promise<T>;
53
53
  export declare function readJsonSync(path: string, parse: false): string;
54
54
  export declare function readJsonSync<T = unknown>(path: string, parse?: true): T;
55
+ export declare function mapValues<T extends Record<string, any>, TResult>(obj: {
56
+ [P in keyof T]: T[P];
57
+ }, fn: (i: T[keyof T], k: keyof T) => TResult): {
58
+ [P in keyof T]: TResult;
59
+ };
55
60
  export {};