Simple yet powerful framework for building command-line apps
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Define commands with arguments, options, and actions. Supports subcommands, aliases, and flexible argument patterns.
Add commands to the CLI with flexible argument patterns and configuration.
/**
* Add a command to the CLI
* @param rawName - Command name with arguments like 'build <entry> [output] [...files]'
* @param description - Command description for help
* @param config - Optional command configuration
* @returns Command instance for method chaining
*/
command(rawName: string, description?: string, config?: CommandConfig): Command;
interface CommandConfig {
/** Allow unknown options in this command */
allowUnknownOptions?: boolean;
/** Don't use option default values in parsed options */
ignoreOptionDefaultValue?: boolean;
}Usage Examples:
// Basic command
cli.command("build", "Build the project");
// Command with required argument
cli.command("deploy <environment>", "Deploy to environment");
// Command with optional argument
cli.command("serve [port]", "Start development server");
// Command with variadic arguments
cli.command("lint [...files]", "Lint files");
// Complex command with mixed arguments
cli.command("build <entry> [output] [...assets]", "Build with assets");
// Command with configuration
cli.command("dev", "Development mode", {
allowUnknownOptions: true,
ignoreOptionDefaultValue: true
});CAC supports various argument patterns using bracket notation.
/**
* Argument patterns in command names:
* - <arg>: Required argument
* - [arg]: Optional argument
* - [...args]: Variadic argument (must be last)
* - Multiple patterns can be combined
*/Examples:
// Required arguments
cli.command("copy <source> <destination>", "Copy files")
.action((source, dest, options) => {
// source and dest are guaranteed to be present
});
// Optional arguments
cli.command("serve [port]", "Start server")
.action((port, options) => {
// port may be undefined
const actualPort = port || 3000;
});
// Variadic arguments
cli.command("delete [...files]", "Delete files")
.action((files, options) => {
// files is an array of all remaining arguments
files.forEach(file => fs.unlinkSync(file));
});Methods available on Command instances for configuration and behavior.
/**
* Set custom usage text for the command
* @param text - Usage text
* @returns Command instance for chaining
*/
usage(text: string): Command;
/**
* Allow unknown options for this command
* @returns Command instance for chaining
*/
allowUnknownOptions(): Command;
/**
* Ignore default values for options in this command
* @returns Command instance for chaining
*/
ignoreOptionDefaultValue(): Command;
/**
* Set version for this command
* @param version - Version string
* @param customFlags - Custom version flags
* @returns Command instance for chaining
*/
version(version: string, customFlags?: string): Command;
/**
* Add an example for this command
* @param example - Example string or function
* @returns Command instance for chaining
*/
example(example: CommandExample): Command;
/**
* Add command alias
* @param name - Alias name (cannot contain brackets)
* @returns Command instance for chaining
*/
alias(name: string): Command;Usage Examples:
cli
.command("build <entry>", "Build application")
.usage("build <entry> [options]")
.alias("compile")
.allowUnknownOptions()
.example("build src/app.js --minify")
.version("2.1.0");Define the behavior when a command is executed.
/**
* Set the action callback for when command is matched
* @param callback - Action function receiving parsed arguments and options
* @returns Command instance for chaining
*/
action(callback: ActionCallback): Command;
type ActionCallback = (
...args: (string | string[] | number | number[])[]
) => any;
/**
* Action callback receives:
* - Individual arguments based on command pattern
* - Final argument is always the options object
* - Variadic arguments are passed as arrays
*/Usage Examples:
// Simple action
cli
.command("hello <name>", "Say hello")
.action((name, options) => {
console.log(`Hello ${name}!`);
});
// Action with multiple arguments
cli
.command("copy <src> <dest>", "Copy file")
.action((src, dest, options) => {
if (options.verbose) {
console.log(`Copying ${src} to ${dest}`);
}
// Copy logic here
});
// Action with variadic arguments
cli
.command("process [...files]", "Process files")
.action((files, options) => {
// files is an array
files.forEach(file => {
console.log(`Processing ${file}`);
});
});
// Async actions are supported
cli
.command("deploy <env>", "Deploy application")
.action(async (env, options) => {
console.log(`Deploying to ${env}...`);
await deployTo(env);
console.log("Deployment complete!");
});Create commands that run when no specific command is matched.
/**
* Create a default command by omitting the command name
* Use brackets to define arguments for the default command
*/Usage Examples:
// Default command with arguments
cli
.command("[...files]", "Process files")
.action((files, options) => {
if (files.length === 0) {
console.log("No files specified");
return;
}
// Process files
});
// Default command with options only
cli
.command("", "Default behavior")
.option("--config <file>", "Config file")
.action((options) => {
// Default behavior
});Access command state and metadata.
interface Command {
/** Command options array */
readonly options: Option[];
/** Command alias names */
readonly aliasNames: string[];
/** Parsed command name (without brackets) */
readonly name: string;
/** Parsed command arguments with metadata */
readonly args: CommandArg[];
/** Command action callback */
readonly commandAction?: ActionCallback;
/** Custom usage text */
readonly usageText?: string;
/** Command version */
readonly versionNumber?: string;
/** Command examples */
readonly examples: CommandExample[];
/** Reference to CLI instance */
readonly cli: CAC;
/** Check if this is the default command */
readonly isDefaultCommand: boolean;
/** Check if this is the global command */
readonly isGlobalCommand: boolean;
}
interface CommandArg {
required: boolean;
value: string;
variadic: boolean;
}Methods for runtime validation and checking.
/**
* Check if a command name matches this command
* @param name - Command name to test
* @returns True if name matches command or aliases
*/
isMatched(name: string): boolean;
/**
* Check if an option is registered in this command
* @param name - Option name to check
* @returns Option instance if found, undefined otherwise
*/
hasOption(name: string): Option | undefined;
/**
* Check if the parsed arguments meet required argument count
* Throws CACError if insufficient required arguments provided
*/
checkRequiredArgs(): void;
/**
* Check if the parsed options contain any unknown options
* Throws CACError for unknown options (unless allowUnknownOptions is true)
*/
checkUnknownOptions(): void;
/**
* Check if required string-type options have values
* Throws CACError for missing required option values
*/
checkOptionValue(): void;
/**
* Output help message for this command
*/
outputHelp(): void;
/**
* Output version for this command
*/
outputVersion(): void;// Error handling example
try {
cli.parse();
} catch (error) {
if (error instanceof CACError) {
console.error(`Command error: ${error.message}`);
}
process.exit(1);
}Install with Tessl CLI
npx tessl i tessl/npm-cac