Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:04:14 +08:00
commit 70c36b5eff
248 changed files with 47482 additions and 0 deletions

View File

@@ -0,0 +1,435 @@
---
name: Commander.js Patterns
description: Commander.js CLI framework patterns including Command class, options, arguments, nested subcommands, and Option class usage. Use when building Node.js CLIs, implementing Commander.js commands, creating TypeScript CLI tools, adding command options/arguments, or when user mentions Commander.js, CLI commands, command options, or nested subcommands.
allowed-tools: Read, Write, Bash, Edit
---
# Commander.js Patterns Skill
Provides comprehensive Commander.js patterns, templates, and examples for building robust Node.js CLI applications with TypeScript support.
## Overview
Commander.js is the complete solution for Node.js command-line interfaces. This skill provides battle-tested patterns for:
- Command class instantiation and configuration
- Options with flags, choices, and defaults
- Arguments (required, optional, variadic)
- Nested subcommands and command hierarchies
- Option class with advanced validation
- Action handlers and middleware
- Error handling and validation
## Instructions
### Basic Command Setup
1. **Create program instance:**
```typescript
import { Command } from 'commander';
const program = new Command();
program
.name('mycli')
.description('CLI description')
.version('1.0.0');
```
2. **Add simple command:**
```typescript
program
.command('init')
.description('Initialize project')
.action(() => {
// Command logic
});
```
3. **Parse arguments:**
```typescript
program.parse();
```
### Command with Options
Use options for named flags with values:
```typescript
program
.command('deploy')
.description('Deploy application')
.option('-e, --env <environment>', 'target environment', 'dev')
.option('-f, --force', 'force deployment', false)
.option('-v, --verbose', 'verbose output')
.action((options) => {
console.log('Environment:', options.env);
console.log('Force:', options.force);
console.log('Verbose:', options.verbose);
});
```
### Command with Arguments
Use arguments for positional parameters:
```typescript
program
.command('deploy <environment>')
.description('Deploy to environment')
.argument('<environment>', 'target environment')
.argument('[region]', 'optional region', 'us-east-1')
.action((environment, region, options) => {
console.log(`Deploying to ${environment} in ${region}`);
});
```
### Option Class Usage
For advanced option configuration:
```typescript
import { Command, Option } from 'commander';
program
.command('deploy')
.addOption(
new Option('-m, --mode <mode>', 'deployment mode')
.choices(['fast', 'safe', 'rollback'])
.default('safe')
.makeOptionMandatory()
)
.addOption(
new Option('-r, --replicas <count>', 'replica count')
.argParser(parseInt)
.default(3)
)
.action((options) => {
console.log(`Mode: ${options.mode}, Replicas: ${options.replicas}`);
});
```
### Nested Subcommands
Create command hierarchies:
```typescript
const config = program
.command('config')
.description('Manage configuration');
config
.command('get <key>')
.description('Get config value')
.action((key) => {
console.log(`Config ${key}:`, getConfig(key));
});
config
.command('set <key> <value>')
.description('Set config value')
.action((key, value) => {
setConfig(key, value);
console.log(`✓ Set ${key} = ${value}`);
});
config
.command('list')
.description('List all config')
.action(() => {
console.log(getAllConfig());
});
```
### Variadic Arguments
Accept multiple values:
```typescript
program
.command('add <items...>')
.description('Add multiple items')
.action((items) => {
console.log('Adding items:', items);
});
// Usage: mycli add item1 item2 item3
```
### Custom Argument Parsing
Transform argument values:
```typescript
program
.command('wait <delay>')
.description('Wait for specified time')
.argument('<delay>', 'delay in seconds', parseFloat)
.action((delay) => {
console.log(`Waiting ${delay} seconds...`);
});
```
### Global Options
Options available to all commands:
```typescript
program
.option('-c, --config <path>', 'config file path')
.option('-v, --verbose', 'verbose output')
.option('--no-color', 'disable colors');
program
.command('deploy')
.action((options, command) => {
const globalOpts = command.parent?.opts();
console.log('Config:', globalOpts?.config);
console.log('Verbose:', globalOpts?.verbose);
});
```
### Error Handling
```typescript
program
.command('deploy <environment>')
.action((environment) => {
if (!['dev', 'staging', 'prod'].includes(environment)) {
throw new Error(`Invalid environment: ${environment}`);
}
// Deploy logic
});
program.exitOverride();
try {
program.parse();
} catch (err) {
console.error('Error:', err.message);
process.exit(1);
}
```
## Available Scripts
- **validate-commander-structure.sh**: Validates Commander.js CLI structure and patterns
- **generate-command.sh**: Scaffolds new command with options and arguments
- **generate-subcommand.sh**: Creates nested subcommand structure
- **test-commander-cli.sh**: Tests CLI commands with various inputs
- **extract-command-help.sh**: Extracts help text from CLI for documentation
## Templates
### TypeScript Templates
- **basic-commander.ts**: Minimal Commander.js setup
- **command-with-options.ts**: Command with various option types
- **command-with-arguments.ts**: Command with required/optional arguments
- **nested-subcommands.ts**: Multi-level command hierarchy
- **option-class-advanced.ts**: Advanced Option class usage
- **full-cli-example.ts**: Complete CLI with all patterns
- **commander-with-inquirer.ts**: Interactive prompts integration
- **commander-with-validation.ts**: Input validation patterns
### JavaScript Templates
- **basic-commander.js**: ES modules Commander.js setup
- **commonjs-commander.js**: CommonJS Commander.js setup
### Configuration Templates
- **tsconfig.commander.json**: TypeScript config for Commander.js projects
- **package.json.template**: Package.json with Commander.js dependencies
## Examples
- **basic-usage.md**: Simple CLI with 2-3 commands
- **options-arguments-demo.md**: Comprehensive options and arguments examples
- **nested-commands-demo.md**: Building command hierarchies
- **advanced-option-class.md**: Option class validation and parsing
- **interactive-cli.md**: Combining Commander.js with Inquirer.js
- **error-handling-patterns.md**: Robust error handling strategies
- **testing-commander-cli.md**: Unit and integration testing patterns
## Commander.js Key Concepts
### Command Class
```typescript
new Command()
.name('cli-name')
.description('CLI description')
.version('1.0.0')
.command('subcommand')
```
### Option Types
- **Flag option**: `-v, --verbose` (boolean)
- **Value option**: `-p, --port <port>` (required value)
- **Optional value**: `-p, --port [port]` (optional value)
- **Negatable**: `--no-color` (inverse boolean)
- **Variadic**: `--files <files...>` (multiple values)
### Argument Types
- **Required**: `<name>`
- **Optional**: `[name]`
- **Variadic**: `<items...>` or `[items...]`
### Option Class Methods
- `.choices(['a', 'b', 'c'])`: Restrict to specific values
- `.default(value)`: Set default value
- `.argParser(fn)`: Custom parsing function
- `.makeOptionMandatory()`: Require option
- `.conflicts(option)`: Mutually exclusive options
- `.implies(option)`: Implies another option
- `.env(name)`: Read from environment variable
### Action Handler Signatures
```typescript
// No arguments
.action(() => {})
// With options only
.action((options) => {})
// With arguments
.action((arg1, arg2, options) => {})
// With command reference
.action((options, command) => {})
```
## Pattern Recipes
### Pattern 1: Simple CLI with Subcommands
Use template: `templates/basic-commander.ts`
### Pattern 2: CLI with Rich Options
Use template: `templates/option-class-advanced.ts`
### Pattern 3: Interactive CLI
Use template: `templates/commander-with-inquirer.ts`
### Pattern 4: CLI with Validation
Use template: `templates/commander-with-validation.ts`
### Pattern 5: Multi-level Commands
Use template: `templates/nested-subcommands.ts`
## Integration with Other Tools
### With Inquirer.js (Interactive Prompts)
```typescript
import inquirer from 'inquirer';
program
.command('setup')
.action(async () => {
const answers = await inquirer.prompt([
{ type: 'input', name: 'name', message: 'Project name:' },
{ type: 'list', name: 'template', message: 'Template:', choices: ['basic', 'advanced'] }
]);
// Use answers
});
```
### With Chalk (Colored Output)
```typescript
import chalk from 'chalk';
program
.command('deploy')
.action(() => {
console.log(chalk.green('✓ Deployment successful'));
console.log(chalk.red('✗ Deployment failed'));
});
```
### With Ora (Spinners)
```typescript
import ora from 'ora';
program
.command('build')
.action(async () => {
const spinner = ora('Building...').start();
await build();
spinner.succeed('Build complete');
});
```
## Best Practices
1. **Use Option class for complex options**: Provides better validation and type safety
2. **Keep action handlers thin**: Delegate to separate functions
3. **Provide clear descriptions**: Help users understand commands
4. **Set sensible defaults**: Reduce required options
5. **Validate early**: Check inputs before processing
6. **Handle errors gracefully**: Provide helpful error messages
7. **Use TypeScript**: Better type safety and IDE support
8. **Test thoroughly**: Unit test commands and options
9. **Document examples**: Show common usage patterns
10. **Version your CLI**: Use semantic versioning
## Common Patterns
### Pattern: Config Command Group
```typescript
const config = program.command('config');
config.command('get <key>').action(getConfig);
config.command('set <key> <value>').action(setConfig);
config.command('list').action(listConfig);
config.command('delete <key>').action(deleteConfig);
```
### Pattern: CRUD Commands
```typescript
program.command('create <name>').action(create);
program.command('read <id>').action(read);
program.command('update <id>').action(update);
program.command('delete <id>').action(deleteItem);
program.command('list').action(list);
```
### Pattern: Deploy with Environments
```typescript
program
.command('deploy')
.addOption(new Option('-e, --env <env>').choices(['dev', 'staging', 'prod']))
.option('-f, --force', 'force deployment')
.action(deploy);
```
## Troubleshooting
### Issue: Options not parsed
**Solution**: Ensure `program.parse()` is called
### Issue: Arguments not received
**Solution**: Check action handler signature matches argument count
### Issue: Subcommands not working
**Solution**: Verify subcommand is attached before `parse()`
### Issue: TypeScript errors
**Solution**: Install `@types/node` and configure tsconfig
### Issue: Help not showing
**Solution**: Commander.js auto-generates help from descriptions
## Success Criteria
✅ Command structure follows Commander.js conventions
✅ Options and arguments properly typed
✅ Help text is clear and descriptive
✅ Error handling covers edge cases
✅ CLI tested with various inputs
✅ TypeScript compiles without errors
✅ Commands execute as expected
## Related Skills
- `click-patterns` - Python Click framework patterns
- `typer-patterns` - Python Typer framework patterns
- `clap-patterns` - Rust Clap framework patterns
---
**Skill Type**: Framework Patterns + Code Templates
**Language**: TypeScript/JavaScript (Node.js)
**Framework**: Commander.js v12+
**Auto-invocation**: Yes (via description matching)

View File

