Command argument system with support for required, optional, and variadic arguments, custom processing, validation, choice restrictions, and comprehensive argument handling.
Create new Argument instances programmatically.
/**
* Creates a new Argument instance
* @param name - Argument name (use <name> for required, [name] for optional)
* @param description - Argument description
* @returns New Argument instance
*/
function createArgument(name: string, description?: string): Argument;Usage Examples:
import { createArgument } from 'commander';
const sourceArg = createArgument('<source>', 'source file path');
const destArg = createArgument('[destination]', 'destination file path')
.default('./output');
const filesArg = createArgument('<files...>', 'input files')
.choices(['jpg', 'png', 'gif']);Represents a command argument with validation and processing.
/**
* Represents a command argument with validation and processing
*/
class Argument {
/**
* Initialize an argument with name and description
* @param name - Argument name with angle brackets for required or square brackets for optional
* @param description - Argument description
*/
constructor(name: string, description?: string);
// Properties
description: string;
required: boolean;
variadic: boolean;
defaultValue?: any;
defaultValueDescription?: string;
parseArg?: Function;
argChoices?: string[];
}Add and configure arguments on commands.
interface Command {
/**
* Define a command argument
* @param name - Argument name (<required> or [optional])
* @param description - Argument description
* @param defaultValue - Default value for optional arguments
* @returns this command for chaining
*/
argument(name: string, description?: string, defaultValue?: unknown): this;
/**
* Define a command argument with custom parser
* @param flags - Argument specification
* @param description - Argument description
* @param parseArg - Custom parsing function
* @param defaultValue - Default value
* @returns this command for chaining
*/
argument<T>(flags: string, description: string, parseArg: (value: string, previous: T) => T, defaultValue?: T): this;
/**
* Define multiple arguments from a string
* @param names - Arguments specification (e.g., '<cmd> [env]')
* @returns this command for chaining
*/
arguments(names: string): this;
/**
* Add a prepared Argument instance
* @param arg - Argument instance to add
* @returns this command for chaining
*/
addArgument(arg: Argument): this;
/**
* Factory for creating Argument instances (can be overridden)
* @param name - Argument name
* @param description - Argument description
* @returns New Argument instance
*/
createArgument(name: string, description?: string): Argument;
}Usage Examples:
program
.command('copy')
// Required argument
.argument('<source>', 'source file')
// Optional argument with default
.argument('[destination]', 'destination file', './output')
// Variadic argument
.argument('<files...>', 'files to process')
.action((source, destination, files) => {
console.log(`Copying ${source} to ${destination}`);
console.log('Additional files:', files);
});
// Multiple arguments from string
program
.command('deploy')
.arguments('<environment> [version]')
.action((environment, version) => {
console.log(`Deploying to ${environment}, version ${version || 'latest'}`);
});
// Argument with custom parser
program
.command('resize')
.argument('<size>', 'image size', (value) => {
const [width, height] = value.split('x').map(Number);
if (!width || !height) {
throw new InvalidArgumentError('Size must be in format WIDTHxHEIGHT');
}
return { width, height };
})
.action((size) => {
console.log(`Resizing to ${size.width}x${size.height}`);
});Configure argument behavior, validation, and processing.
interface Argument {
/**
* Get argument name
* @returns Argument name
*/
name(): string;
/**
* Set default value and optional description
* @param value - Default value
* @param description - Description of default value
* @returns this argument for chaining
*/
default(value: unknown, description?: string): this;
/**
* Set custom argument parser
* @param fn - Parsing function
* @returns this argument for chaining
*/
argParser<T>(fn: (value: string, previous: T) => T): this;
/**
* Restrict argument value to specific choices
* @param values - Allowed values
* @returns this argument for chaining
*/
choices(values: readonly string[]): this;
/**
* Make argument required
* @returns this argument for chaining
*/
argRequired(): this;
/**
* Make argument optional
* @returns this argument for chaining
*/
argOptional(): this;
}Usage Examples:
import { createArgument } from 'commander';
// Argument with default value
const outputArg = createArgument('[output]', 'output directory')
.default('./dist', 'current directory');
// Argument with choices
const formatArg = createArgument('<format>', 'output format')
.choices(['json', 'xml', 'yaml']);
// Argument with custom parser
const coordArg = createArgument('<coordinates>', 'x,y coordinates')
.argParser((value) => {
const [x, y] = value.split(',').map(Number);
if (isNaN(x) || isNaN(y)) {
throw new InvalidArgumentError('Coordinates must be in format x,y');
}
return { x, y };
});
// Variadic argument with validation
const urlsArg = createArgument('<urls...>', 'URLs to process')
.argParser((value, previous) => {
try {
new URL(value);
return (previous || []).concat(value);
} catch {
throw new InvalidArgumentError(`Invalid URL: ${value}`);
}
});Different argument patterns and their behaviors.
Required Arguments:
// Simple required argument
.argument('<filename>', 'file to process')
// Required argument with validation
.argument('<port>', 'port number', (value) => {
const port = parseInt(value);
if (port < 1 || port > 65535) {
throw new InvalidArgumentError('Port must be between 1 and 65535');
}
return port;
})Optional Arguments:
// Optional argument
.argument('[output]', 'output directory')
// Optional argument with default
.argument('[config]', 'configuration file', 'config.json')Variadic Arguments:
// Required variadic (at least one)
.argument('<files...>', 'files to process')
// Optional variadic (zero or more)
.argument('[patterns...]', 'search patterns')Access parsed arguments in action handlers.
interface Command {
// Parsed command-line arguments (with options removed)
args: string[];
// Processed arguments after custom parsing and variadic collection
processedArgs: any[];
}Usage Examples:
program
.command('process')
.argument('<input>', 'input file')
.argument('[output]', 'output file')
.argument('[options...]', 'additional options')
.action((input, output, options) => {
// Arguments passed as separate parameters
console.log('Input:', input);
console.log('Output:', output || 'default.out');
console.log('Options:', options || []);
})
.hook('postAction', (thisCommand) => {
// Access via command properties
console.log('Raw args:', thisCommand.args);
console.log('Processed args:', thisCommand.processedArgs);
});Common patterns for argument validation and processing.
File Path Validation:
import { access, constants } from 'fs/promises';
const inputArg = createArgument('<input>', 'input file')
.argParser(async (value) => {
try {
await access(value, constants.R_OK);
return value;
} catch {
throw new InvalidArgumentError(`Cannot read file: ${value}`);
}
});Number Range Validation:
const percentArg = createArgument('<percent>', 'percentage value')
.argParser((value) => {
const num = parseFloat(value);
if (isNaN(num) || num < 0 || num > 100) {
throw new InvalidArgumentError('Percentage must be between 0 and 100');
}
return num;
});Enum Validation:
const logLevelArg = createArgument('<level>', 'log level')
.choices(['error', 'warn', 'info', 'debug', 'trace']);Complex Object Parsing:
const configArg = createArgument('<config>', 'configuration as key=value pairs')
.argParser((value, previous) => {
const config = previous || {};
const [key, val] = value.split('=');
if (!key || val === undefined) {
throw new InvalidArgumentError('Config must be in format key=value');
}
config[key] = val;
return config;
});Handle argument parsing and validation errors.
import { InvalidArgumentError } from 'commander';
// Custom validation with detailed error messages
const dateArg = createArgument('<date>', 'date in YYYY-MM-DD format')
.argParser((value) => {
const date = new Date(value);
if (isNaN(date.getTime())) {
throw new InvalidArgumentError(`Invalid date format: ${value}. Use YYYY-MM-DD format.`);
}
return date;
});
// Validation with suggestions
const commandArg = createArgument('<command>', 'command to execute')
.choices(['start', 'stop', 'restart', 'status'])
.argParser((value) => {
const valid = ['start', 'stop', 'restart', 'status'];
if (!valid.includes(value)) {
const suggestions = valid.filter(cmd => cmd.startsWith(value.slice(0, 2)));
const suggestion = suggestions.length > 0 ? ` Did you mean: ${suggestions.join(', ')}?` : '';
throw new InvalidArgumentError(`Invalid command: ${value}.${suggestion}`);
}
return value;
});// For variadic arguments, the parser is called for each value
const filesArg = createArgument('<files...>', 'input files')
.argParser((value, previous) => {
// 'previous' contains accumulated values from previous calls
const files = previous || [];
// Validate current file
if (!value.endsWith('.txt')) {
throw new InvalidArgumentError(`File must be .txt: ${value}`);
}
// Return accumulated array
return files.concat(value);
});// Default values are used when argument is not provided
const outputArg = createArgument('[output]', 'output file')
.default('output.txt', 'default output file');
// For variadic arguments, default is used when no arguments provided
const patternsArg = createArgument('[patterns...]', 'search patterns')
.default(['**/*.js'], 'all JavaScript files');