Extend a Turborepo with code generation utilities for creating workspaces and custom generators
—
System for running custom plop-based generators with Turborepo integration, supporting both TypeScript and JavaScript generator configurations.
Main function for executing custom generators programmatically.
/**
* Execute a custom generator
* @param generator - Name of the generator to run (undefined for interactive selection)
* @param opts - Custom generator options
* @returns Promise that resolves when generator execution is complete
*/
function run(generator: string | undefined, opts: CustomGeneratorCLIOptions): Promise<void>;
interface CustomGeneratorCLIOptions {
/** Generator configuration file path */
config?: string;
/** Repository root directory */
root?: string;
/** Arguments passed directly to generator */
args?: Array<string>;
}Usage Examples:
import { run } from "@turbo/gen/dist/commands";
// Run with interactive generator selection
await run(undefined, {
config: "./turbo/generators/config.js"
});
// Run specific generator
await run("my-component", {
config: "./turbo/generators/config.js",
args: ["name=Button", "type=component"]
});
// Run with custom config
await run("api-route", {
config: "./custom-generators/config.ts",
root: "/path/to/project"
});Low-level function for custom generator execution.
/**
* Execute custom generator with detailed arguments
* @param args - Custom generator arguments
* @returns Promise that resolves when generation is complete
*/
function generate(args: CustomGeneratorArguments): Promise<void>;
interface CustomGeneratorArguments {
generator: string | undefined;
project: Project;
opts: CustomGeneratorCLIOptions;
}Usage Examples:
import { generate as customGenerate } from "@turbo/gen/dist/generators/custom";
import { getProject } from "@turbo/gen/dist/utils/getProject";
const project = await getProject({ root: process.cwd() });
await customGenerate({
generator: "component",
project,
opts: {
config: "./turbo/generators/config.js",
args: ["name=MyComponent", "directory=components"]
}
});Get access to the underlying node-plop API for advanced generator operations.
/**
* Get NodePlopAPI instance for direct plop operations
* @param args - Plop configuration
* @returns NodePlopAPI instance or undefined if config not found
*/
function getPlop(args: {
project: Project;
configPath?: string;
}): NodePlopAPI | undefined;Find and list available custom generators.
/**
* Get list of all available custom generators
* @param args - Generator discovery configuration
* @returns Array of generators or separators for UI display
*/
function getCustomGenerators(args: {
project: Project;
configPath?: string;
}): Array<Generator | Separator>;
/**
* Get specific generator by name
* @param args - Generator lookup configuration
* @returns Generator name or undefined if not found
*/
function getCustomGenerator(args: {
project: Project;
generator: string;
configPath?: string;
}): string | undefined;
type Generator = PlopGenerator & {
basePath: string;
name: string;
};Direct generator execution utilities.
/**
* Run a custom generator with bypass arguments
* @param args - Generator execution configuration
* @returns Promise that resolves when generator completes
*/
function runCustomGenerator(args: {
project: Project;
generator: string;
bypassArgs?: Array<string>;
configPath?: string;
}): Promise<void>;Usage Examples:
import {
getPlop,
getCustomGenerators,
getCustomGenerator,
runCustomGenerator
} from "@turbo/gen/dist/utils/plop";
// Get plop instance
const plop = getPlop({
project,
configPath: "./turbo/generators/config.js"
});
// Get all generators
const generators = getCustomGenerators({
project,
configPath: "./turbo/generators/config.js"
});
// Find specific generator
const generator = getCustomGenerator({
project,
generator: "component",
configPath: "./turbo/generators/config.js"
});
// Run generator with arguments
await runCustomGenerator({
project,
generator: "component",
bypassArgs: ["Button", "components/ui"],
configPath: "./turbo/generators/config.js"
});Set up generator templates for new projects.
/**
* Set up generator configuration from built-in templates
* @param args - Template setup configuration
* @returns Promise that resolves when template is set up
*/
function setupFromTemplate(args: {
project: Project;
template: "ts" | "js";
}): Promise<void>;Usage Examples:
import { setupFromTemplate } from "@turbo/gen/dist/utils/setupFromTemplate";
// Set up TypeScript generator template
await setupFromTemplate({
project,
template: "ts"
});
// Set up JavaScript generator template
await setupFromTemplate({
project,
template: "js"
});Programmatic access to generator selection and setup prompts.
/**
* Prompt for generator selection from available generators
* @param args - Generator selection configuration
* @returns Promise with selected generator name
*/
function customGenerators(args: {
generators: Array<Generator | Separator>;
generator?: string;
}): Promise<{ selectedGenerator: string }>;/**
* Prompt for generator template language choice
* @returns Promise with selected template type
*/
function chooseGeneratorTemplate(): Promise<{ answer: "ts" | "js" }>;/**
* Display confirmation prompt to user
* @param args - Confirmation prompt configuration
* @returns Promise with user's boolean response
*/
function confirm(args: { message: string }): Promise<{ answer: boolean }>;Usage Examples:
import {
customGenerators,
chooseGeneratorTemplate,
confirm
} from "@turbo/gen/dist/commands/run/prompts";
// Select generator
const generators = getCustomGenerators({ project });
const selection = await customGenerators({
generators,
generator: undefined
});
// Choose template type
const template = await chooseGeneratorTemplate();
// Confirm action
const confirmation = await confirm({
message: "Are you sure you want to create this generator?"
});Custom generators are configured using node-plop configuration files:
TypeScript Configuration (turbo/generators/config.ts):
import type { PlopTypes } from "@turbo/gen";
const config: PlopTypes.PlopConfig = {
generator: {
description: "Create a new component",
prompts: [
{
type: "input",
name: "name",
message: "Component name:",
validate: (input: string) => input.length > 0
}
],
actions: [
{
type: "add",
path: "{{ turbo.paths.root }}/packages/ui/src/{{ dashCase name }}.tsx",
templateFile: "templates/component.hbs"
}
]
}
};
export default config;JavaScript Configuration (turbo/generators/config.js):
module.exports = {
generator: {
description: "Create a new component",
prompts: [
{
type: "input",
name: "name",
message: "Component name:"
}
],
actions: [
{
type: "add",
path: "{{ turbo.paths.root }}/packages/ui/src/{{ dashCase name }}.tsx",
templateFile: "templates/component.hbs"
}
]
}
};Turbo Gen includes built-in templates for generator setup:
TypeScript template: dist/templates/simple-ts/
config.ts - TypeScript generator configurationtemplates/turborepo-generators.hbs - Handlebars templatepackage.json - Package metadataJavaScript template: dist/templates/simple-js/
config.js - JavaScript generator configurationtemplates/turborepo-generators.hbs - Handlebars templatepackage.json - Package metadataCustom generators have access to Turbo-specific template variables:
{{ turbo.paths.root }} - Repository root path
{{ turbo.paths.workspace }} - Current workspace path
{{ turbo.generator.name }} - Generator nameUsage in Templates:
// Component template (component.hbs)
import React from 'react';
interface {{ pascalCase name }}Props {
children?: React.ReactNode;
}
export const {{ pascalCase name }}: React.FC<{{ pascalCase name }}Props> = ({ children }) => {
return <div className="{{ dashCase name }}">{children}</div>;
};
export default {{ pascalCase name }};Custom generator operations can throw specific error types:
type GenerateErrorType =
| "plop_error_running_generator"
| "plop_unable_to_load_config"
| "plop_generator_not_found"
| "plop_no_config"
| "config_directory_already_exists"
| "unknown";
class GeneratorError extends Error {
public type: GenerateErrorType;
constructor(message: string, opts?: GeneratorErrorOptions);
}
interface GeneratorErrorOptions {
type?: GenerateErrorType;
}Common error scenarios:
Install with Tessl CLI
npx tessl i tessl/npm-turbo--gen