@@ -0,0 +1,513 @@
# Advanced Option Class Usage
Comprehensive examples of the Option class for advanced option handling.
## Basic Option Class
```typescript
import { Command, Option } from 'commander';
const program = new Command();
program
.command('deploy')
.addOption(
new Option('-e, --env <environment>', 'target environment')
.choices(['dev', 'staging', 'prod'])
.default('dev')
)
.action((options) => {
console.log('Environment:', options.env);
});
program.parse();
```
## Option with Choices
```typescript
import { Command, Option } from 'commander';
program
.command('log')
.addOption(
new Option('-l, --level <level>', 'log level')
.choices(['debug', 'info', 'warn', 'error'])
.default('info')
)
.addOption(
new Option('-f, --format <format>', 'output format')
.choices(['json', 'yaml', 'table'])
.default('table')
)
.action((options) => {
console.log(`Logging at ${options.level} level in ${options.format} format`);
});
```
Usage:
```bash
mycli log --level debug --format json
mycli log --level invalid # Error: invalid choice
```
## Mandatory Options
```typescript
import { Command, Option } from 'commander';
program
.command('deploy')
.addOption(
new Option('-t, --token <token>', 'API token')
.makeOptionMandatory()
)
.addOption(
new Option('-e, --env <environment>', 'environment')
.choices(['dev', 'staging', 'prod'])
.makeOptionMandatory()
)
.action((options) => {
console.log('Deploying with token:', options.token);
console.log('Environment:', options.env);
});
```
Usage:
```bash
mycli deploy # Error: required option missing
mycli deploy --token abc --env prod # ✓ Works
```
## Options from Environment Variables
```typescript
import { Command, Option } from 'commander';
program
.command('deploy')
.addOption(
new Option('-t, --token <token>', 'API token')
.env('API_TOKEN')
.makeOptionMandatory()
)
.addOption(
new Option('-u, --api-url <url>', 'API URL')
.env('API_URL')
.default('https://api.example.com')
)
.action((options) => {
console.log('Token:', options.token);
console.log('API URL:', options.apiUrl);
});
```
Usage:
```bash
export API_TOKEN=abc123
export API_URL=https://custom-api.com
mycli deploy # Uses environment variables
mycli deploy --token xyz # CLI arg overrides env var
```
## Custom Argument Parsers
```typescript
import { Command, Option } from 'commander';
program
.command('scale')
.addOption(
new Option('-r, --replicas <count>', 'number of replicas')
.argParser((value) => {
const count = parseInt(value, 10);
if (isNaN(count) || count < 1 || count > 100) {
throw new Error('Replicas must be between 1 and 100');
}
return count;
})
.default(3)
)
.addOption(
new Option('-m, --memory <size>', 'memory limit')
.argParser((value) => {
// Parse sizes like "512M", "2G"
const match = value.match(/^(\d+)([MG])$/i);
if (!match) {
throw new Error('Invalid memory format (use 512M or 2G)');
}
const [, num, unit] = match;
const mb = parseInt(num) * (unit.toUpperCase() === 'G' ? 1024 : 1);
return mb;
})
.default(512)
)
.action((options) => {
console.log('Replicas:', options.replicas);
console.log('Memory:', options.memory, 'MB');
});
```
Usage:
```bash
mycli scale --replicas 5 --memory 2G
# Replicas: 5
# Memory: 2048 MB
```
## Conflicting Options
```typescript
import { Command, Option } from 'commander';
program
.command('build')
.addOption(
new Option('--cache', 'enable caching')
.conflicts('noCache')
)
.addOption(
new Option('--no-cache', 'disable caching')
.conflicts('cache')
)
.addOption(
new Option('--watch', 'watch mode')
.conflicts('production')
)
.addOption(
new Option('--production', 'production build')
.conflicts('watch')
)
.action((options) => {
console.log('Cache:', options.cache);
console.log('Watch:', options.watch);
console.log('Production:', options.production);
});
```
Usage:
```bash
mycli build --cache # ✓ Works
mycli build --no-cache # ✓ Works
mycli build --cache --no-cache # ✗ Error: conflicting options
mycli build --watch --production # ✗ Error: conflicting options
```
## Option Implies
```typescript
import { Command, Option } from 'commander';
program
.command('server')
.addOption(
new Option('--ssl', 'enable SSL')
.implies({ sslCert: './cert.pem', sslKey: './key.pem' })
)
.addOption(
new Option('--ssl-cert <path>', 'SSL certificate path')
)
.addOption(
new Option('--ssl-key <path>', 'SSL key path')
)
.addOption(
new Option('--secure', 'secure mode')
.implies({ ssl: true, httpsOnly: true })
)
.addOption(
new Option('--https-only', 'enforce HTTPS')
)
.action((options) => {
console.log('SSL:', options.ssl);
console.log('SSL Cert:', options.sslCert);
console.log('SSL Key:', options.sslKey);
console.log('HTTPS Only:', options.httpsOnly);
});
```
Usage:
```bash
mycli server --ssl
# SSL: true
# SSL Cert: ./cert.pem
# SSL Key: ./key.pem
mycli server --secure
# SSL: true
# HTTPS Only: true
```
## Preset Configurations
```typescript
import { Command, Option } from 'commander';
program
.command('deploy')
.addOption(
new Option('--preset <preset>', 'use preset configuration')
.choices(['minimal', 'standard', 'enterprise'])
.argParser((value) => {
const presets = {
minimal: {
replicas: 1,
memory: '256M',
cpu: '0.25',
autoScaling: false,
},
standard: {
replicas: 3,
memory: '512M',
cpu: '0.5',
autoScaling: true,
},
enterprise: {
replicas: 10,
memory: '2G',
cpu: '2',
autoScaling: true,
loadBalancer: true,
monitoring: true,
},
};
return presets[value as keyof typeof presets];
})
)
.action((options) => {
if (options.preset) {
console.log('Using preset configuration:');
console.log(JSON.stringify(options.preset, null, 2));
}
});
```
Usage:
```bash
mycli deploy --preset enterprise
# Using preset configuration:
# {
# "replicas": 10,
# "memory": "2G",
# "cpu": "2",
# "autoScaling": true,
# "loadBalancer": true,
# "monitoring": true
# }
```
## Hidden Options (Debug/Internal)
```typescript
import { Command, Option } from 'commander';
program
.command('build')
.option('-p, --production', 'production build')
.addOption(
new Option('--debug', 'enable debug mode')
.hideHelp()
)
.addOption(
new Option('--internal-api', 'use internal API')
.hideHelp()
.default(false)
)
.action((options) => {
if (options.debug) {
console.log('Debug mode enabled');
console.log('All options:', options);
}
});
```
## Complex Validation
```typescript
import { Command, Option } from 'commander';
program
.command('backup')
.addOption(
new Option('-s, --schedule <cron>', 'backup schedule (cron format)')
.argParser((value) => {
// Validate cron expression
const cronRegex = /^(\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\*|([0-9]|1[0-9]|2[0-3])|\*\/([0-9]|1[0-9]|2[0-3])) (\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\*|([1-9]|1[0-2])|\*\/([1-9]|1[0-2])) (\*|([0-6])|\*\/([0-6]))$/;
if (!cronRegex.test(value)) {
throw new Error('Invalid cron expression');
}
return value;
})
)
.addOption(
new Option('-r, --retention <days>', 'backup retention in days')
.argParser((value) => {
const days = parseInt(value, 10);
if (isNaN(days) || days < 1 || days > 365) {
throw new Error('Retention must be between 1 and 365 days');
}
return days;
})
.default(30)
)
.action((options) => {
console.log('Schedule:', options.schedule);
console.log('Retention:', options.retention, 'days');
});
```
Usage:
```bash
mycli backup --schedule "0 2 * * *" --retention 90
# Schedule: 0 2 * * *
# Retention: 90 days
```
## Cumulative Options
```typescript
import { Command, Option } from 'commander';
program
.command('log')
.addOption(
new Option('-v, --verbose', 'increase verbosity')
.argParser((value, previous) => {
return previous + 1;
})
.default(0)
)
.action((options) => {
console.log('Verbosity level:', options.verbose);
// 0 = normal
// 1 = verbose (-v)
// 2 = very verbose (-vv)
// 3 = debug (-vvv)
});
```
Usage:
```bash
mycli log # verbosity: 0
mycli log -v # verbosity: 1
mycli log -vv # verbosity: 2
mycli log -vvv # verbosity: 3
```
## Complete Example
```typescript
#!/usr/bin/env node
import { Command, Option } from 'commander';
import chalk from 'chalk';
const program = new Command();
program
.name('deploy-cli')
.version('1.0.0');
program
.command('deploy')
.description('Deploy application with advanced options')
// Required with choices
.addOption(
new Option('-e, --env <environment>', 'deployment environment')
.choices(['dev', 'staging', 'prod'])
.makeOptionMandatory()
)
// Environment variable with validation
.addOption(
new Option('-t, --token <token>', 'API token')
.env('DEPLOY_TOKEN')
.makeOptionMandatory()
.argParser((value) => {
if (value.length < 32) {
throw new Error('Token must be at least 32 characters');
}
return value;
})
)
// Custom parser with unit conversion
.addOption(
new Option('-m, --memory <size>', 'memory allocation')
.argParser((value) => {
const match = value.match(/^(\d+)([MG])$/i);
if (!match) {
throw new Error('Memory must be in format: 512M or 2G');
}
const [, num, unit] = match;
return parseInt(num) * (unit.toUpperCase() === 'G' ? 1024 : 1);
})
.default(512)
)
// Conflicting options
.addOption(
new Option('--fast', 'fast deployment (skip tests)')
.conflicts('safe')
)
.addOption(
new Option('--safe', 'safe deployment (full tests)')
.conflicts('fast')
.default(true)
)
// Implies relationship
.addOption(
new Option('--production-mode', 'enable production optimizations')
.implies({ env: 'prod', safe: true, monitoring: true })
)
.addOption(
new Option('--monitoring', 'enable monitoring')
)
// Hidden debug option
.addOption(
new Option('--debug', 'debug mode')
.hideHelp()
)
.action((options) => {
console.log(chalk.blue('Deployment Configuration:'));
console.log('Environment:', chalk.yellow(options.env));
console.log('Token:', options.token ? chalk.green('***set***') : chalk.red('missing'));
console.log('Memory:', `${options.memory}MB`);
console.log('Mode:', options.fast ? 'fast' : 'safe');
console.log('Production Mode:', options.productionMode || false);
console.log('Monitoring:', options.monitoring || false);
if (options.debug) {
console.log(chalk.gray('\nDebug - All options:'));
console.log(chalk.gray(JSON.stringify(options, null, 2)));
}
console.log(chalk.green('\n✓ Deployment started'));
});
program.parse();
```
Usage:
```bash
export DEPLOY_TOKEN=abc123xyz789abc123xyz789abc12345
# Basic deployment
deploy-cli deploy --env staging
# Custom memory
deploy-cli deploy --env prod --memory 4G
# Fast mode
deploy-cli deploy --env dev --fast
# Production mode (implies multiple settings)
deploy-cli deploy --production-mode
# Debug
deploy-cli deploy --env dev --debug
```

View File

