0
# Code Generation
1
2
Generate CLI components including commands and hooks using oclif's template system and code generators.
3
4
## Capabilities
5
6
### Generate Command
7
8
Adds a new command to an existing oclif CLI or plugin using predefined templates.
9
10
```bash { .api }
11
oclif generate command [NAME]
12
```
13
14
**Arguments:**
15
- `NAME` (string, required) - Name of the command to create
16
17
**Flags:**
18
- `--commands-dir` (string) - Directory to create the command file in
19
- `--force` (boolean) - Overwrite existing command file if it exists
20
21
**Usage Examples:**
22
23
```bash
24
# Generate a simple command
25
oclif generate command hello
26
27
# Generate nested command
28
oclif generate command users:list
29
30
# Generate with custom directory
31
oclif generate command deploy --commands-dir=./src/commands
32
33
# Force overwrite existing command
34
oclif generate command existing-cmd --force
35
```
36
37
**Generated Command Structure:**
38
39
```typescript
40
import { Args, Command, Flags } from '@oclif/core'
41
42
export default class Hello extends Command {
43
static description = 'describe the command here'
44
45
static examples = [
46
'<%= config.bin %> <%= command.id %>',
47
]
48
49
static flags = {
50
// flag with a value (-n, --name=VALUE)
51
name: Flags.string({char: 'n', description: 'name to print'}),
52
// flag with no value (-f, --force)
53
force: Flags.boolean({char: 'f'}),
54
}
55
56
static args = {
57
file: Args.string({description: 'file to read'}),
58
}
59
60
async run(): Promise<void> {
61
const {args, flags} = await this.parse(Hello)
62
63
const name = flags.name ?? 'world'
64
this.log(`hello ${name} from ./src/commands/hello/world.ts`)
65
if (args.file && flags.force) {
66
this.log(`you input --force and --file: ${args.file}`)
67
}
68
}
69
}
70
```
71
72
### Generate Hook
73
74
Adds a new hook to an existing oclif CLI or plugin for extending functionality at specific lifecycle points.
75
76
```bash { .api }
77
oclif generate hook [NAME]
78
```
79
80
**Arguments:**
81
- `NAME` (string, required) - Name of the hook to create (snake_case)
82
83
**Flags:**
84
- `--event` (string) - Event to run hook on (default: "init")
85
- `--force` (boolean) - Overwrite existing hook file if it exists
86
87
**Usage Examples:**
88
89
```bash
90
# Generate a basic init hook
91
oclif generate hook analytics
92
93
# Generate hook for specific event
94
oclif generate hook my_prerun_hook --event=prerun
95
96
# Force overwrite existing hook
97
oclif generate hook existing_hook --force
98
```
99
100
**Generated Hook Structure:**
101
102
```typescript
103
import { Hook } from '@oclif/core'
104
105
const hook: Hook<'init'> = async function (opts) {
106
// Hook implementation
107
process.stdout.write(`example hook running ${opts.id}\n`)
108
}
109
110
export default hook
111
```
112
113
## Generator Base Classes
114
115
oclif provides base generator classes for creating custom generators and extending the template system.
116
117
### GeneratorCommand Class
118
119
Abstract base class for creating custom file generators using EJS templates.
120
121
```typescript { .api }
122
/**
123
* Base class for commands that generate files from templates
124
*/
125
abstract class GeneratorCommand<T extends typeof Command> extends Command {
126
/** Get flag value or prompt user interactively */
127
protected getFlagOrPrompt<K extends keyof FlagsOfPrompts<any>>(
128
options: GetFlagOrPromptOptions<K>
129
): Promise<any>;
130
131
/** Render EJS template to destination file */
132
protected template(
133
source: string,
134
destination: string,
135
data?: Record<string, any>
136
): Promise<void>;
137
}
138
139
interface GetFlagOrPromptOptions<K> {
140
/** Flag name to check */
141
flag: K;
142
/** Prompt configuration */
143
prompt: FlaggablePrompt;
144
/** Default value if no flag or prompt response */
145
default?: any;
146
}
147
148
interface FlaggablePrompt {
149
/** Prompt message */
150
message: string;
151
/** Prompt type (input, select, confirm) */
152
type: 'input' | 'select' | 'confirm';
153
/** Choices for select prompts */
154
choices?: Array<string | { name: string; value: any }>;
155
/** Initial/default value */
156
initial?: any;
157
}
158
```
159
160
### Utility Functions
161
162
Helper functions for generator implementations and custom generators.
163
164
```typescript { .api }
165
/**
166
* Execute shell command with promise wrapper
167
* @param command - Shell command to execute
168
* @param opts - Execution options
169
* @returns Promise resolving to command output
170
*/
171
function exec(command: string, opts?: ExecOptions): Promise<string>;
172
173
/**
174
* Read and parse package.json file
175
* @param location - Path to package.json
176
* @returns Parsed package.json object
177
*/
178
function readPJSON(location: string): Promise<any>;
179
180
/**
181
* Generate oclif flags from prompt definitions
182
* @param flaggablePrompts - Array of prompt configurations
183
* @returns oclif flag definitions object
184
*/
185
function makeFlags<T extends Record<string, FlaggablePrompt>>(
186
flaggablePrompts: T
187
): FlagsOfPrompts<T>;
188
189
interface ExecOptions {
190
cwd?: string;
191
env?: Record<string, string>;
192
shell?: boolean | string;
193
}
194
195
type FlagsOfPrompts<T extends Record<string, FlaggablePrompt>> = {
196
[K in keyof T]: T[K]['type'] extends 'confirm'
197
? BooleanFlag<boolean>
198
: StringFlag<string | undefined>;
199
};
200
```
201
202
## Template System
203
204
oclif uses EJS templates for code generation with built-in variables and helpers.
205
206
### Template Variables
207
208
```typescript { .api }
209
interface TemplateContext {
210
/** Package configuration */
211
config: {
212
name: string;
213
version: string;
214
bin: string;
215
};
216
/** Command information */
217
command: {
218
id: string;
219
name: string;
220
className: string;
221
};
222
/** User input */
223
answers: Record<string, any>;
224
/** Utility functions */
225
_: {
226
camelCase: (str: string) => string;
227
kebabCase: (str: string) => string;
228
pascalCase: (str: string) => string;
229
snakeCase: (str: string) => string;
230
};
231
}
232
```
233
234
### Template Locations
235
236
Templates are located in the oclif package and can be customized:
237
238
- Command templates: `templates/command/`
239
- Hook templates: `templates/hook/`
240
- Project templates: `templates/cli/`
241
242
**Custom Template Usage:**
243
244
```typescript
245
// In a custom generator command
246
await this.template(
247
path.join(__dirname, '../templates/my-template.ejs'),
248
path.join(this.config.root, 'generated-file.ts'),
249
{
250
className: 'MyClass',
251
description: 'Custom generated class'
252
}
253
);
254
```