@oclif/core 2.8.11 → 2.9.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/lib/cli-ux/styled/table.js +7 -1
- package/lib/interfaces/parser.d.ts +1 -2
- package/lib/parser/parse.d.ts +1 -4
- package/lib/parser/parse.js +123 -105
- package/lib/parser/validate.js +26 -33
- package/package.json +8 -2
|
@@ -10,6 +10,7 @@ const util_2 = require("util");
|
|
|
10
10
|
const stream_1 = require("../stream");
|
|
11
11
|
const sw = require('string-width');
|
|
12
12
|
const { orderBy } = require('natural-orderby');
|
|
13
|
+
const sliceAnsi = require('slice-ansi');
|
|
13
14
|
class Table {
|
|
14
15
|
constructor(data, columns, options = {}) {
|
|
15
16
|
this.data = data;
|
|
@@ -258,7 +259,12 @@ class Table {
|
|
|
258
259
|
const colorWidth = (d.length - visualWidth);
|
|
259
260
|
let cell = d.padEnd(width + colorWidth);
|
|
260
261
|
if ((cell.length - colorWidth) > width || visualWidth === width) {
|
|
261
|
-
|
|
262
|
+
// truncate the cell, preserving ANSI escape sequences, and keeping
|
|
263
|
+
// into account the width of fullwidth unicode characters
|
|
264
|
+
cell = sliceAnsi(cell, 0, width - 2) + '… ';
|
|
265
|
+
// pad with spaces; this is necessary in case the original string
|
|
266
|
+
// contained fullwidth characters which cannot be split
|
|
267
|
+
cell += ' '.repeat(width - sw(cell));
|
|
262
268
|
}
|
|
263
269
|
l += cell;
|
|
264
270
|
}
|
|
@@ -48,7 +48,7 @@ export type Metadata = {
|
|
|
48
48
|
[key: string]: MetadataFlag;
|
|
49
49
|
};
|
|
50
50
|
};
|
|
51
|
-
type MetadataFlag = {
|
|
51
|
+
export type MetadataFlag = {
|
|
52
52
|
setFromDefault?: boolean;
|
|
53
53
|
defaultHelp?: unknown;
|
|
54
54
|
};
|
|
@@ -368,4 +368,3 @@ export type ArgInput<T extends ArgOutput = {
|
|
|
368
368
|
}> = {
|
|
369
369
|
[P in keyof T]: Arg<T[P]>;
|
|
370
370
|
};
|
|
371
|
-
export {};
|
package/lib/parser/parse.d.ts
CHANGED
|
@@ -6,17 +6,14 @@ export declare class Parser<T extends ParserInput, TFlags extends OutputFlags<T[
|
|
|
6
6
|
private readonly booleanFlags;
|
|
7
7
|
private readonly flagAliases;
|
|
8
8
|
private readonly context;
|
|
9
|
-
private readonly metaData;
|
|
10
9
|
private currentFlag?;
|
|
11
10
|
constructor(input: T);
|
|
12
11
|
parse(): Promise<ParserOutput<TFlags, BFlags, TArgs>>;
|
|
13
12
|
private _flags;
|
|
14
|
-
private _parseFlag;
|
|
15
|
-
private _validateOptions;
|
|
16
13
|
private _args;
|
|
17
14
|
private _debugOutput;
|
|
18
15
|
private _debugInput;
|
|
19
16
|
private get _argTokens();
|
|
20
|
-
private get _flagTokens();
|
|
21
17
|
private _setNames;
|
|
18
|
+
private mapAndValidateFlags;
|
|
22
19
|
}
|
package/lib/parser/parse.js
CHANGED
|
@@ -63,7 +63,6 @@ class Parser {
|
|
|
63
63
|
this.flagAliases = Object.fromEntries(Object.values(input.flags).flatMap(flag => {
|
|
64
64
|
return (flag.aliases ?? []).map(a => [a, flag]);
|
|
65
65
|
}));
|
|
66
|
-
this.metaData = {};
|
|
67
66
|
}
|
|
68
67
|
async parse() {
|
|
69
68
|
this._debugInput();
|
|
@@ -85,11 +84,16 @@ class Parser {
|
|
|
85
84
|
if (this.flagAliases[char]) {
|
|
86
85
|
return this.flagAliases[char].name;
|
|
87
86
|
}
|
|
88
|
-
return Object.keys(this.input.flags).find(k => this.input.flags[k].char === char);
|
|
87
|
+
return Object.keys(this.input.flags).find(k => (this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined));
|
|
88
|
+
};
|
|
89
|
+
const findFlag = (arg) => {
|
|
90
|
+
const isLong = arg.startsWith('--');
|
|
91
|
+
const short = isLong ? false : arg.startsWith('-');
|
|
92
|
+
const name = isLong ? findLongFlag(arg) : (short ? findShortFlag(arg) : undefined);
|
|
93
|
+
return { name, isLong };
|
|
89
94
|
};
|
|
90
95
|
const parseFlag = (arg) => {
|
|
91
|
-
const
|
|
92
|
-
const name = long ? findLongFlag(arg) : findShortFlag(arg);
|
|
96
|
+
const { name, isLong } = findFlag(arg);
|
|
93
97
|
if (!name) {
|
|
94
98
|
const i = arg.indexOf('=');
|
|
95
99
|
if (i !== -1) {
|
|
@@ -106,16 +110,17 @@ class Parser {
|
|
|
106
110
|
const flag = this.input.flags[name];
|
|
107
111
|
if (flag.type === 'option') {
|
|
108
112
|
this.currentFlag = flag;
|
|
109
|
-
const input =
|
|
110
|
-
if
|
|
113
|
+
const input = isLong || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
|
|
114
|
+
// if the value ends up being one of the command's flags, the user didn't provide an input
|
|
115
|
+
if ((typeof input !== 'string') || findFlag(input).name) {
|
|
111
116
|
throw new errors_1.CLIError(`Flag --${name} expects a value`);
|
|
112
117
|
}
|
|
113
|
-
this.raw.push({ type: 'flag', flag: flag.name, input });
|
|
118
|
+
this.raw.push({ type: 'flag', flag: flag.name, input: input });
|
|
114
119
|
}
|
|
115
120
|
else {
|
|
116
121
|
this.raw.push({ type: 'flag', flag: flag.name, input: arg });
|
|
117
122
|
// push the rest of the short characters back on the stack
|
|
118
|
-
if (!
|
|
123
|
+
if (!isLong && arg.length > 2) {
|
|
119
124
|
this.argv.unshift(`-${arg.slice(2)}`);
|
|
120
125
|
}
|
|
121
126
|
}
|
|
@@ -157,8 +162,7 @@ class Parser {
|
|
|
157
162
|
const arg = Object.keys(this.input.args)[this._argTokens.length];
|
|
158
163
|
this.raw.push({ type: 'arg', arg, input });
|
|
159
164
|
}
|
|
160
|
-
const { argv, args } = await this._args();
|
|
161
|
-
const flags = await this._flags();
|
|
165
|
+
const [{ argv, args }, { flags, metadata }] = await Promise.all([this._args(), this._flags()]);
|
|
162
166
|
this._debugOutput(argv, args, flags);
|
|
163
167
|
const unsortedArgv = (dashdash ? [...argv, ...nonExistentFlags, '--'] : [...argv, ...nonExistentFlags]);
|
|
164
168
|
return {
|
|
@@ -166,113 +170,118 @@ class Parser {
|
|
|
166
170
|
flags,
|
|
167
171
|
args: args,
|
|
168
172
|
raw: this.raw,
|
|
169
|
-
metadata
|
|
173
|
+
metadata,
|
|
170
174
|
nonExistentFlags,
|
|
171
175
|
};
|
|
172
176
|
}
|
|
173
|
-
// eslint-disable-next-line complexity
|
|
174
177
|
async _flags() {
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (flag.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
flags[token.flag] = true;
|
|
178
|
+
const validateOptions = (flag, input) => {
|
|
179
|
+
if (flag.options && !flag.options.includes(input))
|
|
180
|
+
throw new errors_1.FlagInvalidOptionError(flag, input);
|
|
181
|
+
return input;
|
|
182
|
+
};
|
|
183
|
+
const parseFlagOrThrowError = async (input, flag, token, context = {}) => {
|
|
184
|
+
if (!flag.parse)
|
|
185
|
+
return input;
|
|
186
|
+
try {
|
|
187
|
+
if (flag.type === 'boolean') {
|
|
188
|
+
return await flag.parse(input, { ...context, token }, flag);
|
|
187
189
|
}
|
|
188
|
-
|
|
190
|
+
return await flag.parse(input, { ...context, token }, flag);
|
|
189
191
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
192
|
+
catch (error) {
|
|
193
|
+
error.message = `Parsing --${flag.name} \n\t${error.message}\nSee more help with --help`;
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
/* Could add a valueFunction (if there is a value/env/default) and could metadata.
|
|
198
|
+
* Value function can be resolved later.
|
|
199
|
+
*/
|
|
200
|
+
const addValueFunction = (fws) => {
|
|
201
|
+
const tokenLength = fws.tokens?.length;
|
|
202
|
+
// user provided some input
|
|
203
|
+
if (tokenLength) {
|
|
204
|
+
// boolean
|
|
205
|
+
if (fws.inputFlag.flag.type === 'boolean' && fws.tokens?.at(-1)?.input) {
|
|
206
|
+
return { ...fws, valueFunction: async (i) => parseFlagOrThrowError(i.tokens?.at(-1)?.input !== `--no-${i.inputFlag.name}`, i.inputFlag.flag, i.tokens?.at(-1), this.context) };
|
|
201
207
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
flags[token.flag] = value;
|
|
211
|
-
}
|
|
208
|
+
// multiple with custom delimiter
|
|
209
|
+
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.delimiter && fws.inputFlag.flag.multiple) {
|
|
210
|
+
return {
|
|
211
|
+
...fws, valueFunction: async (i) => (await Promise.all(((i.tokens ?? []).flatMap(token => token.input.split(i.inputFlag.flag.delimiter)))
|
|
212
|
+
// trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
|
|
213
|
+
.map(v => v.trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'))
|
|
214
|
+
.map(async (v) => parseFlagOrThrowError(v, i.inputFlag.flag, { ...i.tokens?.at(-1), input: v }, this.context)))).map(v => validateOptions(i.inputFlag.flag, v)),
|
|
215
|
+
};
|
|
212
216
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const flag = this.input.flags[k];
|
|
217
|
-
if (flags[k])
|
|
218
|
-
continue;
|
|
219
|
-
if (flag.env && Reflect.has(process.env, flag.env)) {
|
|
220
|
-
const input = process.env[flag.env];
|
|
221
|
-
if (flag.type === 'option') {
|
|
222
|
-
if (input) {
|
|
223
|
-
this._validateOptions(flag, input);
|
|
224
|
-
flags[k] = await this._parseFlag(input, flag);
|
|
225
|
-
}
|
|
217
|
+
// multiple in the oclif-core style
|
|
218
|
+
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.multiple) {
|
|
219
|
+
return { ...fws, valueFunction: async (i) => Promise.all((fws.tokens ?? []).map(token => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, token.input), i.inputFlag.flag, token, this.context))) };
|
|
226
220
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
221
|
+
// simple option flag
|
|
222
|
+
if (fws.inputFlag.flag.type === 'option') {
|
|
223
|
+
return { ...fws, valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, fws.tokens?.at(-1)?.input), i.inputFlag.flag, fws.tokens?.at(-1), this.context) };
|
|
230
224
|
}
|
|
231
225
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
for (const k of Object.keys(this.input.flags)) {
|
|
239
|
-
if ((k in flags) && Reflect.has(this.input.flags[k], 'defaultHelp')) {
|
|
240
|
-
try {
|
|
241
|
-
const defaultHelpProperty = Reflect.get(this.input.flags[k], 'defaultHelp');
|
|
242
|
-
const defaultHelp = (typeof defaultHelpProperty === 'function' ? await defaultHelpProperty({
|
|
243
|
-
options: flags[k],
|
|
244
|
-
flags, ...this.context,
|
|
245
|
-
}) : defaultHelpProperty);
|
|
246
|
-
this.metaData.flags[k] = { ...this.metaData.flags[k], defaultHelp };
|
|
226
|
+
// no input: env flags
|
|
227
|
+
if (fws.inputFlag.flag.env && process.env[fws.inputFlag.flag.env]) {
|
|
228
|
+
const valueFromEnv = process.env[fws.inputFlag.flag.env];
|
|
229
|
+
if (fws.inputFlag.flag.type === 'option' && valueFromEnv) {
|
|
230
|
+
return { ...fws, valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, valueFromEnv), i.inputFlag.flag, this.context) };
|
|
247
231
|
}
|
|
248
|
-
|
|
249
|
-
|
|
232
|
+
if (fws.inputFlag.flag.type === 'boolean') {
|
|
233
|
+
return { ...fws, valueFunction: async (i) => Promise.resolve((0, util_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false')) };
|
|
250
234
|
}
|
|
251
235
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
ctx.token = token;
|
|
261
|
-
if (flag.type === 'boolean') {
|
|
262
|
-
const ctx = this.context;
|
|
263
|
-
ctx.token = token;
|
|
264
|
-
return await flag.parse(input, ctx, flag);
|
|
236
|
+
// no input, but flag has default value
|
|
237
|
+
if (typeof fws.inputFlag.flag.default !== undefined) {
|
|
238
|
+
return {
|
|
239
|
+
...fws, metadata: { setFromDefault: true },
|
|
240
|
+
valueFunction: typeof fws.inputFlag.flag.default === 'function' ?
|
|
241
|
+
(i, allFlags = {}) => fws.inputFlag.flag.default({ options: i.inputFlag.flag, flags: allFlags }) :
|
|
242
|
+
async () => fws.inputFlag.flag.default,
|
|
243
|
+
};
|
|
265
244
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
245
|
+
// base case (no value function)
|
|
246
|
+
return fws;
|
|
247
|
+
};
|
|
248
|
+
const addHelpFunction = (fws) => {
|
|
249
|
+
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.defaultHelp) {
|
|
250
|
+
return {
|
|
251
|
+
...fws, helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function' ?
|
|
252
|
+
// @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
|
|
253
|
+
(i, flags, ...context) => i.inputFlag.flag.defaultHelp({ options: i.inputFlag, flags }, ...context) :
|
|
254
|
+
// @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
|
|
255
|
+
(i) => i.inputFlag.flag.defaultHelp,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return fws;
|
|
259
|
+
};
|
|
260
|
+
const addDefaultHelp = async (fws) => {
|
|
261
|
+
const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter(fws => !fws.metadata?.setFromDefault));
|
|
262
|
+
return Promise.all(fws.map(async (fws) => fws.helpFunction ? ({ ...fws, metadata: { ...fws.metadata, defaultHelp: await fws.helpFunction?.(fws, valueReferenceForHelp, this.context) } }) : fws));
|
|
263
|
+
};
|
|
264
|
+
const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.map(fws => [fws.inputFlag.name, fws.value]));
|
|
265
|
+
const flagTokenMap = this.mapAndValidateFlags();
|
|
266
|
+
const flagsWithValues = await Promise.all(Object.entries(this.input.flags)
|
|
267
|
+
// we check them if they have a token, or might have env, default, or defaultHelp. Also include booleans so they get their default value
|
|
268
|
+
.filter(([name, flag]) => flag.type === 'boolean' || flag.env || flag.default || 'defaultHelp' in flag || flagTokenMap.has(name))
|
|
269
|
+
// match each possible flag to its token, if there is one
|
|
270
|
+
.map(([name, flag]) => ({ inputFlag: { name, flag }, tokens: flagTokenMap.get(name) }))
|
|
271
|
+
.map(fws => addValueFunction(fws))
|
|
272
|
+
.filter(fws => fws.valueFunction !== undefined)
|
|
273
|
+
.map(fws => addHelpFunction(fws))
|
|
274
|
+
// we can't apply the default values until all the other flags are resolved because `flag.default` can reference other flags
|
|
275
|
+
.map(async (fws) => (fws.metadata?.setFromDefault ? fws : { ...fws, value: await fws.valueFunction?.(fws) })));
|
|
276
|
+
const valueReference = fwsArrayToObject(flagsWithValues.filter(fws => !fws.metadata?.setFromDefault));
|
|
277
|
+
const flagsWithAllValues = await Promise.all(flagsWithValues
|
|
278
|
+
.map(async (fws) => (fws.metadata?.setFromDefault ? { ...fws, value: await fws.valueFunction?.(fws, valueReference) } : fws)));
|
|
279
|
+
const finalFlags = (flagsWithAllValues.some(fws => typeof fws.helpFunction === 'function')) ? await addDefaultHelp(flagsWithAllValues) : flagsWithAllValues;
|
|
280
|
+
return {
|
|
281
|
+
// @ts-ignore original version returned an any. Not sure how to get to the return type for `flags` prop
|
|
282
|
+
flags: fwsArrayToObject(finalFlags),
|
|
283
|
+
metadata: { flags: Object.fromEntries(finalFlags.filter(fws => fws.metadata).map(fws => [fws.inputFlag.name, fws.metadata])) },
|
|
284
|
+
};
|
|
276
285
|
}
|
|
277
286
|
async _args() {
|
|
278
287
|
const argv = [];
|
|
@@ -346,9 +355,6 @@ class Parser {
|
|
|
346
355
|
get _argTokens() {
|
|
347
356
|
return this.raw.filter(o => o.type === 'arg');
|
|
348
357
|
}
|
|
349
|
-
get _flagTokens() {
|
|
350
|
-
return this.raw.filter(o => o.type === 'flag');
|
|
351
|
-
}
|
|
352
358
|
_setNames() {
|
|
353
359
|
for (const k of Object.keys(this.input.flags)) {
|
|
354
360
|
this.input.flags[k].name = k;
|
|
@@ -357,5 +363,17 @@ class Parser {
|
|
|
357
363
|
this.input.args[k].name = k;
|
|
358
364
|
}
|
|
359
365
|
}
|
|
366
|
+
mapAndValidateFlags() {
|
|
367
|
+
const flagTokenMap = new Map();
|
|
368
|
+
for (const token of this.raw.filter(o => o.type === 'flag')) {
|
|
369
|
+
// fail fast if there are any invalid flags
|
|
370
|
+
if (!(token.flag in this.input.flags)) {
|
|
371
|
+
throw new errors_1.CLIError(`Unexpected flag ${token.flag}`);
|
|
372
|
+
}
|
|
373
|
+
const existing = flagTokenMap.get(token.flag) ?? [];
|
|
374
|
+
flagTokenMap.set(token.flag, [...existing, token]);
|
|
375
|
+
}
|
|
376
|
+
return flagTokenMap;
|
|
377
|
+
}
|
|
360
378
|
}
|
|
361
379
|
exports.Parser = Parser;
|
package/lib/parser/validate.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.validate = void 0;
|
|
|
4
4
|
const errors_1 = require("./errors");
|
|
5
5
|
const util_1 = require("../config/util");
|
|
6
6
|
async function validate(parse) {
|
|
7
|
+
let cachedResolvedFlags;
|
|
7
8
|
function validateArgs() {
|
|
8
9
|
if (parse.output.nonExistentFlags?.length > 0) {
|
|
9
10
|
throw new errors_1.NonExistentFlagsError({ parse, flags: parse.output.nonExistentFlags });
|
|
@@ -33,25 +34,31 @@ async function validate(parse) {
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
async function validateFlags() {
|
|
36
|
-
const promises = Object.entries(parse.input.flags).
|
|
37
|
-
const results = [];
|
|
37
|
+
const promises = Object.entries(parse.input.flags).flatMap(([name, flag]) => {
|
|
38
38
|
if (parse.output.flags[name] !== undefined) {
|
|
39
|
-
|
|
39
|
+
return [
|
|
40
|
+
...flag.relationships ? validateRelationships(name, flag) : [],
|
|
41
|
+
...flag.dependsOn ? [validateDependsOn(name, flag.dependsOn)] : [],
|
|
42
|
+
...flag.exclusive ? [validateExclusive(name, flag.exclusive)] : [],
|
|
43
|
+
...flag.exactlyOne ? [validateExactlyOne(name, flag.exactlyOne)] : [],
|
|
44
|
+
];
|
|
40
45
|
}
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
if (flag.required) {
|
|
47
|
+
return [{ status: 'failed', name, validationFn: 'required', reason: `Missing required flag ${name}` }];
|
|
43
48
|
}
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
if (flag.exactlyOne && flag.exactlyOne.length > 0) {
|
|
50
|
+
return [validateAcrossFlags(flag)];
|
|
46
51
|
}
|
|
47
|
-
return
|
|
52
|
+
return [];
|
|
48
53
|
});
|
|
49
|
-
const results = (await Promise.all(promises))
|
|
54
|
+
const results = (await Promise.all(promises));
|
|
50
55
|
const failed = results.filter(r => r.status === 'failed');
|
|
51
56
|
if (failed.length > 0)
|
|
52
57
|
throw new errors_1.FailedFlagValidationError({ parse, failed });
|
|
53
58
|
}
|
|
54
59
|
async function resolveFlags(flags) {
|
|
60
|
+
if (cachedResolvedFlags)
|
|
61
|
+
return cachedResolvedFlags;
|
|
55
62
|
const promises = flags.map(async (flag) => {
|
|
56
63
|
if (typeof flag === 'string') {
|
|
57
64
|
return [flag, parse.output.flags[flag]];
|
|
@@ -60,15 +67,10 @@ async function validate(parse) {
|
|
|
60
67
|
return result ? [flag.name, parse.output.flags[flag.name]] : null;
|
|
61
68
|
});
|
|
62
69
|
const resolved = await Promise.all(promises);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
function getPresentFlags(flags) {
|
|
66
|
-
return Object.keys(flags).reduce((acc, key) => {
|
|
67
|
-
if (flags[key] !== undefined)
|
|
68
|
-
acc.push(key);
|
|
69
|
-
return acc;
|
|
70
|
-
}, []);
|
|
70
|
+
cachedResolvedFlags = Object.fromEntries(resolved.filter(r => r !== null));
|
|
71
|
+
return cachedResolvedFlags;
|
|
71
72
|
}
|
|
73
|
+
const getPresentFlags = (flags) => Object.keys(flags).filter(key => key !== undefined);
|
|
72
74
|
function validateAcrossFlags(flag) {
|
|
73
75
|
const base = { name: flag.name, validationFn: 'validateAcrossFlags' };
|
|
74
76
|
const intersection = Object.entries(parse.input.flags)
|
|
@@ -131,30 +133,21 @@ async function validate(parse) {
|
|
|
131
133
|
}
|
|
132
134
|
return { ...base, status: 'success' };
|
|
133
135
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return [];
|
|
137
|
-
const results = await Promise.all(flag.relationships.map(async (relationship) => {
|
|
138
|
-
const flags = relationship.flags ?? [];
|
|
139
|
-
const results = [];
|
|
136
|
+
function validateRelationships(name, flag) {
|
|
137
|
+
return ((flag.relationships ?? []).map(relationship => {
|
|
140
138
|
switch (relationship.type) {
|
|
141
139
|
case 'all':
|
|
142
|
-
|
|
143
|
-
break;
|
|
140
|
+
return validateDependsOn(name, relationship.flags);
|
|
144
141
|
case 'some':
|
|
145
|
-
|
|
146
|
-
break;
|
|
142
|
+
return validateSome(name, relationship.flags);
|
|
147
143
|
case 'none':
|
|
148
|
-
|
|
149
|
-
break;
|
|
144
|
+
return validateExclusive(name, relationship.flags);
|
|
150
145
|
default:
|
|
151
|
-
|
|
146
|
+
throw new Error(`Unknown relationship type: ${relationship.type}`);
|
|
152
147
|
}
|
|
153
|
-
return results;
|
|
154
148
|
}));
|
|
155
|
-
return results.flat();
|
|
156
149
|
}
|
|
157
150
|
validateArgs();
|
|
158
|
-
|
|
151
|
+
return validateFlags();
|
|
159
152
|
}
|
|
160
153
|
exports.validate = validate;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oclif/core",
|
|
3
3
|
"description": "base library for oclif CLIs",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.9.0",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"bugs": "https://github.com/oclif/core/issues",
|
|
7
7
|
"dependencies": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"object-treeify": "^1.1.33",
|
|
26
26
|
"password-prompt": "^1.1.2",
|
|
27
27
|
"semver": "^7.5.3",
|
|
28
|
+
"slice-ansi": "^4.0.0",
|
|
28
29
|
"string-width": "^4.2.3",
|
|
29
30
|
"strip-ansi": "^6.0.1",
|
|
30
31
|
"supports-color": "^8.1.1",
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
"@oclif/plugin-plugins": "^2.4.7",
|
|
42
43
|
"@oclif/test": "^2.3.15",
|
|
43
44
|
"@types/ansi-styles": "^3.2.1",
|
|
45
|
+
"@types/benchmark": "^2.1.2",
|
|
44
46
|
"@types/chai": "^4.3.4",
|
|
45
47
|
"@types/chai-as-promised": "^7.1.5",
|
|
46
48
|
"@types/clean-stack": "^2.1.1",
|
|
@@ -55,10 +57,12 @@
|
|
|
55
57
|
"@types/proxyquire": "^1.3.28",
|
|
56
58
|
"@types/semver": "^7.5.0",
|
|
57
59
|
"@types/shelljs": "^0.8.11",
|
|
60
|
+
"@types/slice-ansi": "^4.0.0",
|
|
58
61
|
"@types/strip-ansi": "^5.2.1",
|
|
59
62
|
"@types/supports-color": "^8.1.1",
|
|
60
63
|
"@types/wordwrap": "^1.0.1",
|
|
61
64
|
"@types/wrap-ansi": "^3.0.0",
|
|
65
|
+
"benchmark": "^2.1.4",
|
|
62
66
|
"chai": "^4.3.7",
|
|
63
67
|
"chai-as-promised": "^7.1.1",
|
|
64
68
|
"commitlint": "^12.1.4",
|
|
@@ -108,10 +112,12 @@
|
|
|
108
112
|
"commitlint": "commitlint",
|
|
109
113
|
"lint": "eslint . --ext .ts --config .eslintrc",
|
|
110
114
|
"posttest": "yarn lint",
|
|
115
|
+
"compile": "tsc",
|
|
111
116
|
"prepack": "yarn run build",
|
|
112
117
|
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
|
113
118
|
"test:e2e": "mocha --forbid-only \"test/**/*.e2e.ts\" --timeout 1200000",
|
|
114
|
-
"pretest": "yarn build --noEmit && tsc -p test --noEmit --skipLibCheck"
|
|
119
|
+
"pretest": "yarn build --noEmit && tsc -p test --noEmit --skipLibCheck",
|
|
120
|
+
"test:perf": "ts-node test/perf/parser.perf.ts"
|
|
115
121
|
},
|
|
116
122
|
"types": "lib/index.d.ts"
|
|
117
123
|
}
|