Skip to content

Subcommands

A subcommand is a named command with its own options, arguments, and handler: listy add-items ..., git commit .... Build one with defineSubcommand and pass it to the CLI.

The subcommand name has to be the first input on the command line.

import { defineSubcommand } from "@staticbolt/args-parser";
export const addItemsCommand = defineSubcommand({
name: "add-items",
aliases: ["ai", "add"],
options: {
// same shape as CLI options
},
arguments: {
// same shape as CLI arguments
},
});
import { defineCLI } from "@staticbolt/args-parser";
import { addItemsCommand } from "./commands/add-items.ts";
import { viewListCommand } from "./commands/view-list.ts";
export const listyCLI = defineCLI({
cliName: "listy",
subcommands: [addItemsCommand, viewListCommand],
});

Names and aliases have to be unique across the whole CLI. A duplicate fails with DefinitionErrorCode.DuplicateDefinitionName.

Metadata

meta only affects help output and generated docs.

const meta = {
// Shown as the usage line in terminal help. Ignored in Markdown.
usage: "listy add-items --list <list> --items <items>",
// Shown next to the subcommand name, in help and in Markdown.
placeholder: "<list> <items>",
// Plain text. Preferred in terminal help when both descriptions exist.
description: "Add items to a list.",
// Markdown. Preferred in generated docs, and formatted for the terminal.
descriptionMarkdown: "Add items to a list. Create one first with **create-list**.",
// Shown at the bottom of terminal help, inside a code block in Markdown.
example: "listy add-items --list groceries --items egg,milk,bread",
// Leaves the subcommand out of help and docs. Useful for internal commands.
hidden: false,
};

Full list in the Subcommand reference.

Handlers

Handlers live on the subcommand, not on the CLI. When the input names a subcommand, only that subcommand's handlers run.

const unsubscribe = addItemsCommand.onExecute(result => {
const { list, items } = result.options;
const positionals = result.positionals;
// Where each value came from, and the raw input.
console.log(result.context.options);
});

Printing help from inside a handler works through the methods that the CLI attaches:

addItemsCommand.onExecute(result => {
if (result.options.help && addItemsCommand.generateSubcommandHelpMessage) {
console.log(addItemsCommand.generateSubcommandHelpMessage(result.subcommand));
return;
}
});

Types

import type { InferInputType, InferOutputType } from "@staticbolt/args-parser";
type AddItemsInput = InferInputType<typeof addItemsCommand>;
type AddItemsOutput = InferOutputType<typeof addItemsCommand>;

The whole family is listed in Type utilities.

Calling one from code

Every subcommand has execute and executeAsync, same as the CLI:

export const executeAddItems = addItemsCommand.execute;

See Programmatic execution.