Commander.js: Required arguments for options and commands are not enforced

Created on 13 Jul 2014  路  41Comments  路  Source: tj/commander.js

It would be pretty awesome to have support for required arguments. Although there is support for required argument values, there doesn't appear to be anything for ensuring the argument has been specified.

For example;

    -e, --entry <name>          Add module to entry point

I'd like to make it so an error is raised if -e has not been specified like so;

  error: option `-e, --entry <name>' missing
enhancement

Most helpful comment

I immediately regret using this library.

All 41 comments

I agree, will look into this for a future release!

So what are required arguments for exactly?

@foxx @thethomaseffect Can you guys see if this works for you? I needed similar functionality so I thought I might spin up a quick pull request.

I see a lot of open pull-requests.. Will this be merged if I spend time implementing it?

@NameFILIP Hopefully. If you want to ensure your PR is merged, make sure it's wanted (already shown in this case), and has proper tests & documentation.

Is anyone actually working towards this?

Just come up against this again, seems to be quite a few PRs, are any due to be merged by core dev?

Any word on this @tj?

Any word yet?

just came across this issue and didn't really get why it's still not implemented. I saw different reasons for not doing it, but the main problem that current implementation is not really consistent:

  • In some cases, validation is performed
    program.command('command <option>')
    in some not
    program.option('--option <option>', 'option')

what the reason to define required option and don't perform any validation? Of course, it's possible to implement custom validation, but then you need to align error messages with standard validation messages like ' error: missing required argumentoption''`

Any update on this?

I immediately regret using this library.

Any update? :)

+1

+1

+1
really want this feature

Just came across this thread and I'm wondering the same thing. How is there not support for required arguments and why the reluctance? :(

+1

+1

+1

+1

The fact that this still isn't a thing almost hurts. If you want to be a command-line library this should be one of the core features.

After battling with commander.js for some time, I've finally switched to yargs. It has all the features one commonly needs to build CLI tools, including support for required options.

Here's an example with some basic functionality:

yargs
  .command(
    'create',
    'Create a new storage version',
    {
      message: {
        alias: 'm',
        describe: 'Storage version description',
        demandOption: true,
        requiresArg: true,
        type: 'string',
        nargs: 1
      },
      location: {
        alias: 'l',
        describe:
          'Directory where storage versions are kept, grouped by storage area',
        default: 'storage/versions',
        requiresArg: true,
        type: 'string',
        nargs: 1
      },
      storage: {
        alias: 's',
        describe: 'Storage area',
        choices: ['local', 'sync'],
        default: 'local',
        requiresArg: true,
        type: 'string',
        nargs: 1
      }
    },
    function(argv) {
      createVersion(argv);
    }
  )
  .demandCommand(1)
  .help()
  .alias('help', 'h')
  .version()
  .alias('version', 'v')
  .strict().argv;

For simple scenarios, following code works well for me:

program
  .description('Makes any type of pie.')
  .arguments('<type>')
  .action(function (type) {
     // Bake that pie.
  });

program.parse(process.argv);

if (!process.argv.slice(2).length) {
  program.outputHelp(() => program.help());
}

This issue has been quite active over the years and mandatory options comes up multiple times, so I'll add a long comment here.

@foxx asked in original post about making an option mandatory:

I'd like to make it so an error is raised if -e has not been specified

option with required value (already supported)

As noted in the original post, there is already support for making an option have a required value so if you specify the option you must also specify the value.

