@oclif/core 4.5.6 → 4.7.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/help/docopts.js +15 -1
- package/lib/interfaces/parser.d.ts +5 -1
- package/lib/parser/parse.js +15 -3
- package/lib/parser/validate.js +27 -0
- package/lib/util/cache-command.js +1 -0
- package/package.json +1 -1
package/lib/help/docopts.js
CHANGED
|
@@ -165,8 +165,22 @@ class DocOpts {
|
|
|
165
165
|
if (Array.isArray(flag.dependsOn)) {
|
|
166
166
|
this.combineElementsToFlag(elementMap, flag.name, flag.dependsOn, ' ');
|
|
167
167
|
}
|
|
168
|
+
let exclusive;
|
|
168
169
|
if (Array.isArray(flag.exclusive)) {
|
|
169
|
-
|
|
170
|
+
exclusive = new Set(flag.exclusive);
|
|
171
|
+
}
|
|
172
|
+
if (Array.isArray(flag.combinable)) {
|
|
173
|
+
const combinableFlags = new Set(flag.combinable);
|
|
174
|
+
exclusive ??= new Set();
|
|
175
|
+
for (const item of this.flagList) {
|
|
176
|
+
// each flag not in the "combinable" list, is equivalent to an "exclusive" flag
|
|
177
|
+
if (flag !== item && !combinableFlags.has(item.name)) {
|
|
178
|
+
exclusive.add(item.name);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (exclusive !== undefined && exclusive.size > 0) {
|
|
183
|
+
this.combineElementsToFlag(elementMap, flag.name, [...exclusive], ' | ');
|
|
170
184
|
}
|
|
171
185
|
}
|
|
172
186
|
// Since combineElementsToFlag deletes the references in this.flags when it combines
|
|
@@ -87,7 +87,7 @@ export type FlagRelationship = string | {
|
|
|
87
87
|
when: (flags: Record<string, unknown>) => Promise<boolean>;
|
|
88
88
|
};
|
|
89
89
|
export type Relationship = {
|
|
90
|
-
type: 'all' | 'some' | 'none';
|
|
90
|
+
type: 'all' | 'some' | 'none' | 'only';
|
|
91
91
|
flags: FlagRelationship[];
|
|
92
92
|
};
|
|
93
93
|
export type Deprecation = {
|
|
@@ -138,6 +138,10 @@ export type FlagProps = {
|
|
|
138
138
|
* List of flags that cannot be used with this flag.
|
|
139
139
|
*/
|
|
140
140
|
exclusive?: string[];
|
|
141
|
+
/**
|
|
142
|
+
* List of the only flags that can be used with this flag.
|
|
143
|
+
*/
|
|
144
|
+
combinable?: string[];
|
|
141
145
|
/**
|
|
142
146
|
* Exactly one of these flags must be provided.
|
|
143
147
|
*/
|
package/lib/parser/parse.js
CHANGED
|
@@ -75,6 +75,7 @@ const validateOptions = (flag, input) => {
|
|
|
75
75
|
throw new errors_1.FlagInvalidOptionError(flag, input);
|
|
76
76
|
return input;
|
|
77
77
|
};
|
|
78
|
+
const NEGATION = '--no-';
|
|
78
79
|
class Parser {
|
|
79
80
|
input;
|
|
80
81
|
argv;
|
|
@@ -299,9 +300,16 @@ class Parser {
|
|
|
299
300
|
if (tokenLength) {
|
|
300
301
|
// boolean
|
|
301
302
|
if (fws.inputFlag.flag.type === 'boolean' && (0, util_1.last)(fws.tokens)?.input) {
|
|
303
|
+
const doesNotContainNegation = (i) => {
|
|
304
|
+
const possibleNegations = [i.inputFlag.name, ...(i.inputFlag.flag.aliases ?? [])].map((n) => `${NEGATION}${n}`);
|
|
305
|
+
const input = (0, util_1.last)(i.tokens)?.input;
|
|
306
|
+
if (!input)
|
|
307
|
+
return true;
|
|
308
|
+
return !possibleNegations.includes(input);
|
|
309
|
+
};
|
|
302
310
|
return {
|
|
303
311
|
...fws,
|
|
304
|
-
valueFunction: async (i) => parseFlagOrThrowError((
|
|
312
|
+
valueFunction: async (i) => parseFlagOrThrowError(doesNotContainNegation(i), i.inputFlag.flag, this.context, (0, util_1.last)(i.tokens)),
|
|
305
313
|
};
|
|
306
314
|
}
|
|
307
315
|
// multiple with custom delimiter
|
|
@@ -455,10 +463,14 @@ class Parser {
|
|
|
455
463
|
if (this.flagAliases[name]) {
|
|
456
464
|
return this.flagAliases[name].name;
|
|
457
465
|
}
|
|
458
|
-
if (arg.startsWith(
|
|
459
|
-
const flag = this.booleanFlags[arg.slice(
|
|
466
|
+
if (arg.startsWith(NEGATION)) {
|
|
467
|
+
const flag = this.booleanFlags[arg.slice(NEGATION.length)];
|
|
460
468
|
if (flag && flag.allowNo)
|
|
461
469
|
return flag.name;
|
|
470
|
+
const flagAlias = this.flagAliases[arg.slice(NEGATION.length)];
|
|
471
|
+
if (flagAlias && flagAlias.type === 'boolean' && flagAlias.allowNo) {
|
|
472
|
+
return flagAlias.name;
|
|
473
|
+
}
|
|
462
474
|
}
|
|
463
475
|
}
|
|
464
476
|
findShortFlag([_, char]) {
|
package/lib/parser/validate.js
CHANGED
|
@@ -57,6 +57,7 @@ async function validate(parse) {
|
|
|
57
57
|
...(flag.relationships ? validateRelationships(name, flag) : []),
|
|
58
58
|
...(flag.dependsOn ? [validateDependsOn(name, flag.dependsOn)] : []),
|
|
59
59
|
...(flag.exclusive ? [validateExclusive(name, flag.exclusive)] : []),
|
|
60
|
+
...(flag.combinable ? [validateCombinable(name, flag.combinable)] : []),
|
|
60
61
|
...(flag.exactlyOne ? [validateExactlyOne(name, flag.exactlyOne)] : []),
|
|
61
62
|
];
|
|
62
63
|
}
|
|
@@ -143,6 +144,29 @@ async function validate(parse) {
|
|
|
143
144
|
}
|
|
144
145
|
return { ...base, status: 'success' };
|
|
145
146
|
}
|
|
147
|
+
async function validateCombinable(name, flags) {
|
|
148
|
+
const base = { name, validationFn: 'validateCombinable' };
|
|
149
|
+
const combinableFlags = new Set(flags.map((flag) => (typeof flag === 'string' ? flag : flag.name)));
|
|
150
|
+
const resolved = await resolveFlags(flags);
|
|
151
|
+
for (const flag of Object.keys(parse.output.flags)) {
|
|
152
|
+
// do not enforce exclusivity for flags that were defaulted
|
|
153
|
+
if (parse.output.metadata.flags && parse.output.metadata.flags[flag]?.setFromDefault)
|
|
154
|
+
continue;
|
|
155
|
+
if (parse.output.metadata.flags && parse.output.metadata.flags[name]?.setFromDefault)
|
|
156
|
+
continue;
|
|
157
|
+
if (flag !== name && parse.output.flags[flag] !== undefined && !combinableFlags.has(flag)) {
|
|
158
|
+
const formattedFlags = Object.keys(resolved)
|
|
159
|
+
.map((f) => `--${f}`)
|
|
160
|
+
.join(', ');
|
|
161
|
+
return {
|
|
162
|
+
...base,
|
|
163
|
+
reason: `Only the following can be provided when using --${name}: ${formattedFlags}`,
|
|
164
|
+
status: 'failed',
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return { ...base, status: 'success' };
|
|
169
|
+
}
|
|
146
170
|
async function validateExactlyOne(name, flags) {
|
|
147
171
|
const base = { name, validationFn: 'validateExactlyOne' };
|
|
148
172
|
const resolved = await resolveFlags(flags);
|
|
@@ -195,6 +219,9 @@ async function validate(parse) {
|
|
|
195
219
|
case 'none': {
|
|
196
220
|
return validateExclusive(name, relationship.flags);
|
|
197
221
|
}
|
|
222
|
+
case 'only': {
|
|
223
|
+
return validateCombinable(name, relationship.flags);
|
|
224
|
+
}
|
|
198
225
|
case 'some': {
|
|
199
226
|
return validateSome(name, relationship.flags);
|
|
200
227
|
}
|
|
@@ -20,6 +20,7 @@ async function cacheFlags(cmdFlags, respectNoCacheDefault) {
|
|
|
20
20
|
aliases: flag.aliases,
|
|
21
21
|
char: flag.char,
|
|
22
22
|
charAliases: flag.charAliases,
|
|
23
|
+
combinable: flag.combinable,
|
|
23
24
|
dependsOn: flag.dependsOn,
|
|
24
25
|
deprecateAliases: flag.deprecateAliases,
|
|
25
26
|
deprecated: flag.deprecated,
|