@oclif/core 3.0.0-beta.8 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +4 -2
  2. package/flush.d.ts +3 -0
  3. package/flush.js +1 -0
  4. package/handle.js +1 -0
  5. package/lib/args.d.ts +2 -2
  6. package/lib/args.js +17 -18
  7. package/lib/{ux → cli-ux}/action/base.d.ts +19 -21
  8. package/lib/{ux → cli-ux}/action/base.js +126 -120
  9. package/lib/{ux → cli-ux}/action/simple.js +25 -30
  10. package/lib/{ux → cli-ux}/action/spinner.d.ts +9 -7
  11. package/lib/{ux → cli-ux}/action/spinner.js +45 -37
  12. package/lib/{ux → cli-ux}/action/spinners.js +187 -187
  13. package/lib/cli-ux/action/types.d.ts +5 -0
  14. package/lib/cli-ux/action/types.js +2 -0
  15. package/lib/{ux → cli-ux}/config.d.ts +5 -5
  16. package/lib/{ux → cli-ux}/config.js +17 -17
  17. package/lib/{ux → cli-ux}/exit.js +3 -0
  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 +39 -0
  21. package/lib/{ux → cli-ux}/index.js +74 -97
  22. package/lib/{ux → cli-ux}/list.js +3 -3
  23. package/lib/{ux → cli-ux}/prompt.d.ts +3 -3
  24. package/lib/{ux → cli-ux}/prompt.js +35 -25
  25. package/lib/{ux → cli-ux}/stream.d.ts +6 -6
  26. package/lib/{ux → cli-ux}/stream.js +11 -10
  27. package/lib/cli-ux/styled/index.d.ts +4 -0
  28. package/lib/cli-ux/styled/index.js +11 -0
  29. package/lib/{ux → cli-ux}/styled/object.js +7 -9
  30. package/lib/{ux → cli-ux}/styled/table.d.ts +10 -10
  31. package/lib/{ux → cli-ux}/styled/table.js +130 -133
  32. package/lib/{ux → cli-ux}/styled/tree.js +11 -13
  33. package/lib/cli-ux/wait.js +5 -0
  34. package/lib/command.d.ts +82 -88
  35. package/lib/command.js +196 -175
  36. package/lib/config/config.d.ts +89 -90
  37. package/lib/config/config.js +466 -566
  38. package/lib/config/index.d.ts +0 -1
  39. package/lib/config/index.js +1 -3
  40. package/lib/config/plugin-loader.d.ts +12 -12
  41. package/lib/config/plugin-loader.js +72 -56
  42. package/lib/config/plugin.d.ts +25 -24
  43. package/lib/config/plugin.js +188 -154
  44. package/lib/config/ts-node.d.ts +2 -1
  45. package/lib/config/ts-node.js +71 -58
  46. package/lib/config/util.d.ts +1 -11
  47. package/lib/config/util.js +6 -59
  48. package/lib/errors/config.d.ts +1 -1
  49. package/lib/errors/config.js +6 -6
  50. package/lib/errors/errors/cli.d.ts +7 -7
  51. package/lib/errors/errors/cli.js +20 -16
  52. package/lib/errors/errors/exit.d.ts +1 -4
  53. package/lib/errors/errors/exit.js +1 -1
  54. package/lib/errors/errors/module-load.d.ts +1 -4
  55. package/lib/errors/errors/module-load.js +1 -1
  56. package/lib/errors/errors/pretty-print.d.ts +1 -1
  57. package/lib/errors/errors/pretty-print.js +12 -10
  58. package/lib/errors/handle.d.ts +12 -2
  59. package/lib/errors/handle.js +26 -14
  60. package/lib/errors/index.d.ts +10 -10
  61. package/lib/errors/index.js +25 -24
  62. package/lib/errors/logger.d.ts +2 -2
  63. package/lib/errors/logger.js +14 -13
  64. package/lib/execute.d.ts +6 -6
  65. package/lib/execute.js +10 -9
  66. package/lib/flags.d.ts +103 -32
  67. package/lib/flags.js +79 -45
  68. package/lib/help/command.d.ts +16 -14
  69. package/lib/help/command.js +178 -163
  70. package/lib/help/docopts.d.ts +5 -5
  71. package/lib/help/docopts.js +50 -54
  72. package/lib/help/formatter.d.ts +37 -37
  73. package/lib/help/formatter.js +66 -55
  74. package/lib/help/index.d.ts +25 -21
  75. package/lib/help/index.js +169 -147
  76. package/lib/help/root.d.ts +1 -1
  77. package/lib/help/root.js +15 -17
  78. package/lib/help/util.d.ts +2 -8
  79. package/lib/help/util.js +8 -28
  80. package/lib/index.d.ts +19 -20
  81. package/lib/index.js +37 -43
  82. package/lib/interfaces/config.d.ts +67 -66
  83. package/lib/interfaces/errors.d.ts +5 -5
  84. package/lib/interfaces/help.d.ts +17 -17
  85. package/lib/interfaces/hooks.d.ts +49 -49
  86. package/lib/interfaces/index.d.ts +7 -7
  87. package/lib/interfaces/manifest.d.ts +1 -1
  88. package/lib/interfaces/parser.d.ts +175 -51
  89. package/lib/interfaces/pjson.d.ts +41 -41
  90. package/lib/interfaces/plugin.d.ts +47 -41
  91. package/lib/interfaces/s3-manifest.d.ts +7 -7
  92. package/lib/interfaces/topic.d.ts +1 -1
  93. package/lib/interfaces/ts-config.d.ts +7 -7
  94. package/lib/main.d.ts +2 -2
  95. package/lib/main.js +16 -16
  96. package/lib/module-loader.d.ts +67 -77
  97. package/lib/module-loader.js +183 -150
  98. package/lib/parser/errors.d.ts +7 -7
  99. package/lib/parser/errors.js +29 -22
  100. package/lib/parser/help.js +5 -5
  101. package/lib/parser/index.js +2 -2
  102. package/lib/parser/parse.d.ts +9 -6
  103. package/lib/parser/parse.js +253 -221
  104. package/lib/parser/validate.js +53 -33
  105. package/lib/performance.d.ts +43 -32
  106. package/lib/performance.js +133 -91
  107. package/lib/screen.js +2 -2
  108. package/lib/settings.d.ts +11 -12
  109. package/lib/settings.js +2 -2
  110. package/lib/util/aggregate-flags.d.ts +2 -0
  111. package/lib/util/aggregate-flags.js +13 -0
  112. package/lib/util/cache-command.d.ts +3 -0
  113. package/lib/util/cache-command.js +109 -0
  114. package/lib/util/cache-default-value.d.ts +2 -0
  115. package/lib/util/cache-default-value.js +28 -0
  116. package/lib/util/ensure-arg-object.d.ts +12 -0
  117. package/lib/util/ensure-arg-object.js +14 -0
  118. package/lib/util/fs.d.ts +7 -0
  119. package/lib/util/fs.js +54 -0
  120. package/lib/util/os.d.ts +19 -0
  121. package/lib/util/os.js +28 -0
  122. package/lib/{util.d.ts → util/util.d.ts} +7 -16
  123. package/lib/util/util.js +98 -0
  124. package/package.json +35 -37
  125. package/lib/util.js +0 -126
  126. package/lib/ux/flush.d.ts +0 -1
  127. package/lib/ux/flush.js +0 -27
  128. package/lib/ux/index.d.ts +0 -64
  129. package/lib/ux/styled/index.d.ts +0 -6
  130. package/lib/ux/styled/index.js +0 -13
  131. package/lib/ux/styled/json.d.ts +0 -1
  132. package/lib/ux/styled/json.js +0 -15
  133. package/lib/ux/wait.js +0 -7
  134. package/lib/{ux → cli-ux}/action/simple.d.ts +4 -4
  135. package/lib/{ux → cli-ux}/action/spinners.d.ts +117 -117
  136. package/lib/{ux → cli-ux}/exit.d.ts +2 -2
  137. package/lib/{ux → cli-ux}/list.d.ts +0 -0
  138. package/lib/{ux → cli-ux}/styled/object.d.ts +0 -0
  139. package/lib/{ux → cli-ux}/styled/progress.d.ts +0 -0
  140. package/lib/{ux → cli-ux}/styled/progress.js +0 -0
  141. package/lib/{ux → cli-ux}/styled/tree.d.ts +1 -1
  142. /package/lib/{ux → cli-ux}/wait.d.ts +0 -0
