yargs: Conflicting options with default values (or boolean values)

Using conflicts with an option that has a default value, or a boolean option (which is automatically set to false even if a default value is not provided) always throws an error, because the conflicting option name will always be defined.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 14
  • Comments: 25 (5 by maintainers)

Most upvoted comments

I ran into a similar issue, and what fixed it for me was changing defaults to undefined…

    .option('debug', {
      alias: 'd',
      type: 'boolean',
      describe: 'logs all debug messages',
      conflicts: ['silent', 'quiet', 'verbose'],
      default: undefined
    })
    .option('quiet', {
      alias: 'q',
      type: 'boolean',
      describe: 'log only warnings',
      conflicts: ['silent', 'verbose', 'debug'],
      default: undefined
    })
    .option('silent', {
      alias: 's',
      type: 'boolean',
      describe: 'turn off logging',
      conflicts: ['quiet', 'verbose', 'debug'],
      default: undefined
    })
    .option('verbose', {
      alias: 'V',
      type: 'boolean',
      describe: 'enables verbose logging',
      conflicts: ['silent', 'quiet', 'debug'],
      default: undefined
    })

note above, without default: undefined I kept having the “arguments are mutually exclusive” problem

I’m running into this issue as well; it makes it impossible to have mutually exclusive options where one or both are booleans.

@bcoe what I would expect is that if the argument is a boolean, it only considers it “set” if it’s true. Similarly, conflicts should be checked before default values are applied.

This issue is solved now for booleans: a conflict will be triggered only if you explicitely set a default value (as for other types).

sure, my code is basically:

/**
 * @param {Array<string>} rawArgs - i.e. from `process.argv`
 * @returns {Object} parsed args
 */
export function parseArgs(rawArgs) {
  return yargs
    .command('$0 <files...>', 'My tool command', (yargs) => {
      yargs
        .option('no-color', {
          alias: 'n',
          type: 'boolean',
          default: undefined,  // default: false triggers conflict warning by yargs
          describe:
            `Monochrome output only`
        })
        .option('force-color', {
          alias: 'c',
          type: 'boolean',
          default: undefined,  // default: false triggers conflict warning by yargs
          conflicts: 'no-color',
          describe:
            `When running as a pre-commit hook we are unable to detect if the ` +
            `terminal supports colored output. If you want to see colored ` +
            `output then set this flag.`
        });
    })
    .help()
    .parse(rawArgs.slice(2))
  ;
}

No, sorry, I haven’t made any progress on this. I worked around it by just not using defaults for booleans, and then forgot to look into it beyond the comments above.

Just ran into this bug now.

For now, I’m setting coerce: (v) => v || undefined on the boolean flag that’s causing the problem as a workaround.

@jordansexton any thoughts about what the default behavior should be … what’s weird is that false is a value it feels like it would be too loose to have the conflicts logic simply look for a falsy value since values like "" would also pass the conflicts test.