.option('-c, --config <path>'

$ myCommand -c
error: option `-c, --config <path>' argument missing
$ myCommand
$

A common confusion or expectation is that an option with a required value makes the option itself mandatory (PRs #70 #462 #503 #601). That is not our desired behaviour as most options are optional.

So to be clear I consider these two different things:

  • an option having a required value (currently supported)
  • a mandatory option which must be supplied

I think we should expand on our conventions in the README and be more careful about the terms used to reduce this confusion.

mandatory option (not currently supported)

Now as for making an option mandatory. It has been turned down at least once (#98). At that time it didn't seem worth adding the complexity for something which was easy to check yourself.

However, it is a popular request so I think we shall consider it again!


Questions for readers:

  • what is your favourite example of a common command line application with mandatory options?
  • how is that shown in the command line help?

And:

  • have you got a suggestion for a clean syntax for specifying a mandatory option?

Questions for readers:

  • what is your favourite example of a common command line application with mandatory options?
  • how is that shown in the command line help?

AWS CLI

usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:

  aws help
  aws <command> help
  aws <command> <subcommand> help
aws: error: argument --role-arn is required

Last line mainly.

And:

  • have you got a suggestion for a clean syntax for specifying a mandatory option?

Suggestion 1: Additional boolean parameter at the end:

program.option('-o', '--option <value>', 'A mandatory option.', true)

Suggestion 2: Fancy string syntax -> Add (a) star(s) somewhere with the value

program.option('-o', '--option <*value>', 'A mandatory option.')

Not a fan of the asterisk. I prefer appending true to the end of the option as you have suggested.

I rather prefeer the usage of a property or function call which is more explicit and readable:

program.option('-o', '--option <*value>', 'A mandatory option.').required
program.option.required('-o', '--option <*value>', 'A mandatory option.')

Relatedly, required arguments should be enforced. It should do more than produce nothing.

See above comment for an example use case.

Can be better to add options in case something else has to be passed in future:

program.option('-o, --option <value>', 'A mandatory option.', {required: true})

This also can distinguish from default value, as well as can accept just an object for all settings, this is convenient if options come from somewhere else:

program.option({option: '-o, --option <value>', description: 'A mandatory option.', required: true})

Thanks for the aws example @mrgrain. I tracked down the associated help, and aws explicitly marks all the optional options. Not what I want to do, but interesting.

$ aws sts assume-role 
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:

  aws help
  aws <command> help
  aws <command> <subcommand> help
aws: error: the following arguments are required: --role-arn, --role-session-name

$ aws sts assume-role help
...
SYNOPSIS
            assume-role
          --role-arn <value>
          --role-session-name <value>
          [--policy-arns <value>]
          [--policy <value>]
...

Syntax:

  • a suggestion in #462 is adding .requiredOption('-foo <value>', 'foo must be supplied');
  • a suggestion in #44 is adding * to flag like .option('-b, --bar* <value>', 'add some bar - mandatory');

I am currently liking .requiredOption() as the most explicit and least magical, and support the same calling patterns as .option().

I am currently liking .requiredOption()

I prefer that too.

I tracked down the associated help, and aws explicitly marks all the optional options. Not what I want to do, but interesting.

Yes, they do it pretty much the other way around and documentation-wise the square brackets are certainly common. But for now anyway of requiring an option to be present would be nice. One can always add their own message styling.

I'm very much like .requiredOption().

I do also like the idea in principle of supporting an options/settings parameter to allow for future additions: https://github.com/tj/commander.js/issues/230#issuecomment-520127955

But I think it needs to be a new method as .options has enough overloads already. I remembered a pattern I think from the Windows API, where Ex stands for extra or extended and means there is an extra parameter with settings. e.g.

   .optionEx('-o, --option <value>', 'A mandatory option.', { required: true });
   .optionEx('--secret', '(secret mode)', { noHelp: true });

I added an issue to get some visibility on possible API, vote for preferred API there: #1038

Implementing .requiredOption() in #1071.

Added .requiredOption() to v4.0.0 prerelease: #1067

v4.0.0 has been released.

There were some other things raised in various comments, but the main issue discussed of allowing a mandatory option has been added.

Feel free to open a new issue for other aspects, with new information and renewed interest.

@shadowspawn That's already a start but the other main issue of this thread was mandatory arguments, which still isn't a thing :(

The current workaround being

if (program.args.length < 2) {
  program.outputHelp(() => program.help());
}

@Tofandel

Missing arguments generate an error from Commander v5: #995 #1149

Using the example code from: https://github.com/tj/commander.js/issues/230#issuecomment-424897234

% node args.js 
error: missing required argument 'type'
Was this page helpful?
0 / 5 - 0 ratings

Related issues

cmoulliard picture cmoulliard  路  4Comments

RoXioTD picture RoXioTD  路  4Comments

san-templates picture san-templates  路  5Comments

0505gonzalez picture 0505gonzalez  路  3Comments

DeoLeung picture DeoLeung  路  4Comments