@@ -0,0 +1,284 @@
# Basic Commander.js Usage
Simple examples demonstrating core Commander.js features.
## Example 1: Simple CLI with Commands
```typescript
import { Command } from 'commander';
const program = new Command();
program
.name('mycli')
.description('My CLI tool')
.version('1.0.0');
// Command without options
program
.command('init')
.description('Initialize project')
.action(() => {
console.log('Initializing project...');
});
// Command with options
program
.command('build')
.description('Build project')
.option('-w, --watch', 'watch mode')
.action((options) => {
console.log('Building...');
if (options.watch) {
console.log('Watch mode enabled');
}
});
program.parse();
```
**Usage:**
```bash
mycli init
mycli build
mycli build --watch
mycli --help
mycli --version
```
## Example 2: Command with Arguments
```typescript
import { Command } from 'commander';
const program = new Command();
program
.name('mycli')
.version('1.0.0');
program
.command('greet <name>')
.description('Greet someone')
.action((name) => {
console.log(`Hello, ${name}!`);
});
program
.command('add <a> <b>')
.description('Add two numbers')
.action((a, b) => {
const sum = parseInt(a) + parseInt(b);
console.log(`${a} + ${b} = ${sum}`);
});
program.parse();
```
**Usage:**
```bash
mycli greet Alice
# Output: Hello, Alice!
mycli add 5 3
# Output: 5 + 3 = 8
```
## Example 3: Options with Different Types
```typescript
import { Command } from 'commander';
const program = new Command();
program
.name('mycli')
.version('1.0.0');
program
.command('serve')
.description('Start development server')
// Boolean flag
.option('-o, --open', 'open browser', false)
// Option with value
.option('-p, --port <port>', 'port number', '3000')
// Option with default
.option('-h, --host <host>', 'hostname', 'localhost')
// Negatable option
.option('--no-color', 'disable colors')
.action((options) => {
console.log(`Server running at http://${options.host}:${options.port}`);
console.log('Open browser:', options.open);
console.log('Colors:', options.color);
});
program.parse();
```
**Usage:**
```bash
mycli serve
# Uses defaults
mycli serve --port 8080
# Uses custom port
mycli serve --open --no-color
# Opens browser and disables colors
```
## Example 4: Global Options
```typescript
import { Command } from 'commander';
const program = new Command();
program
.name('mycli')
.version('1.0.0')
// Global options
.option('-v, --verbose', 'verbose output')
.option('-c, --config <path>', 'config file path');
program
.command('deploy')
.action((options, command) => {
const globalOpts = command.parent?.opts();
console.log('Deploying...');
if (globalOpts?.verbose) {
console.log('Verbose mode enabled');
console.log('Config:', globalOpts.config);
}
});
program.parse();
```
**Usage:**
```bash
mycli deploy
# Normal output
mycli --verbose deploy
# Verbose output
mycli --verbose --config ./config.json deploy
# Verbose with custom config
```
## Example 5: Multiple Commands
```typescript
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
program.name('mycli').version('1.0.0');
program
.command('init')
.description('Initialize new project')
.action(() => {
console.log(chalk.green('✓ Project initialized'));
});
program
.command('build')
.description('Build project')
.action(() => {
console.log(chalk.blue('Building...'));
console.log(chalk.green('✓ Build complete'));
});
program
.command('test')
.description('Run tests')
.action(() => {
console.log(chalk.blue('Running tests...'));
console.log(chalk.green('✓ All tests passed'));
});
program
.command('deploy')
.description('Deploy to production')
.action(() => {
console.log(chalk.yellow('Deploying...'));
console.log(chalk.green('✓ Deployed'));
});
program.parse();
```
**Usage:**
```bash
mycli init
mycli build
mycli test
mycli deploy
mycli --help # Shows all commands
```
## Running the Examples
### Setup
1. Create a new project:
```bash
mkdir my-cli
cd my-cli
npm init -y
```
2. Install dependencies:
```bash
npm install commander chalk
npm install -D typescript @types/node tsx
```
3. Configure TypeScript:
```bash
npx tsc --init --target ES2022 --module ESNext
```
4. Create `src/index.ts` with any example above
5. Run with tsx:
```bash
npx tsx src/index.ts --help
```
### Building for Production
```bash
# Build TypeScript
npx tsc
# Run compiled version
node dist/index.js
```
### Making it Executable
Add to `package.json`:
```json
{
"bin": {
"mycli": "./dist/index.js"
}
}
```
Add shebang to top of source file:
```typescript
#!/usr/bin/env node
import { Command } from 'commander';
// ... rest of code
```
Install globally for testing:
```bash
npm link
mycli --help
```

View File

@@ -0,0 +1,558 @@
# Nested Commands Demo
Examples of building multi-level command hierarchies with Commander.js.
## Basic Nested Commands
```typescript
import { Command } from 'commander';
const program = new Command();
program.name('mycli').version('1.0.0');
// Create parent command
const config = program.command('config').description('Configuration management');
// Add subcommands
config
.command('get <key>')
.description('Get config value')
.action((key) => {
console.log(`Getting ${key}...`);
});
config
.command('set <key> <value>')
.description('Set config value')
.action((key, value) => {
console.log(`Setting ${key} = ${value}`);
});
config
.command('list')
.description('List all config')
.action(() => {
console.log('Listing config...');
});
program.parse();
```
Usage:
```bash
mycli config get api-key
mycli config set api-key abc123
mycli config list
mycli config --help # Shows subcommands
```
## Multiple Command Groups
```typescript
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
program.name('mycli').version('1.0.0');
// Database commands
const db = program.command('db').description('Database operations');
db.command('migrate')
.description('Run migrations')
.option('-d, --dry-run', 'show migrations')
.action((options) => {
console.log(chalk.blue('Running migrations...'));
});
db.command('seed')
.description('Seed database')
.option('-e, --env <env>', 'environment', 'dev')
.action((options) => {
console.log(chalk.blue(`Seeding ${options.env} database...`));
});
db.command('reset')
.description('Reset database')
.option('-f, --force', 'skip confirmation')
.action((options) => {
if (!options.force) {
console.log(chalk.red('Use --force to confirm'));
return;
}
console.log(chalk.yellow('Resetting database...'));
});
// User commands
const user = program.command('user').description('User management');
user
.command('list')
.description('List users')
.option('-p, --page <page>', 'page number', '1')
.action((options) => {
console.log(`Listing users (page ${options.page})`);
});
user
.command('create <username> <email>')
.description('Create user')
.action((username, email) => {
console.log(chalk.green(`Created user: ${username} (${email})`));
});
user
.command('delete <userId>')
.description('Delete user')
.option('-f, --force', 'skip confirmation')
.action((userId, options) => {
console.log(chalk.red(`Deleted user: ${userId}`));
});
// Cache commands
const cache = program.command('cache').description('Cache management');
cache
.command('clear')
.description('Clear cache')
.option('-a, --all', 'clear all caches')
.action((options) => {
console.log('Clearing cache...');
});
cache
.command('stats')
.description('Show cache statistics')
.action(() => {
console.log('Cache stats:');
console.log(' Size: 1.2 GB');
console.log(' Hits: 89%');
});
program.parse();
```
Usage:
```bash
mycli db migrate --dry-run
mycli db seed --env prod
mycli db reset --force
mycli user list --page 2
mycli user create john john@example.com
mycli user delete 123 --force
mycli cache clear --all
mycli cache stats
```
## Three-Level Nesting
```typescript
import { Command } from 'commander';
const program = new Command();
program.name('mycli').version('1.0.0');
// Level 1: Cloud
const cloud = program.command('cloud').description('Cloud operations');
// Level 2: AWS
const aws = cloud.command('aws').description('AWS operations');
// Level 3: EC2
const ec2 = aws.command('ec2').description('EC2 operations');
ec2
.command('list')
.description('List EC2 instances')
.action(() => {
console.log('Listing EC2 instances...');
});
ec2
.command('start <instanceId>')
.description('Start EC2 instance')
.action((instanceId) => {
console.log(`Starting instance ${instanceId}...`);
});
ec2
.command('stop <instanceId>')
.description('Stop EC2 instance')
.action((instanceId) => {
console.log(`Stopping instance ${instanceId}...`);
});
// Level 3: S3
const s3 = aws.command('s3').description('S3 operations');
s3.command('list')
.description('List S3 buckets')
.action(() => {
console.log('Listing S3 buckets...');
});
s3.command('upload <file> <bucket>')
.description('Upload to S3')
.action((file, bucket) => {
console.log(`Uploading ${file} to ${bucket}...`);
});
// Level 2: Azure
const azure = cloud.command('azure').description('Azure operations');
azure
.command('vm-list')
.description('List VMs')
.action(() => {
console.log('Listing Azure VMs...');
});
program.parse();
```
Usage:
```bash
mycli cloud aws ec2 list
mycli cloud aws ec2 start i-123456
mycli cloud aws s3 list
mycli cloud aws s3 upload file.txt my-bucket
mycli cloud azure vm-list
```
## CRUD Pattern
```typescript
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
program.name('api-cli').version('1.0.0');
function createResourceCommands(name: string) {
const resource = program.command(name).description(`${name} management`);
resource
.command('list')
.description(`List all ${name}`)
.option('-p, --page <page>', 'page number', '1')
.option('-l, --limit <limit>', 'items per page', '10')
.action((options) => {
console.log(chalk.blue(`Listing ${name}...`));
console.log(`Page ${options.page}, Limit ${options.limit}`);
});
resource
.command('get <id>')
.description(`Get ${name} by ID`)
.action((id) => {
console.log(chalk.blue(`Getting ${name} ${id}...`));
});
resource
.command('create')
.description(`Create new ${name}`)
.option('-d, --data <json>', 'JSON data')
.action((options) => {
console.log(chalk.green(`Creating ${name}...`));
console.log('Data:', options.data);
});
resource
.command('update <id>')
.description(`Update ${name}`)
.option('-d, --data <json>', 'JSON data')
.action((id, options) => {
console.log(chalk.yellow(`Updating ${name} ${id}...`));
console.log('Data:', options.data);
});
resource
.command('delete <id>')
.description(`Delete ${name}`)
.option('-f, --force', 'skip confirmation')
.action((id, options) => {
if (!options.force) {
console.log(chalk.red('Use --force to confirm deletion'));
return;
}
console.log(chalk.red(`Deleted ${name} ${id}`));
});
return resource;
}
// Create CRUD commands for different resources
createResourceCommands('users');
createResourceCommands('posts');
createResourceCommands('comments');
program.parse();
```
Usage:
```bash
# Users
api-cli users list --page 2
api-cli users get 123
api-cli users create --data '{"name":"John"}'
api-cli users update 123 --data '{"email":"new@example.com"}'
api-cli users delete 123 --force
# Posts
api-cli posts list
api-cli posts get 456
api-cli posts create --data '{"title":"Hello"}'
# Comments
api-cli comments list
```
## Modular Command Structure
Split commands into separate files for better organization:
**src/commands/config.ts**
```typescript
import { Command } from 'commander';
export function createConfigCommand(): Command {
const config = new Command('config').description('Configuration management');
config
.command('get <key>')
.description('Get config value')
.action((key) => {
console.log(`Getting ${key}...`);
});
config
.command('set <key> <value>')
.description('Set config value')
.action((key, value) => {
console.log(`Setting ${key} = ${value}`);
});
return config;
}
```
**src/commands/user.ts**
```typescript
import { Command } from 'commander';
export function createUserCommand(): Command {
const user = new Command('user').description('User management');
user
.command('list')
.description('List users')
.action(() => {
console.log('Listing users...');
});
user
.command('create <username>')
.description('Create user')
.action((username) => {
console.log(`Creating user: ${username}`);
});
return user;
}
```
**src/index.ts**
```typescript
import { Command } from 'commander';
import { createConfigCommand } from './commands/config';
import { createUserCommand } from './commands/user';
const program = new Command();
program
.name('mycli')
.version('1.0.0')
.description('My CLI tool');
// Add command groups
program.addCommand(createConfigCommand());
program.addCommand(createUserCommand());
program.parse();
```
## Nested Commands with Shared Options
```typescript
import { Command } from 'commander';
const program = new Command();
program.name('deploy-cli').version('1.0.0');
// Parent deploy command with shared options
const deploy = program
.command('deploy')
.description('Deployment operations')
.option('-e, --env <environment>', 'environment', 'dev')
.option('-v, --verbose', 'verbose output');
// Subcommands inherit parent context
deploy
.command('start')
.description('Start deployment')
.option('-f, --force', 'force deployment')
.action((options, command) => {
const parentOpts = command.parent?.opts();
console.log('Environment:', parentOpts?.env);
console.log('Verbose:', parentOpts?.verbose);
console.log('Force:', options.force);
});
deploy
.command('status')
.description('Check deployment status')
.action((options, command) => {
const parentOpts = command.parent?.opts();
console.log(`Checking ${parentOpts?.env} status...`);
});
deploy
.command('rollback [version]')
.description('Rollback deployment')
.action((version, options, command) => {
const parentOpts = command.parent?.opts();
console.log(`Rolling back ${parentOpts?.env}...`);
});
program.parse();
```
Usage:
```bash
deploy-cli deploy --env prod start --force
deploy-cli deploy --env staging status
deploy-cli deploy --verbose rollback v1.0.0
```
## Command Aliases
```typescript
import { Command } from 'commander';
const program = new Command();
program.name('mycli').version('1.0.0');
const db = program.command('database').alias('db').description('Database ops');
db.command('migrate')
.alias('m')
.description('Run migrations')
.action(() => {
console.log('Running migrations...');
});
db.command('seed')
.alias('s')
.description('Seed database')
.action(() => {
console.log('Seeding...');
});
program.parse();
```
Usage (all equivalent):
```bash
mycli database migrate
mycli db migrate
mycli db m
mycli database seed
mycli db seed
mycli db s
```
## Complete CLI Example
```typescript
#!/usr/bin/env node
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
program
.name('project-cli')
.version('1.0.0')
.description('Project management CLI');
// Project commands
const project = program.command('project').alias('p').description('Project operations');
project
.command('init <name>')
.description('Initialize new project')
.option('-t, --template <type>', 'template', 'basic')
.action((name, options) => {
console.log(chalk.green(`✓ Initialized ${name} with ${options.template} template`));
});
project
.command('build')
.description('Build project')
.action(() => {
console.log(chalk.blue('Building...'));
});
// Environment commands
const env = program.command('env').alias('e').description('Environment management');
env
.command('list')
.alias('ls')
.description('List environments')
.action(() => {
console.log('dev, staging, prod');
});
env
.command('create <name>')
.description('Create environment')
.action((name) => {
console.log(chalk.green(`✓ Created environment: ${name}`));
});
// Deploy commands
const deploy = program.command('deploy').alias('d').description('Deployment operations');
deploy
.command('start <env>')
.description('Start deployment')
.action((env) => {
console.log(chalk.blue(`Deploying to ${env}...`));
});
deploy
.command('status [env]')
.description('Check status')
.action((env) => {
console.log(`Status of ${env || 'all'}:`);
});
program.parse();
```
Usage:
```bash
project-cli project init my-app --template advanced
project-cli p build
project-cli env list
project-cli e create staging
project-cli deploy start prod
project-cli d status
```

View File

@@ -0,0 +1,406 @@
# Commander.js Options and Arguments Demo
Comprehensive examples of option and argument patterns.
## Option Patterns
### 1. Boolean Flags
```typescript
program
.command('build')
.option('-w, --watch', 'watch for changes')
.option('-m, --minify', 'minify output')
.option('-v, --verbose', 'verbose logging')
.action((options) => {
console.log('Watch:', options.watch); // true or undefined
console.log('Minify:', options.minify);
console.log('Verbose:', options.verbose);
});
```
Usage:
```bash
mycli build --watch --minify
```
### 2. Options with Required Values
```typescript
program
.command('deploy')
.option('-e, --env <environment>', 'deployment environment')
.option('-r, --region <region>', 'AWS region')
.action((options) => {
console.log('Environment:', options.env);
console.log('Region:', options.region);
});
```
Usage:
```bash
mycli deploy --env production --region us-west-2
```
### 3. Options with Optional Values
```typescript
program
.command('log')
.option('-f, --file [path]', 'log file path')
.action((options) => {
if (options.file === true) {
console.log('Using default log file');
} else if (options.file) {
console.log('Log file:', options.file);
}
});
```
Usage:
```bash
mycli log --file # file = true
mycli log --file custom.log # file = 'custom.log'
mycli log # file = undefined
```
### 4. Options with Defaults
```typescript
program
.command('serve')
.option('-p, --port <port>', 'port number', '3000')
.option('-h, --host <host>', 'hostname', 'localhost')
.action((options) => {
console.log(`http://${options.host}:${options.port}`);
});
```
Usage:
```bash
mycli serve # Uses defaults
mycli serve --port 8080 # Custom port
```
### 5. Negatable Options
```typescript
program
.command('build')
.option('--cache', 'enable cache')
.option('--no-cache', 'disable cache')
.option('--color', 'enable colors')
.option('--no-color', 'disable colors')
.action((options) => {
console.log('Cache:', options.cache); // undefined, true, or false
console.log('Color:', options.color);
});
```
Usage:
```bash
mycli build # cache & color = undefined
mycli build --cache # cache = true
mycli build --no-cache # cache = false
mycli build --no-color # color = false
```
### 6. Variadic Options
```typescript
program
.command('tag')
.option('-t, --tags <tags...>', 'multiple tags')
.action((options) => {
console.log('Tags:', options.tags); // Array
});
```
Usage:
```bash
mycli tag --tags v1.0 production stable
# Tags: ['v1.0', 'production', 'stable']
```
### 7. Options with Custom Parsers
```typescript
program
.command('scale')
.option('-r, --replicas <count>', 'replica count', parseInt)
.option('-m, --memory <mb>', 'memory in MB', parseFloat)
.option('-t, --timeout <sec>', 'timeout', (value) => {
return parseInt(value) * 1000; // Convert to ms
})
.action((options) => {
console.log('Replicas:', options.replicas); // Number
console.log('Memory:', options.memory); // Number
console.log('Timeout:', options.timeout); // Number (ms)
});
```
Usage:
```bash
mycli scale --replicas 5 --memory 512.5 --timeout 30
```
## Argument Patterns
### 1. Required Arguments
```typescript
program
.command('deploy <environment>')
.description('Deploy to environment')
.action((environment) => {
console.log('Deploying to:', environment);
});
```
Usage:
```bash
mycli deploy production # ✓ Works
mycli deploy # ✗ Error: missing required argument
```
### 2. Optional Arguments
```typescript
program
.command('create <name> [description]')
.description('Create item')
.action((name, description) => {
console.log('Name:', name);
console.log('Description:', description || 'No description');
});
```
Usage:
```bash
mycli create "My Item"
mycli create "My Item" "A detailed description"
```
### 3. Variadic Arguments
```typescript
program
.command('add <items...>')
.description('Add multiple items')
.action((items) => {
console.log('Items:', items); // Array
items.forEach((item, i) => {
console.log(` ${i + 1}. ${item}`);
});
});
```
Usage:
```bash
mycli add item1 item2 item3
# Items: ['item1', 'item2', 'item3']
```
### 4. Mixed Required and Optional
```typescript
program
.command('copy <source> <destination> [options]')
.description('Copy files')
.action((source, destination, options) => {
console.log('Source:', source);
console.log('Destination:', destination);
console.log('Options:', options || 'none');
});
```
### 5. Arguments with Descriptions
```typescript
program
.command('deploy <environment>')
.argument('<environment>', 'target environment (dev, staging, prod)')
.argument('[region]', 'deployment region', 'us-east-1')
.action((environment, region) => {
console.log(`Deploying to ${environment} in ${region}`);
});
```
### 6. Arguments with Custom Parsers
```typescript
program
.command('wait <seconds>')
.argument('<seconds>', 'seconds to wait', parseFloat)
.action(async (seconds) => {
console.log(`Waiting ${seconds} seconds...`);
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
console.log('Done!');
});
```
Usage:
```bash
mycli wait 2.5 # Waits 2.5 seconds
```
### 7. Arguments with Validation
```typescript
program
.command('set-port <port>')
.argument('<port>', 'port number', (value) => {
const port = parseInt(value, 10);
if (isNaN(port)) {
throw new Error('Port must be a number');
}
if (port < 1 || port > 65535) {
throw new Error('Port must be between 1 and 65535');
}
return port;
})
.action((port) => {
console.log('Port set to:', port);
});
```
## Combined Patterns
### Arguments + Options
```typescript
program
.command('deploy <environment>')
.argument('<environment>', 'deployment environment')
.option('-f, --force', 'force deployment')
.option('-d, --dry-run', 'simulate deployment')
.option('-t, --tag <tag>', 'deployment tag', 'latest')
.action((environment, options) => {
console.log('Environment:', environment);
console.log('Force:', options.force);
console.log('Dry run:', options.dryRun);
console.log('Tag:', options.tag);
});
```
Usage:
```bash
mycli deploy production --force --tag v1.2.3
```
### Variadic Arguments + Options
```typescript
program
.command('compile <files...>')
.argument('<files...>', 'files to compile')
.option('-o, --output <dir>', 'output directory', './dist')
.option('-m, --minify', 'minify output')
.action((files, options) => {
console.log('Files:', files);
console.log('Output:', options.output);
console.log('Minify:', options.minify);
});
```
Usage:
```bash
mycli compile src/a.ts src/b.ts --output build --minify
```
### Multiple Option Types
```typescript
program
.command('start')
.option('-p, --port <port>', 'port', '3000')
.option('-h, --host <host>', 'host', 'localhost')
.option('-o, --open', 'open browser')
.option('--no-color', 'disable colors')
.option('-e, --env <vars...>', 'environment variables')
.action((options) => {
console.log('Server:', `http://${options.host}:${options.port}`);
console.log('Open:', options.open);
console.log('Color:', options.color);
console.log('Env:', options.env);
});
```
Usage:
```bash
mycli start --port 8080 --open --env NODE_ENV=production DEBUG=true
```
## Complete Example
```typescript
#!/usr/bin/env node
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
program.name('deploy-cli').version('1.0.0');
program
.command('deploy <environment> [region]')
.description('Deploy application')
.argument('<environment>', 'target environment (dev, staging, prod)')
.argument('[region]', 'deployment region', 'us-east-1')
.option('-f, --force', 'skip confirmations', false)
.option('-d, --dry-run', 'simulate deployment', false)
.option('-t, --tag <tag>', 'deployment tag', 'latest')
.option('-r, --replicas <count>', 'replica count', parseInt, 3)
.option('--env <vars...>', 'environment variables')
.option('--no-rollback', 'disable auto-rollback')
.action((environment, region, options) => {
console.log(chalk.blue('Deployment Configuration:'));
console.log('Environment:', chalk.yellow(environment));
console.log('Region:', region);
console.log('Tag:', options.tag);
console.log('Replicas:', options.replicas);
console.log('Force:', options.force);
console.log('Dry run:', options.dryRun);
console.log('Rollback:', options.rollback);
if (options.env) {
console.log('Environment variables:');
options.env.forEach((v) => console.log(` ${v}`));
}
if (options.dryRun) {
console.log(chalk.yellow('\n🔍 Dry run - no actual deployment'));
return;
}
console.log(chalk.green('\n✓ Deployment complete!'));
});
program.parse();
```
Usage examples:
```bash
# Basic
deploy-cli deploy production
# With region
deploy-cli deploy staging us-west-2
# With options
deploy-cli deploy prod --force --replicas 5
# With environment variables
deploy-cli deploy prod --env NODE_ENV=production API_KEY=xyz
# Dry run
deploy-cli deploy prod --dry-run --no-rollback
# All together
deploy-cli deploy production us-west-2 \
--force \
--tag v2.0.0 \
--replicas 10 \
--env NODE_ENV=production DEBUG=false \
--no-rollback
```

View File

@@ -0,0 +1,67 @@
#!/bin/bash
# Extract help text from Commander.js CLI for documentation
set -euo pipefail
CLI_COMMAND="${1:?Usage: $0 <cli-command> [output-file]}"
OUTPUT_FILE="${2:-docs/CLI-REFERENCE.md}"
echo "📚 Extracting help documentation from: $CLI_COMMAND"
# Create output directory
mkdir -p "$(dirname "$OUTPUT_FILE")"
# Start markdown file
cat > "$OUTPUT_FILE" << EOF
# CLI Reference
Auto-generated documentation for $CLI_COMMAND
---
## Main Command
\`\`\`
EOF
# Get main help
$CLI_COMMAND --help >> "$OUTPUT_FILE" || true
cat >> "$OUTPUT_FILE" << 'EOF'
```
---
## Commands
EOF
# Extract all commands
COMMANDS=$($CLI_COMMAND --help | grep -A 100 "Commands:" | tail -n +2 | awk '{print $1}' | grep -v "^$" || echo "")
if [[ -n "$COMMANDS" ]]; then
for cmd in $COMMANDS; do
echo "### \`$cmd\`" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
echo "\`\`\`" >> "$OUTPUT_FILE"
$CLI_COMMAND $cmd --help >> "$OUTPUT_FILE" 2>&1 || true
echo "\`\`\`" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
done
else
echo "No subcommands found." >> "$OUTPUT_FILE"
fi
cat >> "$OUTPUT_FILE" << EOF
---
*Generated: $(date)*
*CLI Version: $($CLI_COMMAND --version 2>/dev/null || echo "unknown")*
EOF
echo "✅ Documentation generated: $OUTPUT_FILE"
echo ""
echo "Preview:"
head -n 20 "$OUTPUT_FILE"
echo "..."