@@ -2,16 +2,22 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Parser = void 0;
4
4
  /* eslint-disable no-await-in-loop */
5
+ const node_readline_1 = require("node:readline");
6
+ const util_1 = require("../util/util");
5
7
  const errors_1 = require("./errors");
6
- const readline = require("readline");
7
- const util_1 = require("../util");
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
22
  const readStdin = async () => {
17
23
  const { stdin, stdout } = process;
@@ -22,17 +28,17 @@ const readStdin = async () => {
22
28
  // Because of this, we have to set a timeout to prevent the process from hanging.
23
29
  if (stdin.isTTY)
24
30
  return null;
25
- return new Promise(resolve => {
31
+ return new Promise((resolve) => {
26
32
  let result = '';
27
33
  const ac = new AbortController();
28
- const signal = ac.signal;
34
+ const { signal } = ac;
29
35
  const timeout = setTimeout(() => ac.abort(), 100);
30
- const rl = readline.createInterface({
36
+ const rl = (0, node_readline_1.createInterface)({
31
37
  input: stdin,
32
38
  output: stdout,
33
39
  terminal: false,
34
40
  });
35
- rl.on('line', line => {
41
+ rl.on('line', (line) => {
36
42
  result += line;
37
43
  });
38
44
  rl.once('close', () => {
@@ -51,144 +57,110 @@ const readStdin = async () => {
51
57
  function isNegativeNumber(input) {
52
58
  return /^-\d/g.test(input);
53
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
+ };
54
65
  class Parser {
66
+ input;
67
+ argv;
68
+ booleanFlags;
69
+ context;
70
+ currentFlag;
71
+ flagAliases;
72
+ raw = [];
55
73
  constructor(input) {
56
74
  this.input = input;
57
- this.raw = [];
58
75
  this.context = input.context ?? {};
59
76
  this.argv = [...input.argv];
60
77
  this._setNames();
61
- this.booleanFlags = (0, util_1.pickBy)(input.flags, f => f.type === 'boolean');
62
- this.flagAliases = Object.fromEntries(Object.values(input.flags).flatMap(flag => {
63
- return (flag.aliases ?? []).map(a => [a, flag]);
64
- }));
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])));
65
80
  }
66
- async parse() {
67
- this._debugInput();
68
- const findLongFlag = (arg) => {
69
- const name = arg.slice(2);
70
- if (this.input.flags[name]) {
71
- return name;
72
- }
73
- if (this.flagAliases[name]) {
74
- return this.flagAliases[name].name;
75
- }
76
- if (arg.startsWith('--no-')) {
77
- const flag = this.booleanFlags[arg.slice(5)];
78
- if (flag && flag.allowNo)
79
- return flag.name;
80
- }
81
- };
82
- const findShortFlag = ([_, char]) => {
83
- if (this.flagAliases[char]) {
84
- return this.flagAliases[char].name;
85
- }
86
- return Object.keys(this.input.flags).find(k => (this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined));
87
- };
88
- const findFlag = (arg) => {
89
- const isLong = arg.startsWith('--');
90
- const short = isLong ? false : arg.startsWith('-');
91
- const name = isLong ? findLongFlag(arg) : (short ? findShortFlag(arg) : undefined);
92
- return { name, isLong };
93
- };
94
- const parseFlag = (arg) => {
95
- const { name, isLong } = findFlag(arg);
96
- if (!name) {
97
- const i = arg.indexOf('=');
98
- if (i !== -1) {
99
- const sliced = arg.slice(i + 1);
100
- this.argv.unshift(sliced);
101
- const equalsParsed = parseFlag(arg.slice(0, i));
102
- if (!equalsParsed) {
103
- this.argv.shift();
104
- }
105
- return equalsParsed;
106
- }
107
- return false;
108
- }
109
- const flag = this.input.flags[name];
110
- if (flag.type === 'option') {
111
- this.currentFlag = flag;
112
- const input = isLong || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
113
- // if the value ends up being one of the command's flags, the user didn't provide an input
114
- if ((typeof input !== 'string') || findFlag(input).name) {
115
- throw new errors_1.CLIError(`Flag --${name} expects a value`);
81
+ get _argTokens() {
82
+ return this.raw.filter((o) => o.type === 'arg');
83
+ }
84
+ async _args() {
85
+ const argv = [];
86
+ const args = {};
87
+ const tokens = this._argTokens;
88
+ let stdinRead = false;
89
+ const ctx = this.context;
90
+ for (const [name, arg] of Object.entries(this.input.args)) {
91
+ const token = tokens.find((t) => t.arg === name);
92
+ ctx.token = token;
93
+ if (token) {
94
+ if (arg.options && !arg.options.includes(token.input)) {
95
+ throw new errors_1.ArgInvalidOptionError(arg, token.input);
116
96
  }
117
- this.raw.push({ type: 'flag', flag: flag.name, input: input });
97
+ const parsed = await arg.parse(token.input, ctx, arg);
98
+ argv.push(parsed);
99
+ args[token.arg] = parsed;
118
100
  }
119
- else {
120
- this.raw.push({ type: 'flag', flag: flag.name, input: arg });
121
- // push the rest of the short characters back on the stack
122
- if (!isLong && arg.length > 2) {
123
- this.argv.unshift(`-${arg.slice(2)}`);
101
+ else if (!arg.ignoreStdin && !stdinRead) {
102
+ let stdin = await readStdin();
103
+ if (stdin) {
104
+ stdin = stdin.trim();
105
+ const parsed = await arg.parse(stdin, ctx, arg);
106
+ argv.push(parsed);
107
+ args[name] = parsed;
124
108
  }
109
+ stdinRead = true;
125
110
  }
126
- return true;
127
- };
128
- let parsingFlags = true;
129
- const nonExistentFlags = [];
130
- let dashdash = false;
131
- const originalArgv = [...this.argv];
132
- while (this.argv.length > 0) {
133
- const input = this.argv.shift();
134
- if (parsingFlags && input.startsWith('-') && input !== '-') {
135
- // attempt to parse as arg
136
- if (this.input['--'] !== false && input === '--') {
137
- parsingFlags = false;
138
- continue;
139
- }
140
- if (parseFlag(input)) {
141
- continue;
142
- }
143
- if (input === '--') {
144
- dashdash = true;
145
- continue;
111
+ if (!args[name] && (arg.default || arg.default === false)) {
112
+ if (typeof arg.default === 'function') {
113
+ const f = await arg.default();
114
+ argv.push(f);
115
+ args[name] = f;
146
116
  }
147
- if (this.input['--'] !== false && !isNegativeNumber(input)) {
148
- // At this point we have a value that begins with '-' or '--'
149
- // but doesn't match up to a flag definition. So we assume that
150
- // this is a misspelled flag or a non-existent flag,
151
- // e.g. --hekp instead of --help
152
- nonExistentFlags.push(input);
153
- continue;
117
+ else {
118
+ argv.push(arg.default);
119
+ args[name] = arg.default;
154
120
  }
155
121
  }
156
- if (parsingFlags && this.currentFlag && this.currentFlag.multiple) {
157
- this.raw.push({ type: 'flag', flag: this.currentFlag.name, input });
122
+ }
123
+ for (const token of tokens) {
124
+ if (args[token.arg])
158
125
  continue;
159
- }
160
- // not a flag, parse as arg
161
- const arg = Object.keys(this.input.args)[this._argTokens.length];
162
- this.raw.push({ type: 'arg', arg, input });
126
+ argv.push(token.input);
127
+ }
128
+ return { args, argv };
129
+ }
130
+ _debugInput() {
131
+ debug('input: %s', this.argv.join(' '));
132
+ const args = Object.keys(this.input.args);
133
+ if (args.length > 0) {
134
+ debug('available args: %s', args.join(' '));
135
+ }
136
+ if (Object.keys(this.input.flags).length === 0)
137
+ return;
138
+ debug('available flags: %s', Object.keys(this.input.flags)
139
+ .map((f) => `--${f}`)
140
+ .join(' '));
141
+ }
142
+ _debugOutput(args, flags, argv) {
143
+ if (argv.length > 0) {
144
+ debug('argv: %o', argv);
145
+ }
146
+ if (Object.keys(args).length > 0) {
147
+ debug('args: %o', args);
148
+ }
149
+ if (Object.keys(flags).length > 0) {
150
+ debug('flags: %o', flags);
163
151
  }
164
- const [{ argv, args }, { flags, metadata }] = await Promise.all([this._args(), this._flags()]);
165
- this._debugOutput(argv, args, flags);
166
- const unsortedArgv = (dashdash ? [...argv, ...nonExistentFlags, '--'] : [...argv, ...nonExistentFlags]);
167
- return {
168
- argv: unsortedArgv.sort((a, b) => originalArgv.indexOf(a) - originalArgv.indexOf(b)),
169
- flags,
170
- args: args,
171
- raw: this.raw,
172
- metadata,
173
- nonExistentFlags,
174
- };
175
152
  }
176
153
  async _flags() {
177
- const validateOptions = (flag, input) => {
178
- if (flag.options && !flag.options.includes(input))
179
- throw new errors_1.FlagInvalidOptionError(flag, input);
180
- return input;
181
- };
182
154
  const parseFlagOrThrowError = async (input, flag, context, token) => {
183
155
  if (!flag.parse)
184
156
  return input;
185
157
  const ctx = {
186
158
  ...context,
187
- token,
188
159
  error: context?.error,
189
160
  exit: context?.exit,
190
161
  log: context?.log,
191
162
  logToStderr: context?.logToStderr,
163
+ token,
192
164
  warn: context?.warn,
193
165
  };
194
166
  try {
@@ -203,8 +175,8 @@ class Parser {
203
175
  }
204
176
  };
205
177
  /* Could add a valueFunction (if there is a value/env/default) and could metadata.
206
- * Value function can be resolved later.
207
- */
178
+ * Value function can be resolved later.
179
+ */
208
180
  const addValueFunction = (fws) => {
209
181
  const tokenLength = fws.tokens?.length;
210
182
  // user provided some input
@@ -219,17 +191,27 @@ class Parser {
219
191
  // multiple with custom delimiter
220
192
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.delimiter && fws.inputFlag.flag.multiple) {
221
193
  return {
222
- ...fws, valueFunction: async (i) => (await Promise.all(((i.tokens ?? []).flatMap(token => token.input.split(i.inputFlag.flag.delimiter)))
194
+ ...fws,
195
+ valueFunction: async (i) => (await Promise.all((i.tokens ?? [])
196
+ .flatMap((token) => token.input.split(i.inputFlag.flag.delimiter ?? ','))
223
197
  // trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
224
- .map(v => v.trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'))
225
- .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)),
198
+ .map((v) => v
199
+ .trim()
200
+ .replace(/^"(.*)"$/, '$1')
201
+ .replace(/^'(.*)'$/, '$1'))
202
+ .map(async (v) => parseFlagOrThrowError(v, i.inputFlag.flag, this.context, {
203
+ ...(0, util_1.last)(i.tokens),
204
+ input: v,
205
+ }))))
206
+ // eslint-disable-next-line unicorn/no-await-expression-member
207
+ .map((v) => validateOptions(i.inputFlag.flag, v)),
226
208
  };
227
209
  }
228
210
  // multiple in the oclif-core style
229
211
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.multiple) {
230
212
  return {
231
213
  ...fws,
232
- valueFunction: async (i) => Promise.all((fws.tokens ?? []).map(token => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, token.input), i.inputFlag.flag, this.context, token))),
214
+ valueFunction: async (i) => Promise.all((fws.tokens ?? []).map((token) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, token.input), i.inputFlag.flag, this.context, token))),
233
215
  };
234
216
  }
235
217
  // simple option flag
@@ -252,17 +234,19 @@ class Parser {
252
234
  if (fws.inputFlag.flag.type === 'boolean') {
253
235
  return {
254
236
  ...fws,
255
- valueFunction: async (i) => Promise.resolve((0, util_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false')),
237
+ valueFunction: async (i) => (0, util_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false'),
256
238
  };
257
239
  }
258
240
  }
259
241
  // no input, but flag has default value
242
+ // eslint-disable-next-line no-constant-binary-expression, valid-typeof
260
243
  if (typeof fws.inputFlag.flag.default !== undefined) {
261
244
  return {
262
- ...fws, metadata: { setFromDefault: true },
263
- valueFunction: typeof fws.inputFlag.flag.default === 'function' ?
264
- (i, allFlags = {}) => fws.inputFlag.flag.default({ options: i.inputFlag.flag, flags: allFlags }) :
265
- async () => fws.inputFlag.flag.default,
245
+ ...fws,
246
+ metadata: { setFromDefault: true },
247
+ valueFunction: typeof fws.inputFlag.flag.default === 'function'
248
+ ? (i, allFlags = {}) => fws.inputFlag.flag.default({ flags: allFlags, options: i.inputFlag.flag })
249
+ : async () => fws.inputFlag.flag.default,
266
250
  };
267
251
  }
268
252
  // base case (no value function)
@@ -271,17 +255,19 @@ class Parser {
271
255
  const addHelpFunction = (fws) => {
272
256
  if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.defaultHelp) {
273
257
  return {
274
- ...fws, helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function' ?
275
- // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
276
- (i, flags, ...context) => i.inputFlag.flag.defaultHelp({ options: i.inputFlag, flags }, ...context) :
258
+ ...fws,
259
+ helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function'
260
+ ? (i, flags, ...context) =>
277
261
  // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
278
- (i) => i.inputFlag.flag.defaultHelp,
262
+ i.inputFlag.flag.defaultHelp({ flags, options: i.inputFlag }, ...context)
263
+ : // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
264
+ (i) => i.inputFlag.flag.defaultHelp,
279
265
  };
280
266
  }
281
267
  return fws;
282
268
  };
283
269
  const addDefaultHelp = async (fwsArray) => {
284
- const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter(fws => !fws.metadata?.setFromDefault));
270
+ const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter((fws) => !fws.metadata?.setFromDefault));
285
271
  return Promise.all(fwsArray.map(async (fws) => {
286
272
  try {
287
273
  if (fws.helpFunction) {
@@ -300,112 +286,71 @@ class Parser {
300
286
  return fws;
301
287
  }));
302
288
  };
303
- const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.filter(fws => fws.value !== undefined)
304
- .map(fws => [fws.inputFlag.name, fws.value]));
289
+ const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.filter((fws) => fws.value !== undefined).map((fws) => [fws.inputFlag.name, fws.value]));
305
290
  const flagTokenMap = this.mapAndValidateFlags();
306
291
  const flagsWithValues = await Promise.all(Object.entries(this.input.flags)
307
292
  // we check them if they have a token, or might have env, default, or defaultHelp. Also include booleans so they get their default value
308
- .filter(([name, flag]) => flag.type === 'boolean' || flag.env || flag.default !== undefined || 'defaultHelp' in flag || flagTokenMap.has(name))
293
+ .filter(([name, flag]) => flag.type === 'boolean' ||
294
+ flag.env ||
295
+ flag.default !== undefined ||
296
+ 'defaultHelp' in flag ||
297
+ flagTokenMap.has(name))
309
298
  // match each possible flag to its token, if there is one
310
- .map(([name, flag]) => ({ inputFlag: { name, flag }, tokens: flagTokenMap.get(name) }))
311
- .map(fws => addValueFunction(fws))
312
- .filter(fws => fws.valueFunction !== undefined)
313
- .map(fws => addHelpFunction(fws))
299
+ .map(([name, flag]) => ({ inputFlag: { flag, name }, tokens: flagTokenMap.get(name) }))
300
+ .map((fws) => addValueFunction(fws))
301
+ .filter((fws) => fws.valueFunction !== undefined)
302
+ .map((fws) => addHelpFunction(fws))
314
303
  // we can't apply the default values until all the other flags are resolved because `flag.default` can reference other flags
315
304
  .map(async (fws) => (fws.metadata?.setFromDefault ? fws : { ...fws, value: await fws.valueFunction?.(fws) })));
316
- const valueReference = fwsArrayToObject(flagsWithValues.filter(fws => !fws.metadata?.setFromDefault));
317
- const flagsWithAllValues = await Promise.all(flagsWithValues
318
- .map(async (fws) => (fws.metadata?.setFromDefault ? { ...fws, value: await fws.valueFunction?.(fws, valueReference) } : fws)));
319
- const finalFlags = (flagsWithAllValues.some(fws => typeof fws.helpFunction === 'function')) ? await addDefaultHelp(flagsWithAllValues) : flagsWithAllValues;
305
+ const valueReference = fwsArrayToObject(flagsWithValues.filter((fws) => !fws.metadata?.setFromDefault));
306
+ const flagsWithAllValues = await Promise.all(flagsWithValues.map(async (fws) => fws.metadata?.setFromDefault ? { ...fws, value: await fws.valueFunction?.(fws, valueReference) } : fws));
307
+ const finalFlags = flagsWithAllValues.some((fws) => typeof fws.helpFunction === 'function')
308
+ ? await addDefaultHelp(flagsWithAllValues)
309
+ : flagsWithAllValues;
320
310
  return {
321
- // @ts-ignore original version returned an any. Not sure how to get to the return type for `flags` prop
322
311
  flags: fwsArrayToObject(finalFlags),
323
- metadata: { flags: Object.fromEntries(finalFlags.filter(fws => fws.metadata).map(fws => [fws.inputFlag.name, fws.metadata])) },
312
+ metadata: {
313
+ flags: Object.fromEntries(finalFlags.filter((fws) => fws.metadata).map((fws) => [fws.inputFlag.name, fws.metadata])),
314
+ },
324
315
  };
325
316
  }
326
- async _args() {
327
- const argv = [];
328
- const args = {};
329
- const tokens = this._argTokens;
330
- let stdinRead = false;
331
- const ctx = this.context;
332
- for (const [name, arg] of Object.entries(this.input.args)) {
333
- const token = tokens.find(t => t.arg === name);
334
- ctx.token = token;
335
- if (token) {
336
- if (arg.options && !arg.options.includes(token.input)) {
337
- throw new errors_1.ArgInvalidOptionError(arg, token.input);
338
- }
339
- const parsed = await arg.parse(token.input, ctx, arg);
340
- argv.push(parsed);
341
- args[token.arg] = parsed;
342
- }
343
- else if (!arg.ignoreStdin && !stdinRead) {
344
- let stdin = await readStdin();
345
- if (stdin) {
346
- stdin = stdin.trim();
347
- const parsed = await arg.parse(stdin, ctx, arg);
348
- argv.push(parsed);
349
- args[name] = parsed;
350
- }
351
- stdinRead = true;
352
- }
353
- if (!args[name] && (arg.default || arg.default === false)) {
354
- if (typeof arg.default === 'function') {
355
- const f = await arg.default();
356
- argv.push(f);
357
- args[name] = f;
358
- }
359
- else {
360
- argv.push(arg.default);
361
- args[name] = arg.default;
362
- }
363
- }
317
+ _setNames() {
318
+ for (const k of Object.keys(this.input.flags)) {
319
+ this.input.flags[k].name = k;
364
320
  }
365
- for (const token of tokens) {
366
- if (args[token.arg])
367
- continue;
368
- argv.push(token.input);
321
+ for (const k of Object.keys(this.input.args)) {
322
+ this.input.args[k].name = k;
369
323
  }
370
- return { argv, args: args };
371
324
  }
372
- _debugOutput(args, flags, argv) {
373
- if (argv.length > 0) {
374
- debug('argv: %o', argv);
375
- }
376
- if (Object.keys(args).length > 0) {
377
- debug('args: %o', args);
325
+ findFlag(arg) {
326
+ const isLong = arg.startsWith('--');
327
+ const short = isLong ? false : arg.startsWith('-');
328
+ const name = isLong ? this.findLongFlag(arg) : short ? this.findShortFlag(arg) : undefined;
329
+ return { isLong, name };
330
+ }
331
+ findLongFlag(arg) {
332
+ const name = arg.slice(2);
333
+ if (this.input.flags[name]) {
334
+ return name;
378
335
  }
379
- if (Object.keys(flags).length > 0) {
380
- debug('flags: %o', flags);
336
+ if (this.flagAliases[name]) {
337
+ return this.flagAliases[name].name;
381
338
  }
382
- }
383
- _debugInput() {
384
- debug('input: %s', this.argv.join(' '));
385
- const args = Object.keys(this.input.args);
386
- if (args.length > 0) {
387
- debug('available args: %s', args.join(' '));
339
+ if (arg.startsWith('--no-')) {
340
+ const flag = this.booleanFlags[arg.slice(5)];
341
+ if (flag && flag.allowNo)
342
+ return flag.name;
388
343
  }
389
- if (Object.keys(this.input.flags).length === 0)
390
- return;
391
- debug('available flags: %s', Object.keys(this.input.flags)
392
- .map(f => `--${f}`)
393
- .join(' '));
394
344
  }
395
- get _argTokens() {
396
- return this.raw.filter(o => o.type === 'arg');
397
- }
398
- _setNames() {
399
- for (const k of Object.keys(this.input.flags)) {
400
- this.input.flags[k].name = k;
401
- }
402
- for (const k of Object.keys(this.input.args)) {
403
- this.input.args[k].name = k;
345
+ findShortFlag([_, char]) {
346
+ if (this.flagAliases[char]) {
347
+ return this.flagAliases[char].name;
404
348
  }
349
+ return Object.keys(this.input.flags).find((k) => this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined);
405
350
  }
406
351
  mapAndValidateFlags() {
407
352
  const flagTokenMap = new Map();
408
- for (const token of this.raw.filter(o => o.type === 'flag')) {
353
+ for (const token of this.raw.filter((o) => o.type === 'flag')) {
409
354
  // fail fast if there are any invalid flags
410
355
  if (!(token.flag in this.input.flags)) {
411
356
  throw new errors_1.CLIError(`Unexpected flag ${token.flag}`);
@@ -415,5 +360,92 @@ class Parser {
415
360
  }
416
361
  return flagTokenMap;
417
362
  }
363
+ async parse() {
364
+ this._debugInput();
365
+ const parseFlag = (arg) => {
366
+ const { isLong, name } = this.findFlag(arg);
367
+ if (!name) {
368
+ const i = arg.indexOf('=');
369
+ if (i !== -1) {
370
+ const sliced = arg.slice(i + 1);
371
+ this.argv.unshift(sliced);
372
+ const equalsParsed = parseFlag(arg.slice(0, i));
373
+ if (!equalsParsed) {
374
+ this.argv.shift();
375
+ }
376
+ return equalsParsed;
377
+ }
378
+ return false;
379
+ }
380
+ const flag = this.input.flags[name];
381
+ if (flag.type === 'option') {
382
+ if (!flag.multiple && this.raw.some((o) => o.type === 'flag' && o.flag === name)) {
383
+ throw new errors_1.CLIError(`Flag --${name} can only be specified once`);
384
+ }
385
+ this.currentFlag = flag;
386
+ const input = isLong || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
387
+ // if the value ends up being one of the command's flags, the user didn't provide an input
388
+ if (typeof input !== 'string' || this.findFlag(input).name) {
389
+ throw new errors_1.CLIError(`Flag --${name} expects a value`);
390
+ }
391
+ this.raw.push({ flag: flag.name, input, type: 'flag' });
392
+ }
393
+ else {
394
+ this.raw.push({ flag: flag.name, input: arg, type: 'flag' });
395
+ // push the rest of the short characters back on the stack
396
+ if (!isLong && arg.length > 2) {
397
+ this.argv.unshift(`-${arg.slice(2)}`);
398
+ }
399
+ }
400
+ return true;
401
+ };
402
+ let parsingFlags = true;
403
+ const nonExistentFlags = [];
404
+ let dashdash = false;
405
+ const originalArgv = [...this.argv];
406
+ while (this.argv.length > 0) {
407
+ const input = this.argv.shift();
408
+ if (parsingFlags && input.startsWith('-') && input !== '-') {
409
+ // attempt to parse as arg
410
+ if (this.input['--'] !== false && input === '--') {
411
+ parsingFlags = false;
412
+ continue;
413
+ }
414
+ if (parseFlag(input)) {
415
+ continue;
416
+ }
417
+ if (input === '--') {
418
+ dashdash = true;
419
+ continue;
420
+ }
421
+ if (this.input['--'] !== false && !isNegativeNumber(input)) {
422
+ // At this point we have a value that begins with '-' or '--'
423
+ // but doesn't match up to a flag definition. So we assume that
424
+ // this is a misspelled flag or a non-existent flag,
425
+ // e.g. --hekp instead of --help
426
+ nonExistentFlags.push(input);
427
+ continue;
428
+ }
429
+ }
430
+ if (parsingFlags && this.currentFlag && this.currentFlag.multiple) {
431
+ this.raw.push({ flag: this.currentFlag.name, input, type: 'flag' });
432
+ continue;
433
+ }
434
+ // not a flag, parse as arg
435
+ const arg = Object.keys(this.input.args)[this._argTokens.length];
436
+ this.raw.push({ arg, input, type: 'arg' });
437
+ }
438
+ const [{ args, argv }, { flags, metadata }] = await Promise.all([this._args(), this._flags()]);
439
+ this._debugOutput(argv, args, flags);
440
+ const unsortedArgv = (dashdash ? [...argv, ...nonExistentFlags, '--'] : [...argv, ...nonExistentFlags]);
441
+ return {
442
+ args: args,
443
+ argv: unsortedArgv.sort((a, b) => originalArgv.indexOf(a) - originalArgv.indexOf(b)),
444
+ flags,
445
+ metadata,
446
+ nonExistentFlags,
447
+ raw: this.raw,
448
+ };
449
+ }
418
450
  }
419
451
  exports.Parser = Parser;