Command Paths
By default Clipanion mounts all commands as top-level, meaning that they are selected for execution from the very first token in the command line. This is typically what you want if you build a Posix-style tool, like cp
or curl
, but not when building a CLI application, like yarn
or react-native
.
To help with that, Clipanion supports giving each command one or multiple paths. A path is a list of fixed strings that must be found in order for the command to be selected as an execution candidate. Paths are declared using the static paths
property from each command class:
ts
classInstallCommand extendsCommand {staticpaths = [[`install`], [`i`]];asyncexecute () {// ...}}
ts
classInstallCommand extendsCommand {staticpaths = [[`install`], [`i`]];asyncexecute () {// ...}}
In the example above, we declared a command that accepts any of two paths: install
, or i
. If we wanted the command to also trigger when no path is set (just like the default behavior), we'd use the Command.Default
special path:
ts
import {Command} from 'clipanion';// ---cut---class InstallCommand extends Command {static paths = [[`install`], [`i`], Command.Default];async execute() {// ...}}
ts
import {Command} from 'clipanion';// ---cut---class InstallCommand extends Command {static paths = [[`install`], [`i`], Command.Default];async execute() {// ...}}
tip
You could also use an empty array instead of the Command.Default
helper, but using the provided symbol is a good way to clearly signal to the reader that a command is also an entry point.
Path Overlaps​
It's possible for a path to overlap another one, as long as they aren't strictly identical:
ts
import {Command} from 'clipanion';// ---cut---class FooCommand extends Command {static paths = [[`foo`]];async execute() {// ...}}class FooBarCommand extends Command {static paths = [[`foo`, `bar`]];async execute() {// ...}}
ts
import {Command} from 'clipanion';// ---cut---class FooCommand extends Command {static paths = [[`foo`]];async execute() {// ...}}class FooBarCommand extends Command {static paths = [[`foo`, `bar`]];async execute() {// ...}}
Clipanion will property execute FooBarCommand
when running foo bar
, and FooCommand
when running just foo
. You can even declare positional arguments on FooCommand
if you want, which will get picked up as long as they don't match bar
!
tip
You can even have multiple commands that have identical paths but different options, as long as the user specifies an option unique to one of them (or doesn't if the option is required) when invoking the command! The only caveat is that if they don't Clipanion won't know which version to use and will throw a AmbiguousSyntaxError
.