@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.
- package/README.md +4 -2
- package/flush.d.ts +3 -0
- package/flush.js +1 -0
- package/handle.js +1 -0
- package/lib/args.d.ts +2 -2
- package/lib/args.js +17 -18
- package/lib/{ux → cli-ux}/action/base.d.ts +19 -21
- package/lib/{ux → cli-ux}/action/base.js +126 -120
- package/lib/{ux → cli-ux}/action/simple.js +25 -30
- package/lib/{ux → cli-ux}/action/spinner.d.ts +9 -7
- package/lib/{ux → cli-ux}/action/spinner.js +45 -37
- package/lib/{ux → cli-ux}/action/spinners.js +187 -187
- package/lib/cli-ux/action/types.d.ts +5 -0
- package/lib/cli-ux/action/types.js +2 -0
- package/lib/{ux → cli-ux}/config.d.ts +5 -5
- package/lib/{ux → cli-ux}/config.js +17 -17
- package/lib/{ux → cli-ux}/exit.js +3 -0
- package/lib/cli-ux/flush.d.ts +1 -0
- package/lib/cli-ux/flush.js +28 -0
- package/lib/cli-ux/index.d.ts +39 -0
- package/lib/{ux → cli-ux}/index.js +74 -97
- package/lib/{ux → cli-ux}/list.js +3 -3
- package/lib/{ux → cli-ux}/prompt.d.ts +3 -3
- package/lib/{ux → cli-ux}/prompt.js +35 -25
- package/lib/{ux → cli-ux}/stream.d.ts +6 -6
- package/lib/{ux → cli-ux}/stream.js +11 -10
- package/lib/cli-ux/styled/index.d.ts +4 -0
- package/lib/cli-ux/styled/index.js +11 -0
- package/lib/{ux → cli-ux}/styled/object.js +7 -9
- package/lib/{ux → cli-ux}/styled/table.d.ts +10 -10
- package/lib/{ux → cli-ux}/styled/table.js +130 -133
- package/lib/{ux → cli-ux}/styled/tree.js +11 -13
- package/lib/cli-ux/wait.js +5 -0
- package/lib/command.d.ts +82 -88
- package/lib/command.js +196 -175
- package/lib/config/config.d.ts +89 -90
- package/lib/config/config.js +466 -566
- package/lib/config/index.d.ts +0 -1
- package/lib/config/index.js +1 -3
- package/lib/config/plugin-loader.d.ts +12 -12
- package/lib/config/plugin-loader.js +72 -56
- package/lib/config/plugin.d.ts +25 -24
- package/lib/config/plugin.js +188 -154
- package/lib/config/ts-node.d.ts +2 -1
- package/lib/config/ts-node.js +71 -58
- package/lib/config/util.d.ts +1 -11
- package/lib/config/util.js +6 -59
- package/lib/errors/config.d.ts +1 -1
- package/lib/errors/config.js +6 -6
- package/lib/errors/errors/cli.d.ts +7 -7
- package/lib/errors/errors/cli.js +20 -16
- package/lib/errors/errors/exit.d.ts +1 -4
- package/lib/errors/errors/exit.js +1 -1
- package/lib/errors/errors/module-load.d.ts +1 -4
- package/lib/errors/errors/module-load.js +1 -1
- package/lib/errors/errors/pretty-print.d.ts +1 -1
- package/lib/errors/errors/pretty-print.js +12 -10
- package/lib/errors/handle.d.ts +12 -2
- package/lib/errors/handle.js +26 -14
- package/lib/errors/index.d.ts +10 -10
- package/lib/errors/index.js +25 -24
- package/lib/errors/logger.d.ts +2 -2
- package/lib/errors/logger.js +14 -13
- package/lib/execute.d.ts +6 -6
- package/lib/execute.js +10 -9
- package/lib/flags.d.ts +103 -32
- package/lib/flags.js +79 -45
- package/lib/help/command.d.ts +16 -14
- package/lib/help/command.js +178 -163
- package/lib/help/docopts.d.ts +5 -5
- package/lib/help/docopts.js +50 -54
- package/lib/help/formatter.d.ts +37 -37
- package/lib/help/formatter.js +66 -55
- package/lib/help/index.d.ts +25 -21
- package/lib/help/index.js +169 -147
- package/lib/help/root.d.ts +1 -1
- package/lib/help/root.js +15 -17
- package/lib/help/util.d.ts +2 -8
- package/lib/help/util.js +8 -28
- package/lib/index.d.ts +19 -20
- package/lib/index.js +37 -43
- package/lib/interfaces/config.d.ts +67 -66
- package/lib/interfaces/errors.d.ts +5 -5
- package/lib/interfaces/help.d.ts +17 -17
- package/lib/interfaces/hooks.d.ts +49 -49
- package/lib/interfaces/index.d.ts +7 -7
- package/lib/interfaces/manifest.d.ts +1 -1
- package/lib/interfaces/parser.d.ts +175 -51
- package/lib/interfaces/pjson.d.ts +41 -41
- package/lib/interfaces/plugin.d.ts +47 -41
- package/lib/interfaces/s3-manifest.d.ts +7 -7
- package/lib/interfaces/topic.d.ts +1 -1
- package/lib/interfaces/ts-config.d.ts +7 -7
- package/lib/main.d.ts +2 -2
- package/lib/main.js +16 -16
- package/lib/module-loader.d.ts +67 -77
- package/lib/module-loader.js +183 -150
- package/lib/parser/errors.d.ts +7 -7
- package/lib/parser/errors.js +29 -22
- package/lib/parser/help.js +5 -5
- package/lib/parser/index.js +2 -2
- package/lib/parser/parse.d.ts +9 -6
- package/lib/parser/parse.js +253 -221
- package/lib/parser/validate.js +53 -33
- package/lib/performance.d.ts +43 -32
- package/lib/performance.js +133 -91
- package/lib/screen.js +2 -2
- package/lib/settings.d.ts +11 -12
- package/lib/settings.js +2 -2
- package/lib/util/aggregate-flags.d.ts +2 -0
- package/lib/util/aggregate-flags.js +13 -0
- package/lib/util/cache-command.d.ts +3 -0
- package/lib/util/cache-command.js +109 -0
- package/lib/util/cache-default-value.d.ts +2 -0
- package/lib/util/cache-default-value.js +28 -0
- package/lib/util/ensure-arg-object.d.ts +12 -0
- package/lib/util/ensure-arg-object.js +14 -0
- package/lib/util/fs.d.ts +7 -0
- package/lib/util/fs.js +54 -0
- package/lib/util/os.d.ts +19 -0
- package/lib/util/os.js +28 -0
- package/lib/{util.d.ts → util/util.d.ts} +7 -16
- package/lib/util/util.js +98 -0
- package/package.json +35 -37
- package/lib/util.js +0 -126
- package/lib/ux/flush.d.ts +0 -1
- package/lib/ux/flush.js +0 -27
- package/lib/ux/index.d.ts +0 -64
- package/lib/ux/styled/index.d.ts +0 -6
- package/lib/ux/styled/index.js +0 -13
- package/lib/ux/styled/json.d.ts +0 -1
- package/lib/ux/styled/json.js +0 -15
- package/lib/ux/wait.js +0 -7
- package/lib/{ux → cli-ux}/action/simple.d.ts +4 -4
- package/lib/{ux → cli-ux}/action/spinners.d.ts +117 -117
- package/lib/{ux → cli-ux}/exit.d.ts +2 -2
- package/lib/{ux → cli-ux}/list.d.ts +0 -0
- package/lib/{ux → cli-ux}/styled/object.d.ts +0 -0
- package/lib/{ux → cli-ux}/styled/progress.d.ts +0 -0
- package/lib/{ux → cli-ux}/styled/progress.js +0 -0
- package/lib/{ux → cli-ux}/styled/tree.d.ts +1 -1
- /package/lib/{ux → cli-ux}/wait.d.ts +0 -0
package/lib/parser/parse.js
CHANGED
|
@@ -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
|
-
|
|
11
|
-
|
|
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
|
|
34
|
+
const { signal } = ac;
|
|
29
35
|
const timeout = setTimeout(() => ac.abort(), 100);
|
|
30
|
-
const rl =
|
|
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
|
-
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
97
|
+
const parsed = await arg.parse(token.input, ctx, arg);
|
|
98
|
+
argv.push(parsed);
|
|
99
|
+
args[token.arg] = parsed;
|
|
118
100
|
}
|
|
119
|
-
else {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
157
|
-
|
|
122
|
+
}
|
|
123
|
+
for (const token of tokens) {
|
|
124
|
+
if (args[token.arg])
|
|
158
125
|
continue;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
225
|
-
.
|
|
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) =>
|
|
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,
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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,
|
|
275
|
-
|
|
276
|
-
(i, 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
|
-
|
|
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' ||
|
|
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: {
|
|
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
|
-
|
|
319
|
-
|
|
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: {
|
|
312
|
+
metadata: {
|
|
313
|
+
flags: Object.fromEntries(finalFlags.filter((fws) => fws.metadata).map((fws) => [fws.inputFlag.name, fws.metadata])),
|
|
314
|
+
},
|
|
324
315
|
};
|
|
325
316
|
}
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
|
|
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
|
|
366
|
-
|
|
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
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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 (
|
|
380
|
-
|
|
336
|
+
if (this.flagAliases[name]) {
|
|
337
|
+
return this.flagAliases[name].name;
|
|
381
338
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
396
|
-
|
|
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;
|