Skip to content

Ambiguity with multiples

Lloyd Brookes edited this page Jan 16, 2018 · 3 revisions

Ambiguity issues can arise where two or more multiple options are defined where one is the defaultOption. Imagine we built a tool with the following option definitions.

const commandLineArgs = require('command-line-args')
const optionDefinitions = [
  { name: 'files', multiple: true, defaultOption: true },
  { name: 'actions', multiple: true }
]
const options = commandLineArgs(optionDefinitions)

The tool (named example in this case) might typically be used like this...

$ example one.js two.js

...resulting in these options.

{ files: [ 'one.js', 'two.js' ] }

So far, everything is great. In this next command, the user wishes to perform the print and archive actions on each file.

$ example --actions print archive one.js two.js

The parser now has an ambiguity issue - it's not clear which of the four values supplied should be passed to --actions and which to --files (the defaultOption). As it stands, the parsed options will look like this.

{ actions: [ 'print', 'archive', 'one.js', 'two.js' ] }

The two actions (print and archive) have been parsed as actions, which is correct. However, the two file names have been parsed as actions too, which is incorrect. There are several ways to avoid ambiguity arising.

  1. Supply the args in a different order. The following example works correctly, removing the ambiguity but introduces an unwelcome "order sensitivity" to the command.

    $ example one.js two.js --actions print archive
    
    
  2. Be specific where the --files list begins.

    $ example --actions print archive --files one.js two.js
    
  3. Disable greedy parsing. If we set greedy: false on our actions option, like so...

    const optionDefinitions = [
      { name: 'files', multiple: true, defaultOption: true },
      { name: 'actions', multiple: true, greedy: false }
    ]

    ...then our user will need to specific the --actions option for each value added to the list, for example:

    $ example --actions print --actions archive one.js two.js
    

    Now our parsed options look correct.

    {
      actions: [ 'print', 'archive' ],
      files: [ 'one.js', 'two.js' ] }
    }