View File

@@ -0,0 +1,59 @@
#!/bin/bash
# Generate Commander.js command with options and arguments
set -euo pipefail
COMMAND_NAME="${1:?Usage: $0 <command-name> [output-file]}"
OUTPUT_FILE="${2:-src/commands/${COMMAND_NAME}.ts}"
# Create output directory
mkdir -p "$(dirname "$OUTPUT_FILE")"
echo "📝 Generating Commander.js command: $COMMAND_NAME"
cat > "$OUTPUT_FILE" << 'EOF'
import { Command, Option } from 'commander';
import chalk from 'chalk';
export function create{{COMMAND_NAME_PASCAL}}Command(): Command {
const command = new Command('{{COMMAND_NAME}}')
.description('{{DESCRIPTION}}')
.option('-v, --verbose', 'verbose output', false)
.addOption(
new Option('-e, --environment <env>', 'target environment')
.choices(['dev', 'staging', 'prod'])
.default('dev')
)
.action(async (options) => {
try {
console.log(chalk.blue(`Running {{COMMAND_NAME}} command...`));
console.log('Options:', options);
// TODO: Implement command logic
console.log(chalk.green('✓ Command completed successfully'));
} catch (error) {
console.error(chalk.red('✗ Command failed:'), error.message);
process.exit(1);
}
});
return command;
}
EOF
# Convert command name to PascalCase
COMMAND_NAME_PASCAL=$(echo "$COMMAND_NAME" | sed -r 's/(^|-)([a-z])/\U\2/g')
# Replace placeholders
sed -i "s/{{COMMAND_NAME}}/$COMMAND_NAME/g" "$OUTPUT_FILE"
sed -i "s/{{COMMAND_NAME_PASCAL}}/$COMMAND_NAME_PASCAL/g" "$OUTPUT_FILE"
sed -i "s/{{DESCRIPTION}}/Execute $COMMAND_NAME operation/g" "$OUTPUT_FILE"
echo "✅ Command generated: $OUTPUT_FILE"
echo ""
echo "Next steps:"
echo " 1. Implement command logic in the action handler"
echo " 2. Add custom options and arguments as needed"
echo " 3. Import and add to main CLI: program.addCommand(create${COMMAND_NAME_PASCAL}Command())"
echo ""

