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:
- Using Caporal-provided validators
- 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
Use program.NUMBER
to check that the value looks like a numeric one and cast it 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
By default, arguments and options values provided by user input are strings, so this validator (program.STRING
) 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
Use program.BOOLEAN
to 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
converts 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 the most powerful validator because it offers greater flexibility. With this validator, you can, for example, check in a database to ensure that a specific ID exists. You can simultaneously validate user input and cast the value. Your function must return the validated value, which can either be the same as the input or something else. You can set up asynchronous validation by returning a Promise
from your function. If an error occurs within your function, or if the returned Promise
is rejected, it will inform Caporal that the validation has 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
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()