Yargs examples

Yargs is a Node package that parses arguments and generates help menus for your CLI tools. In this post, you’ll see how to configure Yargs to accomplish those tasks with examples. But before we see the examples, it will be useful to explain some CLI terms first.

CLI Terms

Commands and options

CLI tools accept two types of arguments: commands and options.

  • The commands are arguments that don’t have a hyphen - in front of them. For example, git clone or git init; clone and init are two different git commands. Use commands if your program is big and performs a wide range of tasks. If your program performs only a specific task, you don’t need commands.
  • The options, on the other hand, are prefixed with hyphens. With two hyphens you indicate the full name of the option: e.g.--verbose and with one the alias: e.g.-v. Use options to get input from the user or customize the behavior of the program.

Node shebang

#!/usr/bin/env node

I will not attempt to explain what a shebang is—I didn’t find a good, non-technical explanation—but, instead, I will tell you what it does. It locates the node executable and allows you to run the script as a binary in Unix systems. For example, you can run the program with ./scipt.js instead of node script.js. There’s also an ESLint rule for that.

bin field in package.json

Use package.json’s bin field to provide aliases for your scripts. You can then use those aliases to call your scripts after you install your package globally—a thing you do with npm link or by publishing it. Consider the following package.json:

// package.json
{
  "name": "calculate-stuff",
  "bin": {
    "area": "./area.js",
    "circle-area": "./circle-area.js"
  }
}
// Install it globally with `npm link`.
// Run it with `area --width 10 --height 5` or with `circle-area --radius 5`

By specifying the bin fields, you can now call the area script with area --width num --height num and the circle-area script with circle-area --radius num. If you don’t provide aliases, you have to call the index script with calculate-area and figure out what to do from there.

Special characters

  • The argument is required: <argument>.
  • This argument is optional: [argument].
  • Use the pipe operator for name/alias: <name|alias>.
  • You indicate an array with an ellipsis [arguments..].

From (kind of) Wikipedia CLI, Command description syntax, Opengroup utility argument syntax, Positional Arguments.

Configure an option

Let’s assume that you want to write a program that calculates the area of a rectangle:

// area.js
const { width, height } = getArguments();
console.log(`The area is ${width * height}`);

You can use Yargs to get the width and height as arguments from the user and to create a help menu. Calculating the area of a rectangle is trivial, but the following example shows many of the ways you can configure Yargs to parse options and create help menus. To understand what the methods do, read the comments above them:

#!/usr/bin/env node
// area.js
var { argv } = require("yargs")
  // 1. The name of the script in the help menu.
  // You invoke the help menu with the --help option.
  .scriptName("area")
  // 2. Display a usage message in the help menu.
  // The "$0" is the script name.
  .usage("Usage: $0 -w num -h num")
  // If you want to show what is required or not,
  // you could write it as follows—I'm not 100% sure though.
  // .usage("Usage: $0 <-w <num>> <-h <num>>")
  // 3. An example in the help menu; the code to
  // run and a description on what the code does.
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  // 4. Define the width (-w) option.
  .option("w", {
    // 5. The alias of -w is --width (or the other way around).
    alias: "width",
    // 6. Help menu message for the width option.
    describe: "The width of the area.",
    // 7. Make the width option required and
    // provide an error message when it's not present.
    demandOption: "The width is required.",
    // 8. You can use a default value instead of
    // requiring the option:
    //  default: 5.
    // 9. Provide a type for the option. Instead of
    // using the type, you can use the number field:
    // number: true,
    // Other type options you have are: boolean, array, string.
    type: "number",
    // 10. State the number of values you accept after
    // the width option. For example, in this case,
    // if you pass -w 10 11, only the 10 will be assigned
    // to the width.
    nargs: 1
  })
  .option("h", {
    alias: "height",
    describe: "The height of the area.",
    demandOption: "The height is required.",
    type: "number",
    nargs: 1
  })
  // 11. Instead of using the `option` method, you can
  // use the individual methods. Here I'm
  // using the `describe` method to override the message of
  // the --help option. More about that in a bit.
  .describe("help", "Show help.") // Override --help usage message.
  .describe("version", "Show version number.") // Override --version usage message.
  // 12. Print a message at the end of the help menu.
  .epilog("copyright 2019");

const { width, height } = argv;

console.log(`The area is ${width * height}`);

You can find all the valid options in the Yargs API page. In the following example, you can find the same code without the comments:

#!/usr/bin/env node
var { argv } = require("yargs")
  .scriptName("area")
  .usage("Usage: $0 -w num -h num")
  .example(
    "$0 -w 5 -h 6",
    "Returns the area (30) by multiplying the width with the height."
  )
  .option("w", {
    alias: "width",
    describe: "The width of the area.",
    demandOption: "The width is required.",
    type: "number",
    nargs: 1
  })
  .option("h", {
    alias: "height",
    describe: "The height of the area.",
    demandOption: "The height is required.",
    type: "number",
    nargs: 1
  })
  .describe("help", "Show help.")
  .describe("version", "Show version number.")
  .epilog("copyright 2019");

const { width, height } = argv;

console.log(`The area is ${width * height}`);

This is the what the program prints in the console if you call it with the --help option:

./area.js --help

# Usage: area -w num -h num
#
# Options:
#   --help        Show help.                     [boolean]
#   --version     Show version number.           [boolean]
#   -w, --width   The width of the area.         [number] [required]
#   -h, --height  The height of the area.        [number] [required]
#
# Examples:
#   area -w 5 -h 6  Returns the area (30) by multiplying
#                   the width with the height.
#
# copyright 2019

This is the output if you call it without the --width and --height arguments:

node area.js

# Usage: area -w num -h num
#
# Options:
#   --help        Show help.                     [boolean]
#   --version     Show version number.           [boolean]
#   -w, --width   The width of the area.         [number] [required]
#   -h, --height  The height of the area.        [number] [required]
#
# Examples:
#   area -w 5 -h 6  Returns the area (30) by multiplying
#                   the width with the height.
#
# copyright 2019
#
# Missing required arguments: w, h# The width is required.# The height is required.

Use the individual methods

Instead of using the option method, you can also use the individual methods. For example, the configuration for the --width option can be written as shown below:

#!/usr/bin/env node
// area.js
var { argv } = require("yargs")
  // ...
  .alias("w", "width")
  .describe("w", "The width of the area.")
  .demandOption("w", "The width is required.")
  // .default("w", 5)
  .number("w")
  .nargs(1);
// ...

Run the program

You can now run the program in the following ways:

  • ./area.js -w 5 -h 6, if you added the node shebang at the top of the file.
  • node area.js -w 5 -h 6.
  • npm link to install it globally, and then area -w 5 -h 6—replace the area with the name you set up in the bin field of your package.json.

Other interesting configuration options

  • .implies(). implies('w', 'h') means that if -w has a value, then -h should have a value too. It could be useful in our case.
  • .strict(""). Throws errors if the options/command requirements are not met. For example, if the type of an option is not correct, it throws an error.
  • Dealing with quotes

Commands

TODO. I don’t need it right now, maybe I will revisit it in the future. For now, see Advanced in Yargs docs.

Resources

Most of the are from the Yargs Github page.

Other things to read

Popular posts

Other notes