Micro-generator framework that makes it easy for an entire team to create files with a level of uniformity
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Plop uses Handlebars templating with built-in helpers, custom helpers, and partials for flexible file generation. The template system supports both inline templates and external template files.
Register and use custom Handlebars helpers for template processing.
/**
* Register a custom Handlebars helper
* @param name - Helper name for use in templates
* @param fn - Helper function
*/
setHelper(name: string, fn: HelperFunction): void;
/**
* Get a registered helper function by name
* @param name - Helper name
* @returns Helper function
*/
getHelper(name: string): Function;
/**
* Get list of all registered helper names
* @returns Array of helper names
*/
getHelperList(): string[];
/**
* @deprecated Use setHelper instead
*/
addHelper(name: string, fn: Function): void;Usage Examples:
import { nodePlop } from "plop";
const plop = await nodePlop();
// Register a custom helper
plop.setHelper('upperCase', (text) => text.toUpperCase());
// Register a helper with options
plop.setHelper('repeat', (text, count) => {
return new Array(count + 1).join(text);
});
// Use in templates
const template = '{{upperCase name}} - {{repeat "!" 3}}';
const result = plop.renderString(template, { name: 'hello' });
console.log(result); // "HELLO - !!!"
// List all helpers
const helpers = plop.getHelperList();
console.log(helpers);Plop includes numerous built-in case conversion and utility helpers.
// Case conversion helpers (all available by default)
const BUILT_IN_HELPERS = {
// Basic case transformations
camelCase: Function; // myVariableName
pascalCase: Function; // MyVariableName
properCase: Function; // Alias for pascalCase
snakeCase: Function; // my_variable_name
kebabCase: Function; // my-variable-name
dashCase: Function; // Alias for kebabCase
kabobCase: Function; // Alias for kebabCase
constantCase: Function; // MY_VARIABLE_NAME
dotCase: Function; // my.variable.name
pathCase: Function; // my/variable/name
sentenceCase: Function; // My variable name
titleCase: Function; // My Variable Name
lowerCase: Function; // my variable name
upperCase: Function; // MY VARIABLE NAME
// Package helper
pkg: Function; // Access package.json properties
};Usage Examples:
// Template using built-in helpers
const template = `
class {{pascalCase name}} {
constructor() {
this.{{camelCase name}} = '{{kebabCase name}}';
this.version = '{{pkg "version"}}';
}
}
`;
const result = plop.renderString(template, { name: 'my-component' });Register and use Handlebars partials for reusable template components.
/**
* Register a Handlebars partial
* @param name - Partial name for use in templates
* @param str - Partial template string
*/
setPartial(name: string, str: string): void;
/**
* Get a registered partial by name
* @param name - Partial name
* @returns Partial template string
*/
getPartial(name: string): string;
/**
* Get list of all registered partial names
* @returns Array of partial names
*/
getPartialList(): string[];
/**
* @deprecated Use setPartial instead
*/
addPartial(name: string, str: string): void;Usage Examples:
const plop = await nodePlop();
// Register partials
plop.setPartial('header', '// Generated by Plop on {{date}}');
plop.setPartial('footer', '// End of generated file');
// Register a partial with parameters
plop.setPartial('method', `
{{#if async}}async {{/if}}{{name}}({{#each params}}{{name}}{{#unless @last}}, {{/unless}}{{/each}}) {
{{body}}
}
`);
// Use partials in templates
const template = `
{{> header}}
class {{pascalCase name}} {
{{#each methods}}
{{> method this}}
{{/each}}
}
{{> footer}}
`;
const result = plop.renderString(template, {
name: 'my-class',
date: new Date().toISOString(),
methods: [
{
name: 'getData',
async: true,
params: [{ name: 'id' }],
body: 'return await api.get(id);'
}
]
});Specify templates using inline strings or external files.
// Template source configuration
interface TemplateStrOrFile {
template?: string; // Inline template string
templateFile?: string; // Path to template file
}
// Used in action configurations
interface ActionWithTemplate extends ActionConfig, TemplateStrOrFile {
// Action-specific properties
}Usage Examples:
// Using inline template
{
type: 'add',
path: 'src/{{name}}.js',
template: 'export const {{name}} = "{{value}}";'
}
// Using template file
{
type: 'add',
path: 'src/{{name}}.js',
templateFile: 'templates/module.hbs'
}
// Template file: templates/module.hbsimport React from 'react';
export const {{pascalCase name}} = ({{#if props}}{ {{#each props}}{{name}}{{#unless @last}}, {{/unless}}{{/each}} }{{/if}}) => {
return (
<div className="{{kebabCase name}}">
{{#if children}}
{children}
{{else}}
<h1>{{titleCase name}}</h1>
{{/if}}
</div>
);
};Advanced template processing with transform functions and data manipulation.
/**
* Transform function applied after template rendering
* @param template - Rendered template string
* @param data - Template data object
* @param config - Action configuration
* @returns Transformed template string
*/
type TransformFn<T> = (template: string, data: any, config: T) => string;Usage Examples:
// Action with transform function
{
type: 'add',
path: 'src/{{name}}.js',
templateFile: 'templates/component.hbs',
transform: (template, data, config) => {
// Add custom processing
if (data.typescript) {
template = template.replace(/\.js/g, '.ts');
}
// Add prettier formatting
return prettier.format(template, { parser: 'babel' });
}
}
// Advanced data processing in template
const template = `
{{#each items}}
{{#if (eq type "component")}}
{{> component-partial this}}
{{else if (eq type "service")}}
{{> service-partial this}}
{{/if}}
{{/each}}
`;Template data includes user answers plus built-in context variables.
interface TemplateData extends UserAnswers {
// Built-in context available in all templates
[key: string]: any; // User-provided answers from prompts
}Template Context Examples:
{{!-- User answers from prompts --}}
Component: {{name}}
Type: {{type}}
Props: {{#each props}}{{name}}: {{type}}{{/each}}
{{!-- Built-in helpers --}}
File: {{kebabCase name}}.jsx
Class: {{pascalCase name}}
Constant: {{constantCase name}}_CONFIG
{{!-- Package.json access --}}
Version: {{pkg "version"}}
Author: {{pkg "author.name"}}
{{!-- Conditional rendering --}}
{{#if typescript}}
interface {{pascalCase name}}Props {
{{#each props}}
{{name}}: {{type}};
{{/each}}
}
{{/if}}
{{!-- Loops and arrays --}}
{{#each methods}}
{{#unless @first}}
{{/unless}}
{{name}}(): {{returnType}} {
// TODO: Implement {{name}}
}
{{/each}}Use Handlebars conditionals for dynamic template generation.
{{#if condition}}
Render this when condition is true
{{else if otherCondition}}
Render this when otherCondition is true
{{else}}
Default content
{{/if}}
{{#unless disabled}}
Render this when disabled is false
{{/unless}}Iterate over arrays and objects in templates.
{{#each items}}
Item {{@index}}: {{name}} ({{@first}} {{@last}})
{{/each}}
{{#each object}}
{{@key}}: {{this}}
{{/each}}Combine multiple helpers for complex transformations.
{{pascalCase (replace name "-" "")}}
{{upperCase (substring description 0 50)}}
{{#each (sort items "name")}}
{{camelCase name}}: {{value}}
{{/each}}Install with Tessl CLI
npx tessl i tessl/npm-plop