Commander.js: When providing custom function for options, requiredOption don't work

Created on 30 Dec 2019  路  9Comments  路  Source: tj/commander.js

When:

  .requiredOption('--package-id <value>', 'The package identifier.', isAllowedValue, ['test1','test2','test3'])

Commander not existing asking for required option.

Most helpful comment

A possible minimal implementation.

function isAllowedValue(allowedValues) {
  // return a function which checks the value is in the allowedValues
  return (value) => {
    if (!allowedValues.includes(value)) {
      throw Error(`Invalid option value: ${value}`);
    }
    return value;
  }
}

program
  .requiredOption('--package-id <value>', 'The package identifier.', isAllowedValue(['test1','test2','test3']));
$ node index.js                   
error: required option '--package-id <value>' not specified
$ node index.js --package-id test1
test1
$ node index.js --package-id test4
/Users/john/Documents/Sandpits/commander/issues/1130/index.js:6
      throw Error('Invalid value for option');
      ^
...

All 9 comments

Based on the code fragment you supplied, I expect Commander does not complain about the requiredOption because the option has a value.

const program = require('commander');

function isAllowedValue() {}

program
  .requiredOption('--package-id <value>', 'The package identifier.', isAllowedValue, ['test1','test2','test3']);

program.parse(process.argv);
console.log(program.packageId);
$ node index.js
[ 'test1', 'test2', 'test3' ]

In particular, it is supplying the default value that means requiredOption does not complain. Not the addition of a custom function.

So it is by design by the looks of it. Although I think reverse of that also make sense, requiredOption takes priority of default value provided.

How would you achieve what I want to achieve more elegantly?

Yes it is by design. I like some patterns this allows like supplying a default value from an environment variable which may or may not be defined.

How would you achieve what I want to achieve more elegantly?

What do you want? (What does isAllowedValue have in it?)

What do you want? (What does isAllowedValue have in it?)

It ensures the value provided is from a defined set of values. Also respect if that options is required or not.

  .requiredOption('--package-id <value>', 'The package identifier.', isAllowedValue, ['test1','test2','test3'])

In above example 'isAllowedValue' will exit if is not any of ['test1','test2','test3']. Even having ability to validate based on a regex. Just a thought.

The open issue for exactly what you want is #518

(There actually is support to validate using a regular expression! But it is deprecated because it just silently returns default value for mismatches so disappointing in practice.)

I have been thinking about #518 and will add a possible implementation for supplying your own isAllowedValue.

A possible minimal implementation.

function isAllowedValue(allowedValues) {
  // return a function which checks the value is in the allowedValues
  return (value) => {
    if (!allowedValues.includes(value)) {
      throw Error(`Invalid option value: ${value}`);
    }
    return value;
  }
}

program
  .requiredOption('--package-id <value>', 'The package identifier.', isAllowedValue(['test1','test2','test3']));
$ node index.js                   
error: required option '--package-id <value>' not specified
$ node index.js --package-id test1
test1
$ node index.js --package-id test4
/Users/john/Documents/Sandpits/commander/issues/1130/index.js:6
      throw Error('Invalid value for option');
      ^
...

I did not see that being possible. Using same mechanism we do regex like:

function isAllowedValue(regExpStr) {
  // return a function which checks the value is in the allowedValues
  return (value) => {
    if (!RegExp(regExpStr).test(value)) {
      throw Error(`Invalid option value: ${value}`);
    }
    return value;
  }
}

program
  .requiredOption('--package-id <value>', 'The package identifier.', isAllowedValue('^(test1|test2|test3)$'));

An answer was provided, and no further activity in a month. Closing this as resolved.

Feel free to open a new issue if it comes up again, with new information and renewed interest.

Was this page helpful?
0 / 5 - 0 ratings