Route Maps
For CLI applications with more than one command, route maps are the way to organize and nest these commands so that they are accessible to users. In order to create a new route map, call the buildRouteMap
function with a mapping of route names to targets. The argument object for the builder accepts the following properties.
Routes
The routes
object is a simple mapping from route names to targets. The route names specified here are affected by the scanner case style config when provided at runtime.
/// commands.ts
const primaryCommand = ...
const altCommand = ...
buildRouteMap({
routes: {
primary: primaryCommand,
alt: altCommand,
},
...
});
When defining routes, a target can be any command or even another route map. When a route map is specified the usage line that is generated for the help text will list out the names of the sub-routes for that map as options.
/// commands.ts
const itemActionsRouteMap = buildRouteMap({
routes: {
create: createItemCommand,
rename: renameItemCommand,
delete: deleteItemCommand,
},
...
});
const root = buildRouteMap({
routes: {
login: loginCommand,
item: itemActionsRouteMap,
},
...
});
The route map configuration above will produce a command with the following behavior:
run --help
USAGE
run login
run item create|rename|delete
run --help
COMMANDS
login Login with auth credentials
item Actions that manipulate items
run item --help
USAGE
run item create
run item rename
run item delete
run item --help
Actions that manipulate items
COMMANDS
create Create a brand new item
rename Rename an existing item
delete Delete an item
Default Command
In some situations, particularly migrations, it can be useful to turn a single command into multiple commands. When a set of inputs resolve to a route map, the default behavior is to print the help text and discard any other inputs. With the defaultCommand
configuration, all inputs that resolve to a route map instead invoke this default command. The default command must be registered as a route in that route map. This prevents the case where it becomes impossible to invoke a command with an argument that matches the name of another route.
Note that this means that all inputs that were considered invalid routes will now be passed as inputs to the default command.
buildRouteMap({
routes: {
foo: fooCommand,
bar: buildRouteMap({
routes: {
old: oldBarCommand,
new: newBarCommand,
},
defaultCommand: "old",
}),
},
});
The route map configuration above will produce a command with the following behavior:
run --help
USAGE
run foo
run bar
run --help
run bar --help
USAGE
run bar old
run bar new
run bar --help
run bar old
OLD BAR COMMAND
run bar new
NEW BAR COMMAND
run bar
OLD BAR COMMAND
Aliases
For one reason or another, it may make sense to expose the same command multiple times under different names. Since the routes are defined by the route map, it is easy to just re-use the same target in multiple places. However, this option exists as an alternative that makes it easier to add aliases for a given route.
/// commands.ts
buildRouteMap({
routes: {
open: openCommand,
close: closeCommand,
},
aliases: {
reopen: "open",
},
...
});
The route map configuration above will produce a command with the following behavior:
run --help
USAGE
run open
run close
run --help
COMMANDS
open Open the connection
close Close the connection
run open --help
USAGE
run open
run open --help
Open the connection
ALIASES
run reopen
Documentation
A base level of documentation is required, and more is always appreciated. All route maps must specify a value for brief
that contains a short line of text to be used when referring to this route throughout the help text of the application.
Optionally, you can further customize the help text for this specific command by including fullDescription
. This will override brief
in the command's help text and can contain multiple lines of text rather than just one. There is also an additional hideRoute
object that allows you to hide certain routes from showing up in documentation.
/// commands.ts
buildRouteMap({
docs: {
brief: "This is a brief description of the routes",
fullDescription: [
"This is the full description of the routes.",
"It should include all of the necessary details about the subcommands within.",
"It will only be displayed to the user in the help text for this route.",
].join("\n"),
hideRoute: {
secret: true,
},
},
...
});
The command configuration above will produce a command with the following behavior:
run --help
USAGE
run subcommand1|subcommand2
run --help
This is the full description of the routes.
It should include all of the necessary details about the subcommands within.
It will only be displayed to the user in the help text for this route.