0
# Custom Generators
1
2
System for running custom plop-based generators with Turborepo integration, supporting both TypeScript and JavaScript generator configurations.
3
4
## Capabilities
5
6
### Run Function
7
8
Main function for executing custom generators programmatically.
9
10
```typescript { .api }
11
/**
12
* Execute a custom generator
13
* @param generator - Name of the generator to run (undefined for interactive selection)
14
* @param opts - Custom generator options
15
* @returns Promise that resolves when generator execution is complete
16
*/
17
function run(generator: string | undefined, opts: CustomGeneratorCLIOptions): Promise<void>;
18
19
interface CustomGeneratorCLIOptions {
20
/** Generator configuration file path */
21
config?: string;
22
/** Repository root directory */
23
root?: string;
24
/** Arguments passed directly to generator */
25
args?: Array<string>;
26
}
27
```
28
29
**Usage Examples:**
30
31
```typescript
32
import { run } from "@turbo/gen/dist/commands";
33
34
// Run with interactive generator selection
35
await run(undefined, {
36
config: "./turbo/generators/config.js"
37
});
38
39
// Run specific generator
40
await run("my-component", {
41
config: "./turbo/generators/config.js",
42
args: ["name=Button", "type=component"]
43
});
44
45
// Run with custom config
46
await run("api-route", {
47
config: "./custom-generators/config.ts",
48
root: "/path/to/project"
49
});
50
```
51
52
### Custom Generator Function
53
54
Low-level function for custom generator execution.
55
56
```typescript { .api }
57
/**
58
* Execute custom generator with detailed arguments
59
* @param args - Custom generator arguments
60
* @returns Promise that resolves when generation is complete
61
*/
62
function generate(args: CustomGeneratorArguments): Promise<void>;
63
64
interface CustomGeneratorArguments {
65
generator: string | undefined;
66
project: Project;
67
opts: CustomGeneratorCLIOptions;
68
}
69
```
70
71
**Usage Examples:**
72
73
```typescript
74
import { generate as customGenerate } from "@turbo/gen/dist/generators/custom";
75
import { getProject } from "@turbo/gen/dist/utils/getProject";
76
77
const project = await getProject({ root: process.cwd() });
78
79
await customGenerate({
80
generator: "component",
81
project,
82
opts: {
83
config: "./turbo/generators/config.js",
84
args: ["name=MyComponent", "directory=components"]
85
}
86
});
87
```
88
89
## Plop Integration
90
91
### Plop API Access
92
93
Get access to the underlying node-plop API for advanced generator operations.
94
95
```typescript { .api }
96
/**
97
* Get NodePlopAPI instance for direct plop operations
98
* @param args - Plop configuration
99
* @returns NodePlopAPI instance or undefined if config not found
100
*/
101
function getPlop(args: {
102
project: Project;
103
configPath?: string;
104
}): NodePlopAPI | undefined;
105
```
106
107
### Generator Discovery
108
109
Find and list available custom generators.
110
111
```typescript { .api }
112
/**
113
* Get list of all available custom generators
114
* @param args - Generator discovery configuration
115
* @returns Array of generators or separators for UI display
116
*/
117
function getCustomGenerators(args: {
118
project: Project;
119
configPath?: string;
120
}): Array<Generator | Separator>;
121
122
/**
123
* Get specific generator by name
124
* @param args - Generator lookup configuration
125
* @returns Generator name or undefined if not found
126
*/
127
function getCustomGenerator(args: {
128
project: Project;
129
generator: string;
130
configPath?: string;
131
}): string | undefined;
132
133
type Generator = PlopGenerator & {
134
basePath: string;
135
name: string;
136
};
137
```
138
139
### Generator Execution
140
141
Direct generator execution utilities.
142
143
```typescript { .api }
144
/**
145
* Run a custom generator with bypass arguments
146
* @param args - Generator execution configuration
147
* @returns Promise that resolves when generator completes
148
*/
149
function runCustomGenerator(args: {
150
project: Project;
151
generator: string;
152
bypassArgs?: Array<string>;
153
configPath?: string;
154
}): Promise<void>;
155
```
156
157
**Usage Examples:**
158
159
```typescript
160
import {
161
getPlop,
162
getCustomGenerators,
163
getCustomGenerator,
164
runCustomGenerator
165
} from "@turbo/gen/dist/utils/plop";
166
167
// Get plop instance
168
const plop = getPlop({
169
project,
170
configPath: "./turbo/generators/config.js"
171
});
172
173
// Get all generators
174
const generators = getCustomGenerators({
175
project,
176
configPath: "./turbo/generators/config.js"
177
});
178
179
// Find specific generator
180
const generator = getCustomGenerator({
181
project,
182
generator: "component",
183
configPath: "./turbo/generators/config.js"
184
});
185
186
// Run generator with arguments
187
await runCustomGenerator({
188
project,
189
generator: "component",
190
bypassArgs: ["Button", "components/ui"],
191
configPath: "./turbo/generators/config.js"
192
});
193
```
194
195
## Template Setup
196
197
### Template Initialization
198
199
Set up generator templates for new projects.
200
201
```typescript { .api }
202
/**
203
* Set up generator configuration from built-in templates
204
* @param args - Template setup configuration
205
* @returns Promise that resolves when template is set up
206
*/
207
function setupFromTemplate(args: {
208
project: Project;
209
template: "ts" | "js";
210
}): Promise<void>;
211
```
212
213
**Usage Examples:**
214
215
```typescript
216
import { setupFromTemplate } from "@turbo/gen/dist/utils/setupFromTemplate";
217
218
// Set up TypeScript generator template
219
await setupFromTemplate({
220
project,
221
template: "ts"
222
});
223
224
// Set up JavaScript generator template
225
await setupFromTemplate({
226
project,
227
template: "js"
228
});
229
```
230
231
## Interactive Prompts
232
233
Programmatic access to generator selection and setup prompts.
234
235
### Generator Selection
236
237
```typescript { .api }
238
/**
239
* Prompt for generator selection from available generators
240
* @param args - Generator selection configuration
241
* @returns Promise with selected generator name
242
*/
243
function customGenerators(args: {
244
generators: Array<Generator | Separator>;
245
generator?: string;
246
}): Promise<{ selectedGenerator: string }>;
247
```
248
249
### Template Choice
250
251
```typescript { .api }
252
/**
253
* Prompt for generator template language choice
254
* @returns Promise with selected template type
255
*/
256
function chooseGeneratorTemplate(): Promise<{ answer: "ts" | "js" }>;
257
```
258
259
### Confirmation Prompt
260
261
```typescript { .api }
262
/**
263
* Display confirmation prompt to user
264
* @param args - Confirmation prompt configuration
265
* @returns Promise with user's boolean response
266
*/
267
function confirm(args: { message: string }): Promise<{ answer: boolean }>;
268
```
269
270
**Usage Examples:**
271
272
```typescript
273
import {
274
customGenerators,
275
chooseGeneratorTemplate,
276
confirm
277
} from "@turbo/gen/dist/commands/run/prompts";
278
279
// Select generator
280
const generators = getCustomGenerators({ project });
281
const selection = await customGenerators({
282
generators,
283
generator: undefined
284
});
285
286
// Choose template type
287
const template = await chooseGeneratorTemplate();
288
289
// Confirm action
290
const confirmation = await confirm({
291
message: "Are you sure you want to create this generator?"
292
});
293
```
294
295
## Generator Configuration
296
297
### Configuration File Structure
298
299
Custom generators are configured using node-plop configuration files:
300
301
**TypeScript Configuration (`turbo/generators/config.ts`):**
302
303
```typescript
304
import type { PlopTypes } from "@turbo/gen";
305
306
const config: PlopTypes.PlopConfig = {
307
generator: {
308
description: "Create a new component",
309
prompts: [
310
{
311
type: "input",
312
name: "name",
313
message: "Component name:",
314
validate: (input: string) => input.length > 0
315
}
316
],
317
actions: [
318
{
319
type: "add",
320
path: "{{ turbo.paths.root }}/packages/ui/src/{{ dashCase name }}.tsx",
321
templateFile: "templates/component.hbs"
322
}
323
]
324
}
325
};
326
327
export default config;
328
```
329
330
**JavaScript Configuration (`turbo/generators/config.js`):**
331
332
```javascript
333
module.exports = {
334
generator: {
335
description: "Create a new component",
336
prompts: [
337
{
338
type: "input",
339
name: "name",
340
message: "Component name:"
341
}
342
],
343
actions: [
344
{
345
type: "add",
346
path: "{{ turbo.paths.root }}/packages/ui/src/{{ dashCase name }}.tsx",
347
templateFile: "templates/component.hbs"
348
}
349
]
350
}
351
};
352
```
353
354
### Built-in Template Files
355
356
Turbo Gen includes built-in templates for generator setup:
357
358
- **TypeScript template**: `dist/templates/simple-ts/`
359
- `config.ts` - TypeScript generator configuration
360
- `templates/turborepo-generators.hbs` - Handlebars template
361
- `package.json` - Package metadata
362
363
- **JavaScript template**: `dist/templates/simple-js/`
364
- `config.js` - JavaScript generator configuration
365
- `templates/turborepo-generators.hbs` - Handlebars template
366
- `package.json` - Package metadata
367
368
### Turbo-Specific Variables
369
370
Custom generators have access to Turbo-specific template variables:
371
372
```handlebars
373
374
375
376
```
377
378
**Usage in Templates:**
379
380
```handlebars
381
382
383
384
385
386
387
388
389
390
391
392
393
```
394
395
## Error Handling
396
397
Custom generator operations can throw specific error types:
398
399
```typescript { .api }
400
type GenerateErrorType =
401
| "plop_error_running_generator"
402
| "plop_unable_to_load_config"
403
| "plop_generator_not_found"
404
| "plop_no_config"
405
| "config_directory_already_exists"
406
| "unknown";
407
408
class GeneratorError extends Error {
409
public type: GenerateErrorType;
410
constructor(message: string, opts?: GeneratorErrorOptions);
411
}
412
413
interface GeneratorErrorOptions {
414
type?: GenerateErrorType;
415
}
416
```
417
418
Common error scenarios:
419
- Generator configuration file not found or invalid
420
- Selected generator doesn't exist in configuration
421
- Plop execution errors during file generation
422
- Permission issues when creating files
423
- Template file not found or malformed