args-kingdom
v1.0.0
Published
Clean CLI framework with commands, help, and validation - a better yargs
Maintainers
Readme
args-kingdom
Clean CLI framework with full yargs features, but lighter
A modern, TypeScript-first CLI framework. All the power of yargs, but cleaner and lighter.
Why args-kingdom?
| Feature | args-kingdom | yargs | commander | |---------|-------|-------|-----------| | Bundle size | ~16 KB | 231 KB | 208 KB | | TypeScript-first | Yes | Partial | Partial | | Type inference | Full | Limited | Limited | | Zero deps | Yes | No | No |
Full Feature Parity with yargs
| Feature | args-kingdom | yargs |
|---------|-------|-------|
| Subcommands | Yes | Yes |
| Positional args <required> [optional] | Yes | Yes |
| Auto help (--help) | Yes | Yes |
| Version (-V) | Yes | Yes |
| Aliases (-p for --port) | Yes | Yes |
| Boolean negation (--no-verbose) | Yes | Yes |
| Array options (--file a --file b) | Yes | Yes |
| Count options (-vvv = 3) | Yes | Yes |
| Validation (required, choices) | Yes | Yes |
| Conflicts & Implies | Yes | Yes |
| Coerce functions | Yes | Yes |
| Middleware | Yes | Yes |
| Environment variables | Yes | Yes |
| Config file loading | Yes | Yes |
| Default command | Yes | Yes |
| Demand command | Yes | Yes |
| Strict mode | Yes | Yes |
| Fail handler | Yes | Yes |
| Examples in help | Yes | Yes |
| Option groups | Yes | Yes |
| Epilog | Yes | Yes |
Install
npm install args-kingdomQuick Start
import { cli } from 'args-kingdom';
cli('myapp', '1.0.0')
.env('MYAPP') // Load MYAPP_PORT from env
.command('serve', 'Start the server')
.positional('<port>', { desc: 'Port number' })
.option('host', { alias: 'h', type: 'string', default: 'localhost' })
.option('verbose', { alias: 'v', type: 'count', desc: 'Verbosity level' })
.example('myapp serve 3000', 'Start on port 3000')
.example('myapp serve 8080 -vvv', 'Start with max verbosity')
.action((args) => {
console.log(`Server on ${args.host}:${args.port} (verbosity: ${args.verbose})`);
})
.run();$ myapp serve 3000 -vvv
Server on localhost:3000 (verbosity: 3)
$ MYAPP_HOST=0.0.0.0 myapp serve 8080
Server on 0.0.0.0:8080 (verbosity: 0)API Reference
Creating a CLI
import { cli } from 'args-kingdom';
const app = cli('myapp', '1.0.0');Options
.option('name', {
alias: 'n', // Short flag (-n) or array ['-n', '--nm']
type: 'string', // 'string' | 'number' | 'boolean' | 'array' | 'count'
default: 'world', // Default value
desc: 'Your name', // Description for help
required: true, // Make it required
choices: ['a', 'b'], // Limit valid values
conflicts: 'other', // Can't use with --other
implies: 'required', // Requires --required to be set
coerce: (v) => v.trim(), // Transform the value
env: 'MY_NAME', // Load from environment variable
group: 'User Options:' // Group in help output
})Option Types
// String (default)
.option('name', { type: 'string' })
// --name hello → 'hello'
// Number
.option('port', { type: 'number', default: 3000 })
// --port 8080 → 8080
// Boolean
.option('verbose', { type: 'boolean' })
// --verbose → true, --no-verbose → false
// Array (multiple values)
.option('files', { type: 'array' })
// --files a.txt --files b.txt → ['a.txt', 'b.txt']
// Count (count occurrences)
.option('verbose', { alias: 'v', type: 'count' })
// -v → 1, -vvv → 3Positional Arguments
.command('copy', 'Copy files')
.positional('<source>', { desc: 'Source file' }) // Required
.positional('[dest]', { desc: 'Destination', default: '.' }) // Optional
.action((args) => {
console.log(`Copying ${args.source} to ${args.dest}`);
})
// $ myapp copy file.txt /tmp
// args.source = 'file.txt'
// args.dest = '/tmp'Subcommands
cli('git')
.command('remote', 'Manage remotes')
.command('add', 'Add a remote')
.positional('<name>')
.positional('<url>')
.action((args) => { /* ... */ })
.run();
// $ git remote add origin https://github.com/...Default Command
cli('myapp')
.command('serve', 'Start server')
.default() // Runs when no command specified
.option('port', { type: 'number', default: 3000 })
.action((args) => console.log(`Port: ${args.port}`))
.run();
// $ myapp --port 8080
// Port: 8080Middleware
.command('deploy', 'Deploy app')
.middleware(async (args) => {
// Add computed properties
return { ...args, timestamp: Date.now() };
})
.middleware((args) => {
// Auth check
if (!process.env.API_KEY) throw new Error('API_KEY required');
})
.action((args) => {
console.log(`Deploying at ${args.timestamp}`);
})Environment Variables
cli('myapp')
.env('MYAPP') // Prefix for all options
.command('serve', 'Start server')
.option('port', { type: 'number' }) // MYAPP_PORT
.option('host', { type: 'string' }) // MYAPP_HOST
.option('apiKey', { env: 'API_KEY' }) // Custom env name
.action((args) => { /* ... */ })
.run();
// $ MYAPP_PORT=8080 myapp serveConfig File
cli('myapp')
.configFile('./myapp.config.json')
.command('build', 'Build project')
.option('outDir', { type: 'string' })
.action((args) => { /* ... */ })
.run();Validation
// Conflicts - can't use together
.option('json', { type: 'boolean', conflicts: 'verbose' })
.option('verbose', { type: 'boolean' })
// Error: Options --json and --verbose cannot be used together
// Implies - requires another option
.option('cache', { type: 'boolean', implies: 'output' })
.option('output', { type: 'string' })
// Error: Option --cache requires --output
// Choices
.option('env', { type: 'string', choices: ['dev', 'prod'] })
// Error: Invalid value for --env: "staging". Choices: dev, prodCoerce (Transform Values)
.option('date', {
type: 'string',
coerce: (v) => new Date(v)
})
// --date 2024-01-01 → Date object
.option('json', {
type: 'string',
coerce: JSON.parse
})
// --json '{"a":1}' → { a: 1 }Strict Mode
cli('myapp')
.strict() // Error on unknown options
.command('test', 'Run tests')
.action(() => {})
.run();
// $ myapp test --unknown
// Error: Unknown option: --unknownDemand Command
cli('myapp')
.demandCommand(1, 'Please specify a command')
.command('serve', 'Start server')
.command('build', 'Build project')
.run();
// $ myapp
// Error: Please specify a commandFail Handler
cli('myapp')
.fail((msg, err) => {
console.error(`Error: ${msg}`);
process.exit(1);
})
.command('deploy', 'Deploy')
.option('env', { required: true })
.action(() => {})
.run();Help Customization
.command('serve', 'Start the server')
.option('port', { type: 'number', desc: 'Port number' })
.option('host', { type: 'string', desc: 'Host to bind' })
.option('ssl', { type: 'boolean', desc: 'Enable SSL' })
.group(['port', 'host'], 'Server Options:')
.group(['ssl'], 'Security Options:')
.example('myapp serve --port 3000', 'Start on port 3000')
.example('myapp serve --ssl', 'Start with SSL')
.epilog('For more info, visit https://example.com')Output:
Usage: myapp serve [options]
Start the server
Server Options:
--port <number> Port number
--host <string> Host to bind
Security Options:
--ssl Enable SSL
Options:
-h, --help Show help
Examples:
$ myapp serve --port 3000
Start on port 3000
$ myapp serve --ssl
Start with SSL
For more info, visit https://example.comSimple Parsing
For scripts that don't need commands:
import { parse } from 'args-kingdom';
const args = parse({
port: { type: 'number', default: 3000 },
verbose: { alias: 'v', type: 'count' },
files: { type: 'array' }
});
// $ node script.js --port 8080 -vvv --files a.txt --files b.txt
args.port // 8080
args.verbose // 3
args.files // ['a.txt', 'b.txt']Comparison with yargs
args-kingdom
import { cli } from 'args-kingdom';
cli('myapp', '1.0.0')
.env('MYAPP')
.command('serve', 'Start server')
.positional('<port>')
.option('host', { alias: 'h', default: 'localhost' })
.option('verbose', { alias: 'v', type: 'count' })
.action((args) => console.log(`${args.host}:${args.port}`))
.run();yargs
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
yargs(hideBin(process.argv))
.env('MYAPP')
.command('serve <port>', 'Start server', (yargs) => {
return yargs
.positional('port', { type: 'number' })
.option('host', { alias: 'h', default: 'localhost' })
.option('verbose', { alias: 'v', type: 'count' })
}, (argv) => {
console.log(`${argv.host}:${argv.port}`)
})
.parse();Support
License
MIT