View File

@@ -0,0 +1,75 @@
#!/bin/bash
# Generate nested subcommand structure for Commander.js
set -euo pipefail
PARENT_COMMAND="${1:?Usage: $0 <parent-command> <subcommand> [output-file]}"
SUBCOMMAND="${2:?Usage: $0 <parent-command> <subcommand> [output-file]}"
OUTPUT_FILE="${3:-src/commands/${PARENT_COMMAND}/${SUBCOMMAND}.ts}"
# Create output directory
mkdir -p "$(dirname "$OUTPUT_FILE")"
echo "📝 Generating subcommand: $PARENT_COMMAND $SUBCOMMAND"
cat > "$OUTPUT_FILE" << 'EOF'
import { Command } from 'commander';
import chalk from 'chalk';
export function create{{SUBCOMMAND_PASCAL}}Command(): Command {
const command = new Command('{{SUBCOMMAND}}')
.description('{{DESCRIPTION}}')
.action(async (options) => {
try {
console.log(chalk.blue(`Running {{PARENT_COMMAND}} {{SUBCOMMAND}}...`));
// TODO: Implement subcommand logic
console.log(chalk.green('✓ Subcommand completed'));
} catch (error) {
console.error(chalk.red('✗ Subcommand failed:'), error.message);
process.exit(1);
}
});
return command;
}
EOF
# Convert to PascalCase
SUBCOMMAND_PASCAL=$(echo "$SUBCOMMAND" | sed -r 's/(^|-)([a-z])/\U\2/g')
# Replace placeholders
sed -i "s/{{PARENT_COMMAND}}/$PARENT_COMMAND/g" "$OUTPUT_FILE"
sed -i "s/{{SUBCOMMAND}}/$SUBCOMMAND/g" "$OUTPUT_FILE"
sed -i "s/{{SUBCOMMAND_PASCAL}}/$SUBCOMMAND_PASCAL/g" "$OUTPUT_FILE"
sed -i "s/{{DESCRIPTION}}/$SUBCOMMAND operation for $PARENT_COMMAND/g" "$OUTPUT_FILE"
# Generate parent command file if it doesn't exist
PARENT_FILE="src/commands/${PARENT_COMMAND}/index.ts"
if [[ ! -f "$PARENT_FILE" ]]; then
mkdir -p "$(dirname "$PARENT_FILE")"
cat > "$PARENT_FILE" << EOF
import { Command } from 'commander';
import { create${SUBCOMMAND_PASCAL}Command } from './${SUBCOMMAND}';
export function create${PARENT_COMMAND^}Command(): Command {
const command = new Command('${PARENT_COMMAND}')
.description('${PARENT_COMMAND^} operations');
// Add subcommands
command.addCommand(create${SUBCOMMAND_PASCAL}Command());
return command;
}
EOF
echo "✅ Created parent command: $PARENT_FILE"
fi
echo "✅ Subcommand generated: $OUTPUT_FILE"
echo ""
echo "Next steps:"
echo " 1. Implement subcommand logic"
echo " 2. Add to parent command: ${PARENT_FILE}"
echo " 3. Import parent in main CLI: program.addCommand(create${PARENT_COMMAND^}Command())"
echo ""

View File

@@ -0,0 +1,83 @@
#!/bin/bash
# Test Commander.js CLI with various inputs
set -euo pipefail
CLI_COMMAND="${1:?Usage: $0 <cli-command> [test-suite]}"
TEST_SUITE="${2:-basic}"
echo "🧪 Testing Commander.js CLI: $CLI_COMMAND"
echo "Test suite: $TEST_SUITE"
echo ""
PASSED=0
FAILED=0
# Helper function to run test
run_test() {
local test_name="$1"
local test_command="$2"
local expected_exit_code="${3:-0}"
echo -n "Testing: $test_name ... "
if eval "$test_command" > /dev/null 2>&1; then
actual_exit_code=0
else
actual_exit_code=$?
fi
if [[ $actual_exit_code -eq $expected_exit_code ]]; then
echo "✅ PASS"
((PASSED++))
else
echo "❌ FAIL (expected exit code $expected_exit_code, got $actual_exit_code)"
((FAILED++))
fi
}
# Basic tests
if [[ "$TEST_SUITE" == "basic" || "$TEST_SUITE" == "all" ]]; then
echo "Running basic tests..."
run_test "Help flag" "$CLI_COMMAND --help" 0
run_test "Version flag" "$CLI_COMMAND --version" 0
run_test "No arguments" "$CLI_COMMAND" 1
fi
# Command tests
if [[ "$TEST_SUITE" == "commands" || "$TEST_SUITE" == "all" ]]; then
echo ""
echo "Running command tests..."
run_test "List commands" "$CLI_COMMAND --help | grep -q 'Commands:'" 0
fi
# Option tests
if [[ "$TEST_SUITE" == "options" || "$TEST_SUITE" == "all" ]]; then
echo ""
echo "Running option tests..."
run_test "Unknown option" "$CLI_COMMAND --unknown-option" 1
run_test "Short flag" "$CLI_COMMAND -v" 0
run_test "Long flag" "$CLI_COMMAND --verbose" 0
fi
# Argument tests
if [[ "$TEST_SUITE" == "arguments" || "$TEST_SUITE" == "all" ]]; then
echo ""
echo "Running argument tests..."
run_test "Required argument missing" "$CLI_COMMAND deploy" 1
run_test "Required argument provided" "$CLI_COMMAND deploy production" 0
fi
echo ""
echo "Test Results:"
echo " Passed: $PASSED"
echo " Failed: $FAILED"
echo ""
if [[ $FAILED -gt 0 ]]; then
echo "❌ Some tests failed"
exit 1
else
echo "✅ All tests passed!"
exit 0
fi

View File

@@ -0,0 +1,139 @@
#!/bin/bash
# Validate Commander.js CLI structure and patterns
set -euo pipefail
CLI_FILE="${1:?Usage: $0 <cli-file.ts|js>}"
if [[ ! -f "$CLI_FILE" ]]; then
echo "Error: File not found: $CLI_FILE"
exit 1
fi
echo "🔍 Validating Commander.js CLI structure: $CLI_FILE"
echo ""
ERRORS=0
WARNINGS=0
# Check for Commander import
if grep -q "from 'commander'" "$CLI_FILE" || grep -q 'require("commander")' "$CLI_FILE"; then
echo "✅ Commander.js import found"
else
echo "❌ Missing Commander.js import"
((ERRORS++))
fi
# Check for Command instantiation
if grep -q "new Command()" "$CLI_FILE" || grep -q "= program" "$CLI_FILE"; then
echo "✅ Command instance created"
else
echo "❌ No Command instance found"
((ERRORS++))
fi
# Check for program.parse()
if grep -q "\.parse()" "$CLI_FILE"; then
echo "✅ program.parse() called"
else
echo "❌ Missing program.parse() call"
((ERRORS++))
fi
# Check for .name()
if grep -q "\.name(" "$CLI_FILE"; then
echo "✅ CLI name defined"
else
echo "⚠️ CLI name not set (recommended)"
((WARNINGS++))
fi
# Check for .description()
if grep -q "\.description(" "$CLI_FILE"; then
echo "✅ CLI description defined"
else
echo "⚠️ CLI description not set (recommended)"
((WARNINGS++))
fi
# Check for .version()
if grep -q "\.version(" "$CLI_FILE"; then
echo "✅ CLI version defined"
else
echo "⚠️ CLI version not set (recommended)"
((WARNINGS++))
fi
# Check for commands
COMMAND_COUNT=$(grep -c "\.command(" "$CLI_FILE" || echo "0")
if [[ $COMMAND_COUNT -gt 0 ]]; then
echo "✅ Found $COMMAND_COUNT command(s)"
else
echo "⚠️ No commands defined"
((WARNINGS++))
fi
# Check for action handlers
ACTION_COUNT=$(grep -c "\.action(" "$CLI_FILE" || echo "0")
if [[ $ACTION_COUNT -gt 0 ]]; then
echo "✅ Found $ACTION_COUNT action handler(s)"
else
echo "⚠️ No action handlers defined"
((WARNINGS++))
fi
# Check for options
OPTION_COUNT=$(grep -c "\.option(" "$CLI_FILE" || echo "0")
ADDOPTION_COUNT=$(grep -c "\.addOption(" "$CLI_FILE" || echo "0")
TOTAL_OPTIONS=$((OPTION_COUNT + ADDOPTION_COUNT))
if [[ $TOTAL_OPTIONS -gt 0 ]]; then
echo "✅ Found $TOTAL_OPTIONS option(s)"
else
echo "⚠️ No options defined"
((WARNINGS++))
fi
# Check for arguments
ARGUMENT_COUNT=$(grep -c "\.argument(" "$CLI_FILE" || echo "0")
if [[ $ARGUMENT_COUNT -gt 0 ]]; then
echo "✅ Found $ARGUMENT_COUNT argument(s)"
fi
# Check for Option class usage
if grep -q "new Option(" "$CLI_FILE"; then
echo "✅ Option class used (advanced)"
fi
# Check for error handling
if grep -q "try\|catch" "$CLI_FILE" || grep -q "\.exitOverride()" "$CLI_FILE"; then
echo "✅ Error handling present"
else
echo "⚠️ No error handling detected (recommended)"
((WARNINGS++))
fi
# Check for TypeScript
if [[ "$CLI_FILE" == *.ts ]]; then
echo "✅ TypeScript file"
# Check for types
if grep -q "import.*Command.*Option.*from 'commander'" "$CLI_FILE"; then
echo "✅ Proper TypeScript imports"
fi
fi
echo ""
echo "Summary:"
echo " Errors: $ERRORS"
echo " Warnings: $WARNINGS"
echo ""
if [[ $ERRORS -gt 0 ]]; then
echo "❌ Validation failed with $ERRORS error(s)"
exit 1
elif [[ $WARNINGS -gt 0 ]]; then
echo "⚠️ Validation passed with $WARNINGS warning(s)"
exit 0
else
echo "✅ Validation passed - excellent CLI structure!"
exit 0
fi

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env node
import { Command } from 'commander';
const program = new Command();
program
.name('mycli')
.description('A simple CLI tool')
.version('1.0.0');
program
.command('hello')
.description('Say hello')
.option('-n, --name <name>', 'name to greet', 'World')
.action((options) => {
console.log(`Hello, ${options.name}!`);
});
program.parse();

View File

@@ -0,0 +1,18 @@
import { Command } from 'commander';
const program = new Command();
program
.name('mycli')
.description('A simple CLI tool')
.version('1.0.0');
program
.command('hello')
.description('Say hello')
.option('-n, --name <name>', 'name to greet', 'World')
.action((options) => {
console.log(`Hello, ${options.name}!`);
});
program.parse();

View File

