command-line-args icon indicating copy to clipboard operation
command-line-args copied to clipboard

double hyphen is parsed as an argument when `defaultOption` is set

Open bakkot opened this issue 3 years ago • 0 comments

The wiki discusses how to correctly handle a double hyphen / double dash (--), but the suggested solution doesn't work when defaultOption is set, particularly alongside multiple:

'use strict';

const commandLineArgs = require('command-line-args')

const optionDefinitions = [
  { name: 'verbose', alias: 'v', type: Boolean },
  { name: 'src', type: String, defaultOption: true, multiple: true },
  { name: 'timeout', alias: 't', type: Number }
]

const options = commandLineArgs(optionDefinitions, { stopAtFirstUnknown: true })

console.log(options)

run with

node main.js one -t 0 -- --verbose two

produces

{ src: [ 'one', '--', 'two' ], timeout: 0, verbose: true }

That's not what -- means: the whole point is that encountering -- should mean that --verbose is interpreted as a positional argument rather than as a flag.

On the other hand, if you have defaultOption: false, then it will stop when it encounters the first positional argument, and the above invocation will result in

{ _unknown: [ 'one', '-t', '0', '--', '--verbose', 'two' ] }

i.e. it will fail to parse -t.

So neither approach actually allows you to correctly handle --.


For now, I'm working around it by manually splicing out the -- part before invoking commandLineArgs:

'use strict';

const commandLineArgs = require('command-line-args')

const optionDefinitions = [
  { name: 'verbose', alias: 'v', type: Boolean },
  { name: 'src', type: String, defaultOption: true, multiple: true },
  { name: 'timeout', alias: 't', type: Number }
]

const { argv } = process

let notParsed = []
const dashDashIndex = argv.indexOf('--')
if (dashDashIndex !== -1) {
  notParsed = argv.splice(dashDashIndex + 1)
  argv.pop()
}

const options = commandLineArgs(optionDefinitions, { argv })

options.src = (options.src || []).concat(notParsed);

console.log(options)

which gives for the above invocation

{ src: [ 'one', '--verbose', 'two' ], timeout: 0 }

which is the right thing.

bakkot avatar Nov 02 '21 20:11 bakkot