# Program

A Program instance is directly generated for you by Caporal. This is what you get when requiring Caporal:

const { program } = require("caporal")

# Name and description

# .name(name: string) and .description(description: string)

Define the name and description of your program using .name() and .description(). These information are optional but strongly encouraged as they will be displayed in your program help.

// [...]
program
  .name("My super program")
  .description("A program that does something.")
  .action(/*...*/)
// [...]

Note that Caporal will detect your program version by reading it from your package.json. If you want to override it, use the .version() method to do it.

# Adding arguments and options

# .argument(synopsis: string, description: string, options: object)

# .option(synopsis: string, description: string, options: object)

For a simple program, you may want to add arguments and options directly to the Program instance. Adding arguments & options directly to the program make sense if it only does one thing (e.g: a program that does not have commands). To do so, use .argument() and .option() like below:

#!/usr/bin/env node
const { program } = require("caporal")
const fs = require("fs")
// This program does only one thing, so there is no declared commands (using `.command()`)
program
  .name("Count lines")
  .argument("<file>", "File name") // add an argument to the program
  .option("--print-size", "print file size") // add an option to the program
  .action(({ logger, args, options }) => {
    const contents = fs.readFileSync(args.file, "utf-8")
    const lines = contents.split(options.eol)
    logger.info("%d lines", lines.length)
    if (options.printSize) {
      const { size } = fs.statSync(args.file)
      logger.info("File size: %d bytes", size)
    }
  })

program.run()
/*
$ ./count.js file.txt --print-size
39 lines
File size: 782 bytes
*/

In fact, when you declare arguments and options this way, they aren't really attached to the program, but on what we call the program-command, which is an anonymous, auto-generated Command called when executing a program that does not contain any declared command.

To learn how to add arguments and options to your commands, checkout the Commands guide.

# Global options

Those kind of options are set on the program level and available globally, in all commands. Caporal provides the following global options by default:

Notation Description
-h, --help Display global help or command-related help
-v, --verbose Verbose mode: program will also output debug messages.
--quiet Quiet mode: only displays warnings and error messages
--silent Silent mode: does not output anything, giving no indication of success or failure other than the exit code.
-V, --version Display version.
--no-color Disable use of colors in output

# Adding a global option

Use the global property of the .option() method to add a global option to your program.

program.option("--project", "Project ID", {
  global: true,
  action: () => {}, // Optional action executed when the global option is provided
})

# Disabling a global option

# .disableGlobalOption(option: string)

You can totally disable a global option, including those provided by default using .disableGlobalOption():

// disable the verbose option by providing its long notation
program.disableGlobalOption("--verbose")

// OR by providing its short notation
program.disableGlobalOption("-v")

// OR by providing its name
program.disableGlobalOption("verbose")

# Defining an Action

# .action(action: Function)

Use .action() to set the program action, e.g. the function that will be executed when running the program. As explained in the previous paragraph, setting an action on the program level only makes sense for simple, mono-command programs.

// [...]
program.action(({ logger }) => {
  logger.info("Hey there!")
})
// [...]

Actions can be synchronous, asynchronous, throw errors, and more! Checkout the Action guide to learn more about actions.

# Adding commands

# Manually

# .command(name: string, description: string, config?: Object)

Use .command() to add a command to your program.






 










 








#!/usr/bin/env ts-node
// file: pizza-hit.ts
import program from "@caporal/core"

program
  // First possible command: "order"
  .command("order", "Order a pizza")
  .argument("<type>", "Type of pizza")
  .option("-e, --extra-ingredients <ingredients>", "Extra ingredients")
  .action(({ logger, args, options }) => {
    logger.info("Order received: %s", args.type)
    if (options.extraIngredients) {
      logger.info("Extra: %s", options.extraIngredients)
    }
  })

  // Another command: "cancel"
  .command("cancel", "Cancel an order")
  .argument("<order-id>", "Order id")
  .action(({ logger, args }) => {
    logger.info("Order canceled: %s", args.orderId)
  })

program.run()

In the example above, our program contains 2 commands: order and cancel, which can be called this way:

# order a margherita with pepperoni on top
./pizza-hit.js order margherita -e pepperoni

# cancel an order
./pizza-hit.js cancel 12345

.command() will return the created command, allowing you to chain .argument() and .option() methods to add arguments and options to it.

# Auto discovery

Advanced usage

This feature may be interesting for programs handling a large number of commands, or for people who would like to split their commands into several files.

# .discover(path: string)

Commands can also be loaded dynamically from the filesystem using .discover().









 



#!/usr/bin/env ts-node
import { program } from "@caporal/core"
import path from "path"

program
  .name("kubectl")
  .version("1.0.0")
  .description("Mimics the kubectl CLI")
  .discover(path.join(__dirname, "discover/commands"))

program.run()

Commands must be organized into files (one command per file) in a file tree like:

discover/commands
├── config
│   ├── set.ts
│   └── unset.ts
├── create
│   ├── job.ts
│   └── service.ts
├── create.ts
├── describe.ts
└── get.ts

The code above shows a short example of kubectl commands and subcommands. In this particular case, Caporal will generate the following commands:

  • kubectl get
  • kubectl config set
  • kubectl config unset
  • kubectl create
  • kubectl create job
  • kubectl create service
  • kubectl describe
  • kubectl get

Notice how the config command has a mandatory subcommand associated, hence cannot be called without a subcommand, contrary to the create command. This is why there is no config.ts in the tree.

# Custom Logger

# .logger(logger: Logger)

Caporal uses Winston for logging. You can provide your own logger using .logger(). Your logger should implement the Logger interface, which basically extends Winston's Logger interface. Checkout src/logger/index.ts to learn more.






 



// [...]
const myLogger = require("./my-logger")
program
  .name("my-proggram")
  .description("My super program")
  .logger(myLogger)
  .action(/* ... */)
// [...]

# Strict mode

# .strict(enabled: boolean)

By default, the program is executed in what we call strict mode, meaning that arguments & options are checked following these rules:

  • No additional arguments are allowed
  • No unknown options are allowed

You can disable the strict mode by calling .strict(false):





 



// [...]
program
  .name("prog")
  .description("My super program description")
  .strict(false)
  .action(/* ... */)
// [...]

Strict mode is inherited by all commands, but can also be overridden by them.

# Auto-casting

# .cast(enabled: boolean)

By default, the program automatically cast numeric and boolean values. To disable this behavior at the program level, use .cast(false).





 



// [...]
program
  .name("prog")
  .description("My super program description")
  .cast(false)
  .action(/* ... */)
// [...]

Auto-casting mode is inherited by all commands, but can also be overridden by them.

# Customizing help

# .help(text: string, options: object)

You can customize the auto-generated help of your program using .help(). Checkout the help section of this guide to learn how.

# Running the program

# .run(args?: string[])

You'll usually run the program using

Caporal will automatically detect command line arguments from process.argv values, but it can be overridden by providing the argv parameter. It returns a Promise of the value returned by the Action triggered.

Be careful

This method returns a Promise. You'll usually ignore the returned promise and call run() like this:







 

[...]
program
  .name("prog")
  .description("My super program description")
  .action(/* ... */)

program.run()

If you do add some .catch() handler to it, Caporal won't display any potential errors that the promise could reject, and will let you the responsibility to do it.

# Programmatic usage

If you ever want to execute you program outside the terminal, from within another app for example, you can use the programmatic API to do so, using the .exec() method.




 







import { program } from "/path/to/your/program"

program
  .exec(args, {my: "options"})
  .then(actionResult => {
    // do something with your action result
  })
  .catch(err) {
    console.error(err)
  }