@@ -0,0 +1,93 @@
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
program
.name('mycli')
.description('CLI with various argument types')
.version('1.0.0');
// Command with required argument
program
.command('deploy <environment>')
.description('Deploy to specified environment')
.argument('<environment>', 'target environment (dev, staging, prod)')
.action((environment) => {
console.log(chalk.blue(`Deploying to ${environment}...`));
});
// Command with required and optional arguments
program
.command('create <name> [description]')
.description('Create new item')
.argument('<name>', 'item name')
.argument('[description]', 'item description', 'No description provided')
.action((name, description) => {
console.log(`Creating: ${name}`);
console.log(`Description: ${description}`);
});
// Command with variadic arguments
program
.command('add <items...>')
.description('Add multiple items')
.argument('<items...>', 'items to add')
.action((items) => {
console.log(chalk.blue('Adding items:'));
items.forEach((item, index) => {
console.log(` ${index + 1}. ${item}`);
});
console.log(chalk.green(`✓ Added ${items.length} items`));
});
// Command with custom argument parser
program
.command('wait <seconds>')
.description('Wait for specified time')
.argument('<seconds>', 'seconds to wait', parseFloat)
.action(async (seconds) => {
console.log(chalk.blue(`Waiting ${seconds} seconds...`));
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
console.log(chalk.green('✓ Done'));
});
// Command with arguments and options
program
.command('copy <source> <destination>')
.description('Copy file from source to destination')
.argument('<source>', 'source file path')
.argument('<destination>', 'destination file path')
.option('-f, --force', 'overwrite if exists', false)
.option('-r, --recursive', 'copy recursively', false)
.action((source, destination, options) => {
console.log(`Copying ${source} to ${destination}`);
console.log('Options:', options);
if (options.force) {
console.log(chalk.yellow('⚠ Force mode: will overwrite existing files'));
}
if (options.recursive) {
console.log(chalk.blue('Recursive copy enabled'));
}
console.log(chalk.green('✓ Copy complete'));
});
// Command with argument validation
program
.command('set-port <port>')
.description('Set application port')
.argument('<port>', 'port number', (value) => {
const port = parseInt(value, 10);
if (isNaN(port)) {
throw new Error('Port must be a number');
}
if (port < 1 || port > 65535) {
throw new Error('Port must be between 1 and 65535');
}
return port;
})
.action((port) => {
console.log(chalk.green(`✓ Port set to ${port}`));
});
program.parse();

View File

@@ -0,0 +1,60 @@
import { Command, Option } from 'commander';
import chalk from 'chalk';
const program = new Command();
program
.name('mycli')
.description('CLI with various option types')
.version('1.0.0');
program
.command('deploy')
.description('Deploy application')
// Boolean flag
.option('-v, --verbose', 'verbose output', false)
// Option with required value
.option('-p, --port <port>', 'port number', '3000')
// Option with optional value
.option('-c, --config [path]', 'config file path')
// Negatable option
.option('--no-build', 'skip build step')
// Multiple choice option using Option class
.addOption(
new Option('-e, --env <environment>', 'target environment')
.choices(['dev', 'staging', 'prod'])
.default('dev')
)
// Option with custom parser
.addOption(
new Option('-r, --replicas <count>', 'number of replicas')
.argParser(parseInt)
.default(3)
)
// Mandatory option
.addOption(
new Option('-t, --token <token>', 'API token')
.makeOptionMandatory()
.env('API_TOKEN')
)
// Variadic option
.option('--tags <tags...>', 'deployment tags')
.action((options) => {
console.log(chalk.blue('Deploying with options:'));
console.log('Verbose:', options.verbose);
console.log('Port:', options.port);
console.log('Config:', options.config);
console.log('Build:', options.build);
console.log('Environment:', options.env);
console.log('Replicas:', options.replicas);
console.log('Token:', options.token ? '***' : 'not set');
console.log('Tags:', options.tags);
if (options.verbose) {
console.log(chalk.gray('Verbose mode enabled'));
}
console.log(chalk.green('✓ Deployment complete'));
});
program.parse();

View File

@@ -0,0 +1,341 @@
import { Command } from 'commander';
import inquirer from 'inquirer';
import chalk from 'chalk';
const program = new Command();
program
.name('mycli')
.description('Interactive CLI with Inquirer.js integration')
.version('1.0.0');
// Interactive init command
program
.command('init')
.description('Initialize project interactively')
.option('-y, --yes', 'skip prompts and use defaults', false)
.action(async (options) => {
if (options.yes) {
console.log(chalk.blue('Using default configuration...'));
await initProject({
name: 'my-project',
template: 'basic',
features: [],
});
return;
}
// Interactive prompts
const answers = await inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'Project name:',
default: 'my-project',
validate: (input) => {
if (!input.trim()) {
return 'Project name is required';
}
if (!/^[a-z0-9-]+$/.test(input)) {
return 'Project name must contain only lowercase letters, numbers, and hyphens';
}
return true;
},
},
{
type: 'list',
name: 'template',
message: 'Choose a template:',
choices: ['basic', 'advanced', 'enterprise'],
default: 'basic',
},
{
type: 'checkbox',
name: 'features',
message: 'Select features:',
choices: [
{ name: 'TypeScript', value: 'typescript', checked: true },
{ name: 'ESLint', value: 'eslint', checked: true },
{ name: 'Prettier', value: 'prettier', checked: true },
{ name: 'Testing (Jest)', value: 'jest' },
{ name: 'CI/CD', value: 'cicd' },
{ name: 'Docker', value: 'docker' },
],
},
{
type: 'confirm',
name: 'install',
message: 'Install dependencies now?',
default: true,
},
]);
await initProject(answers);
});
// Interactive deploy command
program
.command('deploy')
.description('Deploy with interactive configuration')
.option('-e, --env <environment>', 'skip environment prompt')
.action(async (options) => {
const questions: any[] = [];
// Conditionally add environment question
if (!options.env) {
questions.push({
type: 'list',
name: 'environment',
message: 'Select deployment environment:',
choices: ['dev', 'staging', 'prod'],
});
}
questions.push(
{
type: 'list',
name: 'strategy',
message: 'Deployment strategy:',
choices: ['rolling', 'blue-green', 'canary'],
default: 'rolling',
},
{
type: 'confirm',
name: 'runTests',
message: 'Run tests before deployment?',
default: true,
},
{
type: 'confirm',
name: 'createBackup',
message: 'Create backup before deployment?',
default: true,
when: (answers) => answers.environment === 'prod',
},
{
type: 'password',
name: 'token',
message: 'Enter deployment token:',
mask: '*',
validate: (input) => (input.length > 0 ? true : 'Token is required'),
}
);
const answers = await inquirer.prompt(questions);
const deployConfig = {
environment: options.env || answers.environment,
...answers,
};
console.log(chalk.blue('\nDeployment configuration:'));
console.log(JSON.stringify(deployConfig, null, 2));
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: 'Proceed with deployment?',
default: false,
},
]);
if (!confirm) {
console.log(chalk.yellow('Deployment cancelled'));
return;
}
await deploy(deployConfig);
});
// Interactive config command
program
.command('config')
.description('Configure application interactively')
.action(async () => {
const mainMenu = await inquirer.prompt([
{
type: 'list',
name: 'action',
message: 'What would you like to do?',
choices: [
{ name: 'View configuration', value: 'view' },
{ name: 'Edit configuration', value: 'edit' },
{ name: 'Reset to defaults', value: 'reset' },
{ name: 'Exit', value: 'exit' },
],
},
]);
switch (mainMenu.action) {
case 'view':
console.log(chalk.blue('\nCurrent configuration:'));
console.log(JSON.stringify(getConfig(), null, 2));
break;
case 'edit':
const config = await inquirer.prompt([
{
type: 'input',
name: 'apiUrl',
message: 'API URL:',
default: getConfig().apiUrl,
},
{
type: 'number',
name: 'timeout',
message: 'Request timeout (ms):',
default: getConfig().timeout,
},
{
type: 'list',
name: 'logLevel',
message: 'Log level:',
choices: ['debug', 'info', 'warn', 'error'],
default: getConfig().logLevel,
},
]);
saveConfig(config);
console.log(chalk.green('✓ Configuration saved'));
break;
case 'reset':
const { confirmReset } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirmReset',
message: 'Reset to default configuration?',
default: false,
},
]);
if (confirmReset) {
resetConfig();
console.log(chalk.green('✓ Configuration reset'));
}
break;
case 'exit':
console.log(chalk.gray('Goodbye!'));
break;
}
});
// Multi-step wizard
program
.command('wizard')
.description('Run setup wizard')
.action(async () => {
console.log(chalk.blue('🧙 Welcome to the setup wizard\n'));
// Step 1: Basic info
console.log(chalk.bold('Step 1: Basic Information'));
const step1 = await inquirer.prompt([
{
type: 'input',
name: 'projectName',
message: 'Project name:',
},
{
type: 'input',
name: 'description',
message: 'Description:',
},
]);
// Step 2: Technology stack
console.log(chalk.bold('\nStep 2: Technology Stack'));
const step2 = await inquirer.prompt([
{
type: 'list',
name: 'language',
message: 'Primary language:',
choices: ['TypeScript', 'JavaScript', 'Python', 'Go', 'Rust'],
},
{
type: 'checkbox',
name: 'frameworks',
message: 'Select frameworks:',
choices: (answers) => {
const frameworksByLanguage: Record<string, string[]> = {
TypeScript: ['Next.js', 'Express', 'NestJS'],
JavaScript: ['React', 'Vue', 'Express'],
Python: ['FastAPI', 'Django', 'Flask'],
Go: ['Gin', 'Echo', 'Fiber'],
Rust: ['Actix', 'Rocket', 'Axum'],
};
return frameworksByLanguage[answers.language] || [];
},
},
]);
// Step 3: Infrastructure
console.log(chalk.bold('\nStep 3: Infrastructure'));
const step3 = await inquirer.prompt([
{
type: 'list',
name: 'database',
message: 'Database:',
choices: ['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite', 'None'],
},
{
type: 'checkbox',
name: 'services',
message: 'Additional services:',
choices: ['Redis', 'ElasticSearch', 'RabbitMQ', 'S3'],
},
]);
// Summary
const config = { ...step1, ...step2, ...step3 };
console.log(chalk.bold('\n📋 Configuration Summary:'));
console.log(JSON.stringify(config, null, 2));
const { confirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirm',
message: 'Create project with this configuration?',
default: true,
},
]);
if (confirm) {
console.log(chalk.green('\n✓ Project created successfully!'));
} else {
console.log(chalk.yellow('\n✗ Project creation cancelled'));
}
});
// Helper functions
async function initProject(config: any) {
console.log(chalk.blue('\nInitializing project...'));
console.log('Name:', config.name);
console.log('Template:', config.template);
console.log('Features:', config.features.join(', '));
console.log(chalk.green('\n✓ Project initialized!'));
}
async function deploy(config: any) {
console.log(chalk.blue('\nDeploying...'));
console.log(JSON.stringify(config, null, 2));
console.log(chalk.green('\n✓ Deployment complete!'));
}
function getConfig() {
return {
apiUrl: 'https://api.example.com',
timeout: 5000,
logLevel: 'info',
};
}
function saveConfig(config: any) {
console.log('Saving config:', config);
}
function resetConfig() {
console.log('Resetting config to defaults');
}
program.parse();

View File

