@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.
@@ -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
- this.combineElementsToFlag(elementMap, flag.name, flag.exclusive, ' | ');
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
  */
@@ -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((0, util_1.last)(i.tokens)?.input !== `--no-${i.inputFlag.name}`, i.inputFlag.flag, this.context, (0, util_1.last)(i.tokens)),
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('--no-')) {
459
- const flag = this.booleanFlags[arg.slice(5)];
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]) {
@@ -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,
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": "4.5.6",
4
+ "version": "4.7.0",
5
5
  "author": "Salesforce",
6
6
  "bugs": "https://github.com/oclif/core/issues",
7
7
  "dependencies": {