# Validation and casting

Caporal helps you validate user input, e.g. arguments and options, so you don't have to.

There are 2 main solutions for validating those:

  1. Using Caporal-provided validators
  2. Using User validators (your own validators)

# Caporal validators

Those are simple, yet powerful validators. They can help you validate that user input has the expected type (string, boolean, numeric) and cast them automatically. Those are perfect for simple type validations.

# Number validator (program.NUMBER)

Check that the value looks like a numeric one and cast the provided value to a javascript Number.

#!/usr/bin/env node
const { program } = require("@caporal/core")

program
  .argument("<year>", "Year of birth", { validator: program.NUMBER })
  .action(({ logger, args }) => {
    // will print something like: "year: 1985 (type: number)"
    logger.info("year: %d (type: %s)", args.year, typeof args.year)
  })

program.run()

# String validator (program.STRING)

String validator. By default, arguments and options values provided by user input are strings, so this validator is mainly used to prevent Caporal from auto-casting numerical values and boolean-like strings like true or false.

#!/usr/bin/env node
const { program } = require("@caporal/core")

program
  .argument("<postal-code>", "Postal code", { validator: program.STRING })
  .action(({ logger, args }) => {
    // will print something like: "Postal code: 75001 (type: string)"
    logger.info("Postal code: %s (type: %s)", args.postalCode, typeof args.postalCode)
  })

program.run()

# Boolean validator (program.BOOLEAN)

Check that the value looks like a boolean. It accepts values like true, false, yes, no, 0, and 1, and will auto-cast those values to true or false.

#!/usr/bin/env node
const { program } = require("@caporal/core")

program
  .argument("<answer>", "Your answer", { validator: program.BOOLEAN })
  .action(({ logger, args }) => {
    // will print something like: "Answer: true (type: boolean)"
    // even if "1" is provided as argument
    logger.info("Answer: %s (type: %s)", args.answer, typeof args.answer)
  })

program.run()

# Array validator (program.ARRAY)

Convert any provided value to an array. If a string is provided, it will try to split it by commas. If a scalar value is provided, it will convert it to an array containing the value. Moreover, this validator can be combined with another Caporal validator!

#!/usr/bin/env node
const { program } = require("@caporal/core")

program
  // here we combine the 2 validators, to get back an array of strings
  .argument("<years>", "Favorite years(s)", { validator: program.ARRAY | program.STRING })
  .action(({ logger, args }) => {
    // if "2032,2056" is provided, will print: "years: ["2032","2056"] (is array: true)"
    // if "2032" is provided, will print: "years: ["2032"] (is array: true)"
    // if "yes" is provided, will print: "years: ["yes"] (is array: true)"
    logger.info("years: %j (is array: %s)", args.years, Array.isArray(args.years))
  })

program.run()

# User validators

There are 3 types of user validators you can provide

  • Array: an array of allowed values.
  • Function: a function in charge of validating and casting user input.
  • RegExp: a RegExp taht user input should match

# Array validator

This is not to confuse with Caporal Array validator. This one list the only valid values that should be accepted.

#!/usr/bin/env node
const { program } = require("@caporal/core")

program
  .argument("<city>", "Vote for your favorite City", {
    // just provide an array
    validator: ["Paris", "New-York", "Tokyo"],
  })
  .action(({ logger, args }) => {
    // the program will throw an error
    // if user provided city is not in ["Paris", "New-York", "Tokyo"]
    logger.info("Favorite city: %s", args.city)
  })

program.run()

# Function validator

This is certainly the most powerful validator because it allows you the most flexibility. With this validator, you could for example check in a database that a specific ID exists. You can at the same time validate the user input and cast the value. You function must return the validated value. It can be the same as the input, but it can be something else. You can setup an asynchronous validation by returning a Promise from your function. Just throw an error inside your function, or make the returned Promise rejecting to let Caporal know that the validation failed.

Synchronous example

#!/usr/bin/env node
const { program } = require("@caporal/core")

program
  .argument("<year>", "Year of birth", {
    validator: function (value) {
      if (value > new Date().getFullYear()) {
        throw Error("Year cannot be in the future!")
      }
      // cast to Number
      return +value
    },
  })
  .action(({ logger, args }) => {
    // will print something like: "year: 1985 (type: number)"
    logger.info("year: %d (type: %s)", args.year, typeof args.year)
  })

program.run()

Asynchronous example

#!/usr/bin/env node
/* eslint-disable no-undef */
const { program } = require("@caporal/core")

program
  .description("Get username from ID")
  .argument("<id>", "User ID", {
    validator: function (id) {
      return fetch(`/api/user/${id}`).then(() => {
        return id
      })
    },
  })
  .action(({ logger, args }) => {
    logger.info("User ID: %s", args.id)
  })

program.run()