@@ -0,0 +1,266 @@
import { Command, Option } from 'commander';
import chalk from 'chalk';
import { z } from 'zod';
const program = new Command();
program
.name('mycli')
.description('CLI with comprehensive input validation')
.version('1.0.0');
// Zod schemas for validation
const EmailSchema = z.string().email();
const UrlSchema = z.string().url();
const PortSchema = z.number().int().min(1).max(65535);
const EnvironmentSchema = z.enum(['dev', 'staging', 'prod']);
// Validation helper
function validateOrThrow<T>(schema: z.ZodSchema<T>, value: unknown, fieldName: string): T {
try {
return schema.parse(value);
} catch (error) {
if (error instanceof z.ZodError) {
throw new Error(`Invalid ${fieldName}: ${error.errors[0].message}`);
}
throw error;
}
}
// Command with validated arguments
program
.command('create-user <email> <username>')
.description('Create user with validated inputs')
.argument('<email>', 'user email', (value) => {
return validateOrThrow(EmailSchema, value, 'email');
})
.argument('<username>', 'username', (value) => {
const UsernameSchema = z
.string()
.min(3, 'Username must be at least 3 characters')
.max(20, 'Username must be at most 20 characters')
.regex(/^[a-z0-9_]+$/, 'Username must contain only lowercase letters, numbers, and underscores');
return validateOrThrow(UsernameSchema, value, 'username');
})
.option('-a, --age <age>', 'user age', (value) => {
const age = parseInt(value, 10);
const AgeSchema = z.number().int().min(13).max(120);
return validateOrThrow(AgeSchema, age, 'age');
})
.action((email, username, options) => {
console.log(chalk.green('✓ User validation passed'));
console.log('Email:', email);
console.log('Username:', username);
if (options.age) {
console.log('Age:', options.age);
}
});
// Command with validated options
program
.command('deploy')
.description('Deploy with validated configuration')
.addOption(
new Option('-e, --env <environment>', 'deployment environment')
.argParser((value) => {
return validateOrThrow(EnvironmentSchema, value, 'environment');
})
.makeOptionMandatory()
)
.addOption(
new Option('-u, --url <url>', 'deployment URL')
.argParser((value) => {
return validateOrThrow(UrlSchema, value, 'URL');
})
.makeOptionMandatory()
)
.addOption(
new Option('-p, --port <port>', 'server port')
.argParser((value) => {
const port = parseInt(value, 10);
return validateOrThrow(PortSchema, port, 'port');
})
.default(3000)
)
.addOption(
new Option('-r, --replicas <count>', 'replica count')
.argParser((value) => {
const count = parseInt(value, 10);
const ReplicaSchema = z.number().int().min(1).max(100);
return validateOrThrow(ReplicaSchema, count, 'replicas');
})
.default(3)
)
.action((options) => {
console.log(chalk.green('✓ Deployment configuration validated'));
console.log('Environment:', options.env);
console.log('URL:', options.url);
console.log('Port:', options.port);
console.log('Replicas:', options.replicas);
});
// Command with complex object validation
program
.command('configure')
.description('Configure application with JSON validation')
.option('-c, --config <json>', 'configuration as JSON string', (value) => {
// Parse JSON
let parsed;
try {
parsed = JSON.parse(value);
} catch {
throw new Error('Invalid JSON format');
}
// Validate with Zod schema
const ConfigSchema = z.object({
api: z.object({
url: z.string().url(),
timeout: z.number().int().positive(),
retries: z.number().int().min(0).max(5),
}),
database: z.object({
host: z.string(),
port: z.number().int().min(1).max(65535),
name: z.string(),
}),
features: z.object({
enableCache: z.boolean(),
enableMetrics: z.boolean(),
}),
});
return validateOrThrow(ConfigSchema, parsed, 'configuration');
})
.action((options) => {
if (options.config) {
console.log(chalk.green('✓ Configuration validated'));
console.log(JSON.stringify(options.config, null, 2));
}
});
// Command with file path validation
program
.command('process <inputFile> <outputFile>')
.description('Process file with path validation')
.argument('<inputFile>', 'input file path', (value) => {
const FilePathSchema = z.string().refine(
(path) => {
// Check file extension
return path.endsWith('.json') || path.endsWith('.yaml') || path.endsWith('.yml');
},
{ message: 'File must be .json, .yaml, or .yml' }
);
return validateOrThrow(FilePathSchema, value, 'input file');
})
.argument('<outputFile>', 'output file path', (value) => {
const FilePathSchema = z.string().min(1);
return validateOrThrow(FilePathSchema, value, 'output file');
})
.action((inputFile, outputFile) => {
console.log(chalk.green('✓ File paths validated'));
console.log('Input:', inputFile);
console.log('Output:', outputFile);
});
// Command with date/time validation
program
.command('schedule <datetime>')
.description('Schedule task with datetime validation')
.argument('<datetime>', 'ISO 8601 datetime', (value) => {
const date = new Date(value);
if (isNaN(date.getTime())) {
throw new Error('Invalid datetime format (use ISO 8601)');
}
if (date < new Date()) {
throw new Error('Datetime must be in the future');
}
return date;
})
.option('-d, --duration <minutes>', 'duration in minutes', (value) => {
const minutes = parseInt(value, 10);
const DurationSchema = z.number().int().min(1).max(1440); // 1 min to 24 hours
return validateOrThrow(DurationSchema, minutes, 'duration');
})
.action((datetime, options) => {
console.log(chalk.green('✓ Schedule validated'));
console.log('Start time:', datetime.toISOString());
if (options.duration) {
const endTime = new Date(datetime.getTime() + options.duration * 60000);
console.log('End time:', endTime.toISOString());
}
});
// Command with array validation
program
.command('tag <items...>')
.description('Tag items with validation')
.argument('<items...>', 'items to tag')
.option('-t, --tags <tags...>', 'tags to apply', (values) => {
const TagSchema = z.array(
z
.string()
.min(2)
.max(20)
.regex(/^[a-z0-9-]+$/, 'Tags must contain only lowercase letters, numbers, and hyphens')
);
return validateOrThrow(TagSchema, values, 'tags');
})
.action((items, options) => {
console.log(chalk.green('✓ Items and tags validated'));
console.log('Items:', items);
if (options.tags) {
console.log('Tags:', options.tags);
}
});
// Command with custom validation logic
program
.command('migrate')
.description('Database migration with version validation')
.option('-f, --from <version>', 'migrate from version', (value) => {
const VersionSchema = z.string().regex(/^\d+\.\d+\.\d+$/, 'Version must be in format X.Y.Z');
return validateOrThrow(VersionSchema, value, 'from version');
})
.option('-t, --to <version>', 'migrate to version', (value) => {
const VersionSchema = z.string().regex(/^\d+\.\d+\.\d+$/, 'Version must be in format X.Y.Z');
return validateOrThrow(VersionSchema, value, 'to version');
})
.action((options) => {
// Additional cross-field validation
if (options.from && options.to) {
const fromParts = options.from.split('.').map(Number);
const toParts = options.to.split('.').map(Number);
const fromNum = fromParts[0] * 10000 + fromParts[1] * 100 + fromParts[2];
const toNum = toParts[0] * 10000 + toParts[1] * 100 + toParts[2];
if (fromNum >= toNum) {
throw new Error('Target version must be higher than source version');
}
console.log(chalk.green('✓ Migration versions validated'));
console.log(`Migrating from ${options.from} to ${options.to}`);
}
});
// Global error handling
program.exitOverride();
try {
program.parse();
} catch (error: any) {
if (error.code === 'commander.help' || error.code === 'commander.version') {
process.exit(0);
} else {
console.error(chalk.red('Validation Error:'), error.message);
console.error(chalk.gray('\nUse --help for usage information'));
process.exit(1);
}
}

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env node
const { Command } = require('commander');
const program = new Command();
program
.name('mycli')
.description('A simple CLI tool (CommonJS)')
.version('1.0.0');
program
.command('hello')
.description('Say hello')
.option('-n, --name <name>', 'name to greet', 'World')
.action((options) => {
console.log(`Hello, ${options.name}!`);
});
program
.command('deploy <environment>')
.description('Deploy to environment')
.option('-f, --force', 'force deployment', false)
.action((environment, options) => {
console.log(`Deploying to ${environment}...`);
if (options.force) {
console.log('Force mode enabled');
}
});
program.parse();

View File

@@ -0,0 +1,282 @@
#!/usr/bin/env node
import { Command, Option } from 'commander';
import chalk from 'chalk';
import ora from 'ora';
const program = new Command();
// Configure main program
program
.name('mycli')
.description('A powerful CLI tool with all Commander.js features')
.version('1.0.0')
.option('-c, --config <path>', 'config file path', './config.json')
.option('-v, --verbose', 'verbose output', false)
.option('--no-color', 'disable colored output');
// Init command
program
.command('init')
.description('Initialize a new project')
.option('-t, --template <type>', 'project template', 'basic')
.option('-d, --directory <path>', 'target directory', '.')
.option('-f, --force', 'overwrite existing files', false)
.action(async (options) => {
const spinner = ora('Initializing project...').start();
try {
await new Promise((resolve) => setTimeout(resolve, 1000));
spinner.text = 'Creating directory structure...';
await new Promise((resolve) => setTimeout(resolve, 500));
spinner.text = 'Copying template files...';
await new Promise((resolve) => setTimeout(resolve, 500));
spinner.text = 'Installing dependencies...';
await new Promise((resolve) => setTimeout(resolve, 1000));
spinner.succeed(chalk.green('Project initialized successfully!'));
console.log(chalk.blue('\nNext steps:'));
console.log(` cd ${options.directory}`);
console.log(' mycli dev');
} catch (error) {
spinner.fail(chalk.red('Initialization failed'));
throw error;
}
});
// Dev command
program
.command('dev')
.description('Start development server')
.option('-p, --port <port>', 'server port', '3000')
.option('-h, --host <host>', 'server host', 'localhost')
.option('--open', 'open browser automatically', false)
.action((options) => {
console.log(chalk.blue('Starting development server...'));
console.log(`Server running at http://${options.host}:${options.port}`);
if (options.open) {
console.log(chalk.gray('Opening browser...'));
}
});
// Build command
program
.command('build')
.description('Build for production')
.addOption(
new Option('-m, --mode <mode>', 'build mode')
.choices(['development', 'production'])
.default('production')
)
.option('--analyze', 'analyze bundle size', false)
.option('--sourcemap', 'generate source maps', false)
.action(async (options) => {
const spinner = ora('Building for production...').start();
try {
await new Promise((resolve) => setTimeout(resolve, 2000));
spinner.succeed(chalk.green('Build complete!'));
console.log(chalk.blue('\nBuild info:'));
console.log('Mode:', options.mode);
console.log('Source maps:', options.sourcemap ? 'enabled' : 'disabled');
if (options.analyze) {
console.log(chalk.gray('\nBundle analysis:'));
console.log(' main.js: 245 KB');
console.log(' vendor.js: 892 KB');
}
} catch (error) {
spinner.fail(chalk.red('Build failed'));
throw error;
}
});
// Deploy command with nested subcommands
const deploy = program.command('deploy').description('Deployment operations');
deploy
.command('start <environment>')
.description('Deploy to specified environment')
.argument('<environment>', 'target environment (dev, staging, prod)')
.addOption(
new Option('-s, --strategy <strategy>', 'deployment strategy')
.choices(['rolling', 'blue-green', 'canary'])
.default('rolling')
)
.option('-f, --force', 'force deployment', false)
.option('--dry-run', 'simulate deployment', false)
.action(async (environment, options) => {
if (options.dryRun) {
console.log(chalk.yellow('🔍 Dry run mode - no actual deployment'));
}
const spinner = ora(`Deploying to ${environment}...`).start();
try {
spinner.text = 'Running tests...';
await new Promise((resolve) => setTimeout(resolve, 1000));
spinner.text = 'Building application...';
await new Promise((resolve) => setTimeout(resolve, 1500));
spinner.text = `Deploying with ${options.strategy} strategy...`;
await new Promise((resolve) => setTimeout(resolve, 2000));
spinner.succeed(chalk.green(`Deployed to ${environment}!`));
console.log(chalk.blue('\nDeployment details:'));
console.log('Environment:', environment);
console.log('Strategy:', options.strategy);
console.log('URL:', `https://${environment}.example.com`);
} catch (error) {
spinner.fail(chalk.red('Deployment failed'));
throw error;
}
});
deploy
.command('rollback [version]')
.description('Rollback to previous version')
.argument('[version]', 'version to rollback to', 'previous')
.option('-f, --force', 'skip confirmation', false)
.action((version, options) => {
if (!options.force) {
console.log(chalk.yellow('⚠ This will rollback your deployment. Use --force to confirm.'));
return;
}
console.log(chalk.blue(`Rolling back to ${version}...`));
console.log(chalk.green('✓ Rollback complete'));
});
deploy
.command('status')
.description('Check deployment status')
.option('-e, --env <environment>', 'check specific environment')
.action((options) => {
console.log(chalk.blue('Deployment status:'));
const envs = options.env ? [options.env] : ['dev', 'staging', 'prod'];
envs.forEach((env) => {
console.log(`\n${env}:`);
console.log(' Status:', chalk.green('healthy'));
console.log(' Version:', '1.2.3');
console.log(' Uptime:', '5d 12h 34m');
});
});
// Config command group
const config = program.command('config').description('Configuration management');
config
.command('get <key>')
.description('Get configuration value')
.action((key) => {
console.log(`${key}: value`);
});
config
.command('set <key> <value>')
.description('Set configuration value')
.action((key, value) => {
console.log(chalk.green(`✓ Set ${key} = ${value}`));
});
config
.command('list')
.description('List all configuration')
.option('-f, --format <format>', 'output format (json, yaml, table)', 'table')
.action((options) => {
console.log(`Configuration (format: ${options.format}):`);
console.log('key1: value1');
console.log('key2: value2');
});
// Database command group
const db = program.command('db').description('Database operations');
db.command('migrate')
.description('Run database migrations')
.option('-d, --dry-run', 'show migrations without running')
.action((options) => {
if (options.dryRun) {
console.log(chalk.blue('Migrations to run:'));
console.log(' 001_create_users.sql');
console.log(' 002_add_email_index.sql');
} else {
console.log(chalk.blue('Running migrations...'));
console.log(chalk.green('✓ 2 migrations applied'));
}
});
db.command('seed')
.description('Seed database with data')
.option('-e, --env <env>', 'environment', 'dev')
.action((options) => {
console.log(chalk.blue(`Seeding ${options.env} database...`));
console.log(chalk.green('✓ Database seeded'));
});
// Test command
program
.command('test [pattern]')
.description('Run tests')
.argument('[pattern]', 'test file pattern', '**/*.test.ts')
.option('-w, --watch', 'watch mode', false)
.option('-c, --coverage', 'collect coverage', false)
.option('--verbose', 'verbose output', false)
.action((pattern, options) => {
console.log(chalk.blue('Running tests...'));
console.log('Pattern:', pattern);
if (options.watch) {
console.log(chalk.gray('Watch mode enabled'));
}
if (options.coverage) {
console.log(chalk.gray('\nCoverage:'));
console.log(' Statements: 85%');
console.log(' Branches: 78%');
console.log(' Functions: 92%');
console.log(' Lines: 87%');
}
console.log(chalk.green('\n✓ 42 tests passed'));
});
// Global error handling
program.exitOverride();
try {
program.parse();
} catch (error: any) {
if (error.code === 'commander.help') {
// Help was displayed, exit normally
process.exit(0);
} else if (error.code === 'commander.version') {
// Version was displayed, exit normally
process.exit(0);
} else {
console.error(chalk.red('Error:'), error.message);
const globalOpts = program.opts();
if (globalOpts.verbose) {
console.error(chalk.gray('\nStack trace:'));
console.error(chalk.gray(error.stack));
}
process.exit(1);
}
}
// Handle no command
if (process.argv.length <= 2) {
program.help();
}

