3

I can't find a way to properly configure positional arguments. I have this code:

#!/usr/bin/env node

const create = (argv) => {
  console.log('create component with name:', argv.name)
}

const createBuilder = (yargs) => {
  yargs.positional('name', {
    desc: 'Name of the new component',
  })
}

/* eslint-disable no-unused-expressions */
require('yargs')
  .command({
    command: 'create <name>',
    desc: 'Create a new component',
    builder: createBuilder,
    handler: create,
  })
  .demandCommand(1, 'A command is required')
  .help()
  .argv

and I would like to provide a custom error message in case the user doesn't specify a name after the create command.

It's not clear to me from the documentation how to do that, and while going through github issues I came across this comment (#928):

I recommend instead using demandCommand and demandOption (each of which are documented).

These allow you to configure positional arguments and flag arguments separately

I've tried all kinds of combinations with

.demandCommand(1, 'You need to provide name for the new component')

or

.demandOption('name', 'You need to provide name for the new component')

but without luck. Does anybody know how to do this?

devboell
  • 1,180
  • 2
  • 16
  • 34

2 Answers2

3

tl;dr - try making your command a default command by adding the string * or $0 to the start of your command name.

I've found that the positional arguments are only respected (ie: show up in the help menu and throw an error when a required positional isn't provided) when the positional argument is defined in a default command.

Here's an example of getting it to work with your code (note that you no longer have to use .demandCommand()):

require('yargs')
  .scriptName('cli-app')
  .command({
    command: '$0 create <name>',
    desc: 'Create a new component',
    builder: yargs => {
      yargs.positional('name', {
        desc: 'Name of the new component'
      });
    },
    handler: function(argv) {
      console.log('this is the handler function!');
    }
  })
  .help().argv;

Output (note the "Not enough non-option arguments: got 1, need at least 2" line at the end):

➞ node cli-app.js create                                                                                                                                       1 ↵
cli-app create <name>

Create a new component

Positionals:
  name  Name of the new component

Options:
  --version  Show version number                                       [boolean]
  --help     Show help                                                 [boolean]

Not enough non-option arguments: got 1, need at least 2
Brian Zelip
  • 2,909
  • 4
  • 33
  • 45
0

The command option of yargs can take two types of arguments.

The first being Obligatory: <varName>. If for some reason, the user type the command without entering a varName, then it will run the help page.

The second being Optional: [varName]. If the user enters the command, even with a missing varName, the command will run.

Extra: if you want infinite varName variables, then you can provide a spread operator for the wanted option. Being <...varNames> or [...varNames]


That being said, if you want to provide a custom error message, there are several ways of going about it. The first is this one:

const program = require('yargs')
    .command('create [fileName]', 'your description', () => {}, argv => {
        if(argv.fileName === undefined) {
            console.error('You need to provide name for the new component')
            return;
        }
        console.log(`success, a component called ${argv.fileName} got created.`)
    })

Lodash also provides a function _.isUndefined which would also work.


The second is this one:

const program = require('yargs')
    .command('create <fileName>', 'A description', () => {}, argv => {

    }).fail((msg, err, yargs) => {
        console.log('Sorry, no component name was given.')
    })

program.argv

For more information, here is the fail documentation on yargs api.

Dany Gagnon
  • 102
  • 1
  • 9
  • thank you, but I feel this is more of workaround, than a solution using the yargs api. A problem I see is that -h would display: `create [fileName] Create a new component` marking fileName as optional, whereas I want to communicate it is required. – devboell Nov 15 '17 at 13:15
  • The second example *fixed* your issue? – Dany Gagnon Nov 15 '17 at 13:33
  • Not really, it will still call the handler with `undefined`, so I'll have to handle that. Also I don't know what other errors might cause `fail` to be called, so i'll have to add code to figure that out. Plus the user feedback by means of console.log/error is not consistent with the messages returned by `demandCommand` and `demandOption`. I was hoping for something like `demandPositional` ... I may just open issue on github. I appreciate your help though! – devboell Nov 15 '17 at 13:56