https://github.com/robingenz/zli
📟 A powerful CLI parser built with TypeScript and Zod for type-safe command-line interfaces.
https://github.com/robingenz/zli
cli parser zod
Last synced: 5 months ago
JSON representation
📟 A powerful CLI parser built with TypeScript and Zod for type-safe command-line interfaces.
- Host: GitHub
- URL: https://github.com/robingenz/zli
- Owner: robingenz
- License: mit
- Created: 2025-08-18T18:46:45.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-09-01T20:09:42.000Z (5 months ago)
- Last Synced: 2025-09-02T14:04:26.427Z (5 months ago)
- Topics: cli, parser, zod
- Language: TypeScript
- Homepage:
- Size: 410 KB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# @robingenz/zli
[](https://www.npmjs.com/package/@robingenz/zli)
[](https://www.npmjs.com/package/@robingenz/zli)
[](https://github.com/robingenz/zli/blob/main/LICENSE)
A powerful CLI parser built with TypeScript and Zod for type-safe command-line interfaces.
## Features
- 🛡️ **Type-safe**: Built with TypeScript and Zod for runtime validation.
- 📋 **Declarative**: Define commands, options, and arguments with simple schemas.
- 🔄 **Flexible parsing**: Support for long flags, short flags, and flag clustering.
- 🔀 **Smart conversion**: Automatic kebab-case to camelCase conversion.
- 🏷️ **Alias support**: Define short aliases for any option.
- 📦 **Array handling**: Automatic normalization of single values to arrays.
- 🎯 **Default commands**: Set a default command to run when no command is specified.
- ❓ **Help message**: Automatic help generation for commands and options.
- ⚠️ **Error handling**: Clear, actionable error messages.
- 🚀 **Zero dependencies**: Only requires Zod as a peer dependency.
- 📦 **ESM support**: Modern ES modules with full TypeScript support.
## Installation
```bash
npm install @robingenz/zli zod
```
## Usage
### Basic Example
```javascript
import { z } from 'zod';
import { defineConfig, defineCommand, defineOptions, processConfig } from '@robingenz/zli';
// Define a simple command
const greetCommand = defineCommand({
description: 'Greet someone',
options: defineOptions(
z.object({
name: z.string().describe('Name to greet'),
loud: z.boolean().default(false).describe('Use uppercase'),
}),
{ n: 'name', l: 'loud' } // Short aliases
),
action: async (options) => {
const greeting = `Hello, ${options.name}!`;
console.log(options.loud ? greeting.toUpperCase() : greeting);
},
});
// Configure the CLI
const config = defineConfig({
meta: {
name: 'my-cli',
version: '1.0.0',
description: 'A simple CLI example',
},
commands: {
greet: greetCommand,
},
defaultCommand: greetCommand,
});
// Process command line arguments
try {
const result = processConfig(config, process.argv.slice(2));
await result.command.action(result.options, result.args);
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
```
### Command Usage
```bash
# Show help
my-cli --help
my-cli greet --help
# Run commands
my-cli greet --name Alice
my-cli greet -n Bob --loud
# Run default command
my-cli --name Alice
my-cli greet --name Alice
```
### Advanced Features
#### Default Commands
You can specify a default command that will be executed when no command is provided:
```javascript
const config = defineConfig({
meta: {
name: 'my-app',
version: '1.0.0',
},
commands: {
start: startCommand,
build: buildCommand,
},
defaultCommand: startCommand,
});
```
With this configuration:
- `my-app` will run the `startCommand`
- `my-app --help` will still show the help message
- `my-app build` will run the `build` command
#### Commands with Arguments
```javascript
const copyCommand = defineCommand({
description: 'Copy a file',
args: z.tuple([
z.string().describe('Source file'),
z.string().describe('Destination file'),
]),
options: defineOptions(
z.object({
verbose: z.boolean().default(false).describe('Verbose output'),
}),
{ v: 'verbose' }
),
action: async (options, args) => {
const [source, dest] = args;
console.log(`Copying ${source} to ${dest}`);
},
});
```
#### Array Options
```javascript
const options = defineOptions(
z.object({
files: z.array(z.string()).describe('Input files'),
tags: z.array(z.string()).optional().describe('Tags to apply'),
})
);
// Usage: --files file1.txt --files file2.txt
// Single values are automatically converted to arrays
```
#### Type Transformations
```javascript
const options = defineOptions(
z.object({
port: z.coerce.number().min(1).max(65535).describe('Port number'),
count: z.coerce.number().min(1).describe('Count'),
})
);
```
### Flag Parsing
`@robingenz/zli` supports various flag formats:
```bash
# Long flags
--verbose --name=value --port 3000
# Short flags
-v -n value -p 3000
# Flag clustering
-abc # equivalent to -a -b -c
# Kebab-case conversion
--my-option # becomes myOption in your code
# Multiple values
--file a.txt --file b.txt # becomes ['a.txt', 'b.txt']
```
### API Reference
#### `defineOptions(schema, aliases?)`
Define options for a command with optional aliases.
- `schema`: Zod object schema defining the options
- `aliases`: Optional object mapping short aliases to option names
#### `defineCommand(config)`
Define a command with options, arguments, and action.
- `description`: Command description for help
- `options`: Options definition (optional)
- `args`: Zod schema for arguments (optional)
- `action`: Function to execute when command is run
#### `defineConfig(config)`
Define the CLI configuration.
- `meta`: CLI metadata (name, version, description)
- `commands`: Object mapping command names to definitions
- `defaultCommand`: Optional default command definition to run when no command is specified
#### `processConfig(config, args)`
Process command line arguments and return the result.
- `config`: CLI configuration
- `args`: Command line arguments (typically `process.argv.slice(2)`)
Returns an object with:
- `command`: The matched command definition
- `options`: Parsed and validated options
- `args`: Parsed and validated arguments
## Changelog
See [CHANGELOG.md](./CHANGELOG.md).
## License
See [LICENSE](./LICENSE).