View File

@@ -0,0 +1,150 @@
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
program
.name('mycli')
.description('CLI with nested subcommands')
.version('1.0.0');
// Config command group
const config = program.command('config').description('Manage configuration');
config
.command('get <key>')
.description('Get configuration value')
.action((key) => {
const value = getConfig(key);
if (value) {
console.log(`${key} = ${value}`);
} else {
console.log(chalk.yellow(`Config key '${key}' not found`));
}
});
config
.command('set <key> <value>')
.description('Set configuration value')
.action((key, value) => {
setConfig(key, value);
console.log(chalk.green(`✓ Set ${key} = ${value}`));
});
config
.command('list')
.description('List all configuration')
.option('-f, --format <format>', 'output format (json, table)', 'table')
.action((options) => {
const allConfig = getAllConfig();
if (options.format === 'json') {
console.log(JSON.stringify(allConfig, null, 2));
} else {
Object.entries(allConfig).forEach(([key, value]) => {
console.log(`${key.padEnd(20)} ${value}`);
});
}
});
config
.command('delete <key>')
.description('Delete configuration value')
.option('-f, --force', 'skip confirmation', false)
.action((key, options) => {
if (!options.force) {
console.log(chalk.yellow(`Are you sure? Use --force to confirm`));
return;
}
deleteConfig(key);
console.log(chalk.green(`✓ Deleted ${key}`));
});
// Database command group
const db = program.command('db').description('Database operations');
db.command('migrate')
.description('Run database migrations')
.option('-d, --dry-run', 'show what would be migrated')
.action((options) => {
if (options.dryRun) {
console.log(chalk.blue('Dry run: showing migrations...'));
} else {
console.log(chalk.blue('Running migrations...'));
}
console.log(chalk.green('✓ Migrations complete'));
});
db.command('seed')
.description('Seed database with data')
.option('-e, --env <env>', 'environment', 'dev')
.action((options) => {
console.log(chalk.blue(`Seeding ${options.env} database...`));
console.log(chalk.green('✓ Seeding complete'));
});
db.command('reset')
.description('Reset database')
.option('-f, --force', 'skip confirmation')
.action((options) => {
if (!options.force) {
console.log(chalk.red('⚠ This will delete all data! Use --force to confirm'));
return;
}
console.log(chalk.yellow('Resetting database...'));
console.log(chalk.green('✓ Database reset'));
});
// User command group with nested subcommands
const user = program.command('user').description('User management');
const userList = user.command('list').description('List users');
userList
.option('-p, --page <page>', 'page number', '1')
.option('-l, --limit <limit>', 'items per page', '10')
.action((options) => {
console.log(`Listing users (page ${options.page}, limit ${options.limit})`);
});
user
.command('create <username> <email>')
.description('Create new user')
.option('-r, --role <role>', 'user role', 'user')
.action((username, email, options) => {
console.log(chalk.green(`✓ Created user ${username} (${email}) with role ${options.role}`));
});
user
.command('delete <userId>')
.description('Delete user')
.option('-f, --force', 'skip confirmation')
.action((userId, options) => {
if (!options.force) {
console.log(chalk.red('Use --force to confirm deletion'));
return;
}
console.log(chalk.green(`✓ Deleted user ${userId}`));
});
// Helper functions (mock implementations)
const configStore: Record<string, string> = {
apiUrl: 'https://api.example.com',
timeout: '5000',
};
function getConfig(key: string): string | undefined {
return configStore[key];
}
function setConfig(key: string, value: string): void {
configStore[key] = value;
}
function getAllConfig(): Record<string, string> {
return { ...configStore };
}
function deleteConfig(key: string): void {
delete configStore[key];
}
program.parse();

View File

@@ -0,0 +1,213 @@
import { Command, Option } from 'commander';
import chalk from 'chalk';
const program = new Command();
program
.name('mycli')
.description('Advanced Option class usage')
.version('1.0.0');
program
.command('deploy')
.description('Deploy with advanced option patterns')
// Option with choices
.addOption(
new Option('-e, --env <environment>', 'deployment environment')
.choices(['dev', 'staging', 'prod'])
.default('dev')
)
// Option with custom parser and validation
.addOption(
new Option('-p, --port <port>', 'server port')
.argParser((value) => {
const port = parseInt(value, 10);
if (isNaN(port) || port < 1 || port > 65535) {
throw new Error('Port must be between 1 and 65535');
}
return port;
})
.default(3000)
)
// Mandatory option
.addOption(
new Option('-t, --token <token>', 'API authentication token')
.makeOptionMandatory()
.env('API_TOKEN')
)
// Option from environment variable
.addOption(
new Option('-u, --api-url <url>', 'API base URL')
.env('API_URL')
.default('https://api.example.com')
)
// Conflicting options
.addOption(
new Option('--use-cache', 'enable caching')
.conflicts('noCache')
)
.addOption(
new Option('--no-cache', 'disable caching')
.conflicts('useCache')
)
// Implies relationship
.addOption(
new Option('--ssl', 'enable SSL')
.implies({ sslVerify: true })
)
.addOption(
new Option('--ssl-verify', 'verify SSL certificates')
)
// Preset configurations
.addOption(
new Option('--preset <preset>', 'use preset configuration')
.choices(['minimal', 'standard', 'complete'])
.argParser((value) => {
const presets = {
minimal: { replicas: 1, timeout: 30 },
standard: { replicas: 3, timeout: 60 },
complete: { replicas: 5, timeout: 120 },
};
return presets[value as keyof typeof presets];
})
)
// Hidden option (for debugging)
.addOption(
new Option('--debug', 'enable debug mode')
.hideHelp()
)
// Custom option processing
.addOption(
new Option('-r, --replicas <count>', 'number of replicas')
.argParser((value, previous) => {
const count = parseInt(value, 10);
if (count < 1) {
throw new Error('Replicas must be at least 1');
}
return count;
})
.default(3)
)
.action((options) => {
console.log(chalk.blue('Deployment configuration:'));
console.log('Environment:', chalk.yellow(options.env));
console.log('Port:', options.port);
console.log('Token:', options.token ? chalk.green('***set***') : chalk.red('not set'));
console.log('API URL:', options.apiUrl);
console.log('Cache:', options.useCache ? 'enabled' : 'disabled');
console.log('SSL:', options.ssl ? 'enabled' : 'disabled');
console.log('SSL Verify:', options.sslVerify ? 'enabled' : 'disabled');
if (options.preset) {
console.log('Preset configuration:', options.preset);
}
console.log('Replicas:', options.replicas);
if (options.debug) {
console.log(chalk.gray('\nDebug mode enabled'));
console.log(chalk.gray('All options:'), options);
}
console.log(chalk.green('\n✓ Deployment configuration validated'));
});
// Command demonstrating option dependencies
program
.command('backup')
.description('Backup data with option dependencies')
.addOption(
new Option('-m, --method <method>', 'backup method')
.choices(['full', 'incremental', 'differential'])
.makeOptionMandatory()
)
.addOption(
new Option('--base-backup <path>', 'base backup for incremental')
.conflicts('full')
)
.addOption(
new Option('--compression <level>', 'compression level')
.choices(['none', 'low', 'medium', 'high'])
.default('medium')
)
.action((options) => {
if (options.method === 'incremental' && !options.baseBackup) {
console.log(chalk.red('Error: --base-backup required for incremental backup'));
process.exit(1);
}
console.log(chalk.blue(`Running ${options.method} backup...`));
console.log('Compression:', options.compression);
if (options.baseBackup) {
console.log('Base backup:', options.baseBackup);
}
console.log(chalk.green('✓ Backup complete'));
});
// Command with complex validation
program
.command('scale')
.description('Scale application with complex validation')
.addOption(
new Option('-r, --replicas <count>', 'number of replicas')
.argParser((value) => {
const count = parseInt(value, 10);
if (isNaN(count)) {
throw new Error('Replicas must be a number');
}
if (count < 1 || count > 100) {
throw new Error('Replicas must be between 1 and 100');
}
return count;
})
.makeOptionMandatory()
)
.addOption(
new Option('--cpu <value>', 'CPU limit (millicores)')
.argParser((value) => {
const cpu = parseInt(value, 10);
if (cpu < 100 || cpu > 8000) {
throw new Error('CPU must be between 100 and 8000 millicores');
}
return cpu;
})
.default(1000)
)
.addOption(
new Option('--memory <value>', 'Memory limit (MB)')
.argParser((value) => {
const mem = parseInt(value, 10);
if (mem < 128 || mem > 16384) {
throw new Error('Memory must be between 128 and 16384 MB');
}
return mem;
})
.default(512)
)
.action((options) => {
console.log(chalk.blue('Scaling application:'));
console.log('Replicas:', chalk.yellow(options.replicas));
console.log('CPU:', `${options.cpu}m`);
console.log('Memory:', `${options.memory}MB`);
const totalCpu = options.replicas * options.cpu;
const totalMemory = options.replicas * options.memory;
console.log(chalk.gray('\nTotal resources:'));
console.log(chalk.gray(`CPU: ${totalCpu}m`));
console.log(chalk.gray(`Memory: ${totalMemory}MB`));
console.log(chalk.green('\n✓ Scaling complete'));
});
program.parse();

View File

@@ -0,0 +1,46 @@
{
"name": "{{CLI_NAME}}",
"version": "1.0.0",
"description": "{{DESCRIPTION}}",
"type": "module",
"main": "dist/index.js",
"bin": {
"{{CLI_NAME}}": "dist/index.js"
},
"scripts": {
"build": "tsc",
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"lint": "eslint src --ext .ts",
"format": "prettier --write 'src/**/*.ts'",
"test": "vitest",
"prepublishOnly": "npm run build"
},
"keywords": [
"cli",
"commander",
"typescript"
],
"author": "{{AUTHOR}}",
"license": "MIT",
"dependencies": {
"commander": "^12.0.0",
"chalk": "^5.3.0",
"ora": "^8.0.1",
"inquirer": "^9.2.15"
},
"devDependencies": {
"@types/node": "^20.11.24",
"@types/inquirer": "^9.0.7",
"typescript": "^5.3.3",
"tsx": "^4.7.1",
"eslint": "^8.57.0",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"prettier": "^3.2.5",
"vitest": "^1.3.1"
},
"engines": {
"node": ">=18.0.0"
}
}

View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022"],
"moduleResolution": "node",
"resolveJsonModule": true,
"allowJs": true,
"outDir": "./dist",
"rootDir": "./src",
"removeComments": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}