@bunli/generator
Generate TypeScript definitions from CLI commands for enhanced developer experience
@bunli/generator has minimal dependencies and uses Babel for AST parsing to extract command metadata from your TypeScript files.
Installation
bash bun add @bunli/generator
bash npm install @bunli/generator
bash pnpm add @bunli/generator
Features
- 🚀 Fast Generation - Uses Babel for efficient AST parsing
- 📝 Type Safety - Generates fully typed TypeScript definitions
- 🔄 Watch Mode - Automatically regenerate on file changes
- 🎯 Command Discovery - Scans and parses command files automatically
- 🔌 Plugin Integration - Works seamlessly with Bunli's plugin system
- ⚡ Build Integration - Integrates with
bunli devandbunli build - 🛠️ CLI Tool - Standalone
bunli generatecommand
Core APIs
Generator Class
The main class for generating TypeScript definitions:
import { Generator } from "@bunli/generator";
const generator = new Generator({
entry: "./src/cli.ts",
directory: "./src/commands",
outputFile: "./.bunli/commands.gen.ts",
config: {}, // Optional config object
generateReport: false, // Optional report generation
});
// Generate types once
await generator.run();
// Generate with specific options
await generator.run({
type: "update",
path: "./commands/new-command.ts",
});CommandScanner
Scans directories for command files:
import { CommandScanner } from "@bunli/generator";
const scanner = new CommandScanner();
const files = await scanner.scanCommands("./src/cli.ts", "./src/commands");
console.log(files); // ['greet.ts', 'deploy.ts', 'test.ts']parseCommand Function
Parse individual command files:
import { parseCommand } from "@bunli/generator";
const commandData = await parseCommand("./commands/greet.ts", "./src", "./.bunli/commands.gen.ts");
console.log(commandData);
// {
// name: 'greet',
// description: 'Greet someone',
// options: { ... },
// alias: ['hello'],
// filePath: './commands/greet.ts',
// importPath: '../commands/greet',
// exportPath: 'greet'
// }buildTypes Function
Build TypeScript definitions from command data:
import { buildTypes } from '@bunli/generator'
const commands = [
{ name: 'greet', description: 'Greet someone', options: { ... } },
{ name: 'deploy', description: 'Deploy app', options: { ... } }
]
const types = buildTypes(commands)
console.log(types) // Generated TypeScript codePlugin Integration
bunliCodegenPlugin
Use as a Bun plugin for build integration:
import { bunliCodegenPlugin } from "@bunli/generator";
// In your build configuration
export default {
plugins: [
bunliCodegenPlugin({
entry: "./src/cli.ts",
directory: "./src/commands",
outputFile: "./.bunli/commands.gen.ts",
}),
],
};CLI Integration
The generator is automatically integrated with Bunli CLI commands:
# Development mode with watch
bunli dev
# Build with type generation
bunli build
# Standalone generation
bunli generate --watchConfiguration Options
Generator Options
Configuration for type generation
| Option | Type | Default | Description |
|---|---|---|---|
entry | string | './cli.ts' | CLI entry file used for command discovery |
directory | string | undefined | Optional fallback directory for command scanning |
outputFile | string | './commands.gen.ts' | Output file for generated types |
include | string[] | ['**/*.ts', '**/*.js'] | File patterns to include |
exclude | string[] | ['**/*.test.*', '**/*.spec.*'] | File patterns to exclude |
Generated Output Structure
The generator creates .bunli/commands.gen.ts which exports a GeneratedStore instance:
GeneratedStore Interface
The generated file exports a cli object (a GeneratedStore instance) and named command exports:
// Named command exports
export { greet } from "../src/commands/greet.js";
export { deploy } from "../src/commands/deploy.js";
// Generated command metadata
export const metadata: Record<string, GeneratedCommandMeta>;
// Generated store instance
export const cli: GeneratedStore<typeof commands, typeof metadata>;GeneratedStore Methods
interface GeneratedStore<TModules, TMeta> {
commands: TModules;
metadata: TMeta;
register(cli?: CLI<any>): GeneratedStore<TModules, TMeta>;
list(): Array<{
name: keyof TModules;
command: TModules[keyof TModules];
metadata: TMeta[keyof TModules];
}>;
get<Name extends keyof TModules>(name: Name): TModules[Name];
getMetadata<Name extends keyof TModules>(name: Name): TMeta[Name];
findByName<Name extends keyof TModules>(
name: Name,
): { name: Name; command: TModules[Name]; metadata: TMeta[Name] };
findByDescription(searchTerm: string): Array<{
name: keyof TModules;
command: TModules[keyof TModules];
metadata: TMeta[keyof TModules];
}>;
getCommandNames(): Array<keyof TModules & string>;
getFlags<Name extends keyof RegisteredCommands>(name: Name): Record<string, unknown>;
getFlagsMeta<Name extends keyof TModules>(name: Name): Record<string, GeneratedOptionMeta>;
validateCommand<Name extends keyof TModules>(
name: Name,
flags: Record<string, unknown>,
): { success: true; data: Record<string, unknown> } | { success: false; errors: string[] };
withCLI(cli: CLI<any>): GeneratedExecutor<TModules>;
}GeneratedExecutor
interface GeneratedExecutor<TModules extends Record<string, Command<any>>> {
execute(name: string, options: unknown): Promise<void>;
}Usage
Basic Generation
import { Generator } from "@bunli/generator";
const generator = new Generator({
entry: "./src/cli.ts",
directory: "./src/commands",
outputFile: "./.bunli/commands.gen.ts",
});
await generator.run();Watch Mode
Watch mode is handled by the CLI command:
bunli generate --watchPerformance
- Scanning: ~10ms for 50 command files
- Parsing: ~5ms per command file
- Generation: ~2ms for 20 commands
- Watch Mode: <1ms incremental updates
API Reference
Generator
class Generator {
constructor(options: GeneratorConfig);
// Generate types
run(options?: GeneratorEvent): Promise<Result<void, GeneratorRunError>>;
// Get current configuration
getConfig(): GeneratorConfig;
// Update configuration
updateConfig(options: Partial<GeneratorConfig>): void;
}GeneratorConfig
interface GeneratorConfig {
entry: string;
directory?: string;
outputFile: string;
config?: any;
generateReport?: boolean;
}GeneratorEvent
interface GeneratorEvent {
type: "create" | "update" | "delete";
path: string;
}CommandMetadata
interface CommandMetadata {
name: string;
description: string;
alias?: string | string[];
options?: Record<string, OptionMetadata>;
commands?: CommandMetadata[];
filePath: string;
importPath: string;
exportPath: string;
hasHandler?: boolean;
hasRender?: boolean;
}
interface OptionMetadata {
type: string;
required: boolean;
hasDefault: boolean;
default?: any;
description?: string;
short?: string;
schema?: any;
validator?: string;
}Integration
With Bunli CLI
// bunli.config.ts
import { defineConfig } from "@bunli/core";
export default defineConfig({
name: "my-cli",
version: "1.0.0",
});With Custom Build Script
import { Generator } from "@bunli/generator";
const generator = new Generator({
entry: "./src/cli.ts",
directory: "./src/commands",
outputFile: "./.bunli/commands.gen.ts",
});
await generator.run();Troubleshooting
Generation fails:
- Check that command files use
defineCommand - Verify TypeScript syntax is correct
Types not updating:
- Use
bunli generate --watchfor development - Check file paths are correct
Import errors:
- Ensure generated file exists at
./.bunli/commands.gen.ts - Verify TypeScript configuration
See Also
- Type Generation Guide - Complete guide to using generated types
- bunli CLI - CLI toolchain with integrated generation
- Configuration - Configure code generation
- @bunli/core - Core framework with type utilities