Skip to content

Defining Commands

Adam Wolfe edited this page Aug 1, 2024 · 1 revision

Overview

To build an Imperative CLI, you must supply command definitions on the definitions or commandModulesGlobs properties in the Imperative configuration document.

Detailed documentation for the command definition can be found in the typedoc of the ICommandDefinition interface.

Definitions

Command definitions are JSON documents that describe the structure of the commands:

"definitions": [{
        "name": "hello",
        "description": "A sample command",
        "type": "command",
        "handler": "/path/to/handler"
}]

Given the example above, if we assume the base CLI executable is samp, we can issue our command with:

samp hello

The handler property must contain a file path to a Node.js require()-able module that uses export default and implements the ICommandHandler interface.

Using Module Globs

You can choose to keep command definitions in separate js or ts files and use the commandModuleGlobs property. You can specify file glob patterns that imperative will use to "search" for command definition modules:

"imperative": {
    "productDisplayName": "Example Command Line Interface",
    "commandModuleGlobs": ["**/cli/*.definition!(.d).*s"],
    "rootCommandDescription": "Welcome to the Example CLI",
    "envVariablePrefix": "SAMPLE_CLI"
}

In the above example, the glob pattern will match command module names under the /cli directory.

Definition Types

Command definitions can be one of two types:

  • Command
    • An issue-able command with a handler
  • Group
    • A command segment that must have children and does not have a handler Groups are handy for creating nested command segments:
"definitions": [{
        "name": "hello",
        "description": "A sample group",
        "type": "group",
        "children": [{
            "name": "world",
            "description": "A sample command",
            "type": "command",
            "handler": "/path/to/handler"
        }]
}]

To issue the world command (assuming the CLI executable is samp), the user would specify:

samp hello world

Imperative tries to guide users through the CLI by offering help if a partial command is issued. In our above example, if the user issued:

samp hello

Imperative would display the help for the hello group, which includes the description and the available commands.

"Passing On" Attributes

At times, you may have a set of ICommandDefinition properties that you wish to apply to all children of a group. For example, you may want to expose the same set of "connection" options to all commands (host, port). You can use the passOn property of the ICommandDefinition to apply the options to all (or some) children.

export const definition: ICommandDefinition = {
    name: "my-group",
    type: "group",
    description: "A sample group",
    children: [
        Cmd1Definition,
        Cmd2Definition,
        Cmd3Definition
    ],
    passOn: [
        {
            property: "options",
            value: [{
                name: "common-option",
                description: "A common option applied to all children",
                type: "string"
            }],
            merge: true,
            ignoreNodes: [
                {type: "group"}
            ]
        }
    ]
};

In the above example, the options property is passed on and "merged" with the options property of all children in the "my-group" group. The effect being, "common-option" is now an option on "Cmd1Definition", "Cmd2Definition", and "Cmd3Definition", assuming they are NOT of type "group" (notice the ignoreNodes specification).

See the ICommandDefinition interface typedoc for details.