75lb / command-line-args

A mature, feature-complete library to parse command-line options.
MIT License
679 stars 107 forks source link

Support positional args #97

Open 75lb opened 5 years ago

75lb commented 5 years ago

Support positional args, similar to what is available in argparse.

ghost commented 5 years ago

I think they can be emulated via { name: 'defaults', defaultOption: true, multiple: true }, but then command-line-usage will print this option...

Ahh, with hide: 'defaults' complements it.

tnunamak commented 5 years ago

That emulation technique is very clever! One drawback with it, however, is that it cannot coerce the arguments to different data types (which I realized after trying it).

Myaamori commented 4 years ago

I'd also love to see this. I have a set of commands of the form

cmd1 <positional1> <positional2>
cmd2 <positional1>
<positional1> subcmd1 <positional2>
<positional1> subcmd2 <positional3> [flags]
<positional1> <positional2> <multiple-positionals..>

and command-line-args' stopAtFirstUnknown is very useful for dealing with the subcommands preceded by positionals (which e.g. yargs can't handle), but the lack of explicit support for positionals makes implementing commands that can take multiple positionals, e.g. cmd1 here, annoying. If possible I'd like to be able to do something like

if (mainCommand.command === "cmd1") {
    const cmd1 = commandLineArgs([
        { name: "positional1", defaultOption: true },
        { name: "positional2", defaultOption: true }
    ], { argv: mainCommand._unknown })
}

but this gives an error saying that only one option can be a defaultOption.

I'd rather not have to use multiple, since no error would be thrown if less or more than two positionals are supplied.

75lb commented 4 years ago

Hi @Myaamori, positional args are planned for the next release. In the meantime, you can emulate positional args with code like this.

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

const optionDefinitions = [
  {
    name: 'positionals',
    multiple: true,
    defaultOption: true
  }
]

const options = commandLineArgs(optionDefinitions)
console.log(options)

/* validate positionals */
const validArgs = options.positionals
  && options.positionals.length === 2
  && options.positionals.every(p => p)

if (validArgs) {
  console.log('Valid args')
} else {
  throw new Error('Exactly two args are required.')
}

Example invocations:

$ node example.js image.jpg
{ positionals: [ 'image.jpg' ] }
/Users/lloyd/Documents/75lb/command-line-args/tmp/examples/positionals.js:22
  throw new Error('Exactly two args are required.')

$ node example.js image.jpg imgs
{ positionals: [ 'image.jpg', 'imgs' ] }
Valid args
75lb commented 4 years ago

Using the above example, if using command-line-usage the positionals option would appear in your usage guide (as @ghost mentioned above). See here for instructions how to hide it.