Use @clerc/advanced-types for runtime validation
main@clerc/advanced-types package provides advanced runtime types for Clerc. These types can be used to validate and parse data at runtime, extending the capabilities of the core Clerc library.repository·main·Indexed 42 days ago
https://github.com/clercjs/clercA lightweight, full-featured library for building CLI applications in Node.js, Deno, or Bun. It features a plugin-based architecture, a chainable strongly-typed API, and a non-greedy parser supporting dot-nested objects, custom type functions, and automatic camelCase conversion of flags and parameters.
@clerc/advanced-types package provides advanced runtime types for Clerc. These types can be used to validate and parse data at runtime, extending the capabilities of the core Clerc library.Clerc is designed for building CLI applications in Node.js, Deno, or Bun with the following characteristics:
camelCase.Define subcommands by using spaces in the command name string. For example, command("parent child") creates a nested command structure.
To handle cases where no subcommand is specified (running the base script name), define a command with an empty string name "".
// Subcommand
.command("parent child", "A subcommand")
.on("parent child", (ctx) => { ... })
// Root command
.command("", "Root command")
.on("", (ctx) => { ... })You can organize commands and flags into logical sections using the groups option in helpPlugin. This prevents a single long list and makes the help output easier to navigate.
commands: An array of [groupName, groupDescription] tuples. Assign commands to a group using the help: { group: 'groupName' } option in the command definition.flags: An array of [groupName, groupDescription] tuples for command-specific flags.globalFlags: An array of [groupName, groupDescription] tuples for global flags.const cli = Clerc.create()
.scriptName("my-cli")
.use(
helpPlugin({
groups: {
commands: [["dev", "Development Commands"]],
flags: [["input", "Input Options"]],
globalFlags: [["help", "Help Options"]],
},
}),
)
.command("dev", "Start development server", {
help: {
group: "dev",
},
})
.parse();To collect multiple values or count occurrences, use an array type in the type property.
[Type] to collect multiple values into an array.[Boolean] to count how many times a flag appears (e.g., -vvv results in 3).// Array of strings
const { flags: arrayFlags } = parse(["--arr", "a", "--arr", "b"], {
flags: {
arr: { type: [String] },
},
});
// arrayFlags: { arr: ["a", "b"] }
// Counter
const { flags: counterFlags } = parse(["-vvv"], {
flags: {
verbose: { type: [Boolean], alias: "v" },
},
});
// counterFlags: { verbose: 3 }In Clerc, both handler functions and interceptor functions receive a context object as their first parameter. This object provides metadata about the current CLI invocation, including parsed commands, parameters, flags, and unparsed arguments.
While the keys are identical in both, the values may differ:
resolved indicates if a matching command was found.resolved is always true, command is always present, and calledAs always has a value.To allow a flag to accept multiple values or act as a counter, wrap the type function in an array.
type: [Number] allows users to pass the flag multiple times (e.g., -n 1 -n 2), resulting in an array [1, 2].type: [Boolean] allows users to pass the flag multiple times to increment a value (e.g., -c -c -c results in 3).const cli = Cli()
.command("echo", "Echo", {
flags: {
someNumber: {
type: [Number],
short: "n",
description: "Array of numbers",
},
counter: {
type: [Boolean],
description: "A counter flag",
},
},
})
.on("echo", (ctx) => {
// $ node cli.mjs echo -n 1 -n 2 -c -c
console.log(ctx.flags.someNumber); // [1, 2]
console.log(ctx.flags.counter); // 2
})
.parse();Clerc provides several built-in type constructors to validate, convert, and parse values. These can be used in the type property of a flag or parameter configuration.
undefined unless a default is specified.false. Simply mentioning the flag sets it to true.--flag.key value). Default value is {}.const cli = Cli()
.command("example", "description", {
flags: {
name: { type: String, default: "World" },
debug: { type: Boolean },
count: { type: Number },
config: { type: Object }
}
})
.parse();Multiple boolean short flags can be combined into a single argument (e.g., -abc). The last flag in the group can optionally take a value.
-abc is equivalent to a=true, b=true, c=true.-ab val or -abval (if b is not a boolean) allows the last flag to consume the next argument.// -abc => a=true, b=true, c=true
const { flags: merged } = parse(["-abc"], {
flags: {
a: Boolean,
b: Boolean,
c: Boolean,
},
});
// -ab val => a=true, b="val"
const { flags: withValue } = parse(["-ab", "val"], {
flags: {
a: Boolean,
b: String,
},
});Arguments appearing after a -- are not parsed as flags. They are collected in the doubleDash array.
const { flags, doubleDash } = parse(["--foo", "--", "--bar"], {
flags: {
foo: Boolean,
bar: Boolean,
},
});
// flags: { foo: true, bar: false }
// doubleDash: ["--bar"]Interceptors have access to ctx.flags and ctx.parameters via the InterceptorContext.
Important Note on Validation: Required flag and argument validation errors are only thrown before the command handler is called. If you attempt to access a required flag in an interceptor and the user has not provided it, the flag will be missing from ctx.flags, and the validation error will only be thrown when the command handler is eventually invoked.
The @clerc/plugin-completions plugin provides automatic script generation for:
-) and long (--) flags.my-cli <TAB>: Completes available commands.my-cli command <TAB>: Completes subcommands of the specified command.my-cli -<TAB>: Completes global short flags (e.g., -h, -V).my-cli --<TAB>: Completes global long flags.my-cli command -<TAB>: Completes short flags for the specific command (including global flags).my-cli command --<TAB>: Completes all available flags for the specific command (including global flags).