cobra.js
A small cli framework for Deno. This is heavily inspired on the excellent
Cobra. The framework relies on the Deno's
built-in flags
library for the parsing of
arguments.
The foundation to a good cli is good help. Most of the complexity in Cobra.js is to auto-generate usage information. Cobra.js self-generates help from a command's configuration.
All clis in cobra.js will use commands and flags.
Commands
The basic configuration for a command, specifies the following:
export interface Cmd {
use: string; // name and usage
short?: string; // short description shown in help
long?: string; // long help (cmd action --help)
run: Run;
}
// import the library
import { cli } from "./cmd.ts";
// create a root command
const root = cli("greeting");
// add a subcommand
const hello = root.addCommand({
use: "hello --name string [--strong]",
short: "says hello",
// this is the handler for the command, you get
// the command being executed, any args following a `--`
// and a map of flag names to flags.
run: (cmd, args, flags): Promise<number> => {
const strong = (flags.get("strong")?.value ?? false) ? "!!!" : "";
const n = flags.get("name")?.value ?? "mystery person";
console.log(`hello ${n}${strong}`);
return Promise.resolve(0);
},
});
The return of the command is a Promise<number>
which is a number you can use
to provide to the Deno.exit(n)
function.
Flags
The second component is flags. While parsing arguments can easily be one with
utils such as [parse
](from https://deno.land/std/flags) when creating cli
tools, you'll also want to provide long/short flag names, the type of the data
that you expect, and usage:
export interface Flag {
type: "string" | "boolean" | "number";
name: string;
usage: string;
short: string;
required: boolean;
persistent: boolean;
changed: boolean;
default: null | unknown | unknown[];
value: null | unknown | unknown[];
}
Adding flags to the command above:
hello.addFlag({
short: "n",
name: "name",
type: "string",
usage: "name to say hello to",
});
hello.addFlag({
short: "s",
name: "strong",
type: "boolean",
usage: "say hello strongly",
});
Running your commands
Once you build your command tree and related, flags, you simply call the root
command's execute()
with a list of arguments:
Deno.exit(await root.execute(Deno.args));
Help is built-in
Help is implemented as a persistent flag on the root command, simply passing
-h
or --help
to any command, will display help. The help you get will be
context sensitive. Container commands will list possible subcommands, and their
persistent flags. A leaf command will show usage, flags and persistent flags.
This results in help that looks like this:
> deno run main.ts
greeting
Usage:
greeting [commands]
Available Commands:
goodbye says goodbye
hello says hello
Flags:
-h, --help display greeting's help
> deno run main.ts hello -h
hello --name string [--strong]
Usage:
hello --name string [--strong]
Flags:
-h, --help display greeting's help
-n, --name name to say hello to
-s, --strong say hello strongly