Claude Code Plugins

Community-maintained marketplace

Feedback

code-generation-template

@aj-geddes/useful-ai-prompts
4
0

Generate code from templates and patterns including scaffolding, boilerplate generation, AST-based code generation, and template engines. Use when generating code, scaffolding projects, creating boilerplate, or using templates.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name code-generation-template
description Generate code from templates and patterns including scaffolding, boilerplate generation, AST-based code generation, and template engines. Use when generating code, scaffolding projects, creating boilerplate, or using templates.

Code Generation & Templates

Overview

Comprehensive guide to code generation techniques including template engines, AST manipulation, code scaffolding, and automated boilerplate generation for increased productivity and consistency.

When to Use

  • Scaffolding new projects or components
  • Generating repetitive boilerplate code
  • Creating CRUD operations automatically
  • Generating API clients from OpenAPI specs
  • Building code from templates
  • Creating database models from schemas
  • Generating TypeScript types from JSON Schema
  • Building custom CLI generators

Instructions

1. Template Engines

Handlebars Templates

// templates/component.hbs
import React from 'react';

export interface {{pascalCase name}}Props {
  {{#each props}}
  {{this.name}}{{#if this.optional}}?{{/if}}: {{this.type}};
  {{/each}}
}

export const {{pascalCase name}}: React.FC<{{pascalCase name}}Props> = ({
  {{#each props}}{{this.name}},{{/each}}
}) => {
  return (
    <div className="{{kebabCase name}}">
      {/* Component implementation */}
    </div>
  );
};
// generator.ts
import Handlebars from 'handlebars';
import fs from 'fs';

// Register helpers
Handlebars.registerHelper('pascalCase', (str: string) =>
  str.replace(/(\w)(\w*)/g, (_, first, rest) =>
    first.toUpperCase() + rest.toLowerCase()
  )
);

Handlebars.registerHelper('kebabCase', (str: string) =>
  str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
);

// Load template
const templateSource = fs.readFileSync('templates/component.hbs', 'utf8');
const template = Handlebars.compile(templateSource);

// Generate code
const code = template({
  name: 'userProfile',
  props: [
    { name: 'userId', type: 'string', optional: false },
    { name: 'onUpdate', type: '() => void', optional: true }
  ]
});

fs.writeFileSync('src/components/UserProfile.tsx', code);

EJS Templates

// templates/api-endpoint.ejs
import { Router } from 'express';
import { <%= modelName %>Service } from '../services/<%= kebabCase(modelName) %>.service';

const router = Router();
const service = new <%= modelName %>Service();

// GET /<%= pluralize(kebabCase(modelName)) %>
router.get('/', async (req, res) => {
  try {
    const items = await service.findAll();
    res.json(items);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// GET /<%= pluralize(kebabCase(modelName)) %>/:id
router.get('/:id', async (req, res) => {
  try {
    const item = await service.findById(req.params.id);
    if (!item) {
      return res.status(404).json({ error: 'Not found' });
    }
    res.json(item);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// POST /<%= pluralize(kebabCase(modelName)) %>
router.post('/', async (req, res) => {
  try {
    const item = await service.create(req.body);
    res.status(201).json(item);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

export default router;
// Using EJS
import ejs from 'ejs';

const code = await ejs.renderFile('templates/api-endpoint.ejs', {
  modelName: 'User',
  kebabCase: (str: string) => str.replace(/([A-Z])/g, '-$1').toLowerCase().slice(1),
  pluralize: (str: string) => str + 's'
});

2. AST-Based Code Generation

Using Babel/TypeScript AST

// ast-generator.ts
import * as ts from 'typescript';

export class TypeScriptGenerator {
  // Generate interface
  generateInterface(name: string, properties: Array<{ name: string; type: string; optional?: boolean }>) {
    const members = properties.map(prop =>
      ts.factory.createPropertySignature(
        undefined,
        ts.factory.createIdentifier(prop.name),
        prop.optional ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined,
        ts.factory.createTypeReferenceNode(prop.type)
      )
    );

    const interfaceDecl = ts.factory.createInterfaceDeclaration(
      [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
      ts.factory.createIdentifier(name),
      undefined,
      undefined,
      members
    );

    return this.printNode(interfaceDecl);
  }

  // Generate class
  generateClass(name: string, properties: Array<{ name: string; type: string }>) {
    const propertyDecls = properties.map(prop =>
      ts.factory.createPropertyDeclaration(
        [ts.factory.createToken(ts.SyntaxKind.PrivateKeyword)],
        ts.factory.createIdentifier(prop.name),
        undefined,
        ts.factory.createTypeReferenceNode(prop.type),
        undefined
      )
    );

    const constructor = ts.factory.createConstructorDeclaration(
      undefined,
      properties.map(prop =>
        ts.factory.createParameterDeclaration(
          undefined,
          undefined,
          ts.factory.createIdentifier(prop.name),
          undefined,
          ts.factory.createTypeReferenceNode(prop.type)
        )
      ),
      ts.factory.createBlock(
        properties.map(prop =>
          ts.factory.createExpressionStatement(
            ts.factory.createBinaryExpression(
              ts.factory.createPropertyAccessExpression(
                ts.factory.createThis(),
                prop.name
              ),
              ts.SyntaxKind.EqualsToken,
              ts.factory.createIdentifier(prop.name)
            )
          )
        ),
        true
      )
    );

    const classDecl = ts.factory.createClassDeclaration(
      [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
      ts.factory.createIdentifier(name),
      undefined,
      undefined,
      [...propertyDecls, constructor]
    );

    return this.printNode(classDecl);
  }

  private printNode(node: ts.Node): string {
    const sourceFile = ts.createSourceFile(
      'temp.ts',
      '',
      ts.ScriptTarget.Latest,
      false,
      ts.ScriptKind.TS
    );

    const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
    return printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
  }
}

// Usage
const generator = new TypeScriptGenerator();

const interfaceCode = generator.generateInterface('User', [
  { name: 'id', type: 'string' },
  { name: 'email', type: 'string' },
  { name: 'name', type: 'string', optional: true }
]);

const classCode = generator.generateClass('UserService', [
  { name: 'repository', type: 'UserRepository' },
  { name: 'logger', type: 'Logger' }
]);

3. Project Scaffolding

Simple CLI Generator

// cli/generate.ts
#!/usr/bin/env node
import { Command } from 'commander';
import inquirer from 'inquirer';
import fs from 'fs-extra';
import path from 'path';

const program = new Command();

program
  .name('generate')
  .description('Code generator CLI')
  .version('1.0.0');

program
  .command('component <name>')
  .description('Generate a React component')
  .option('-d, --dir <directory>', 'Output directory', 'src/components')
  .action(async (name, options) => {
    const answers = await inquirer.prompt([
      {
        type: 'list',
        name: 'type',
        message: 'Component type?',
        choices: ['functional', 'class']
      },
      {
        type: 'confirm',
        name: 'typescript',
        message: 'Use TypeScript?',
        default: true
      },
      {
        type: 'confirm',
        name: 'test',
        message: 'Generate test file?',
        default: true
      }
    ]);

    await generateComponent(name, options.dir, answers);
  });

program
  .command('api <resource>')
  .description('Generate API endpoint with controller, service, and model')
  .action(async (resource) => {
    await generateApiResource(resource);
  });

program.parse();

async function generateComponent(name: string, dir: string, options: any) {
  const componentName = pascalCase(name);
  const ext = options.typescript ? 'tsx' : 'jsx';

  const template = options.type === 'functional'
    ? getFunctionalComponentTemplate(componentName, options.typescript)
    : getClassComponentTemplate(componentName, options.typescript);

  const componentPath = path.join(dir, `${componentName}.${ext}`);

  await fs.ensureDir(dir);
  await fs.writeFile(componentPath, template);

  console.log(`✓ Created ${componentPath}`);

  if (options.test) {
    const testTemplate = getTestTemplate(componentName, options.typescript);
    const testPath = path.join(dir, `${componentName}.test.${ext}`);
    await fs.writeFile(testPath, testTemplate);
    console.log(`✓ Created ${testPath}`);
  }
}

function getFunctionalComponentTemplate(name: string, ts: boolean): string {
  if (ts) {
    return `import React from 'react';

export interface ${name}Props {
  // Add props here
}

export const ${name}: React.FC<${name}Props> = (props) => {
  return (
    <div className="${kebabCase(name)}">
      <h1>${name}</h1>
    </div>
  );
};
`;
  }

  return `import React from 'react';

export const ${name} = (props) => {
  return (
    <div className="${kebabCase(name)}">
      <h1>${name}</h1>
    </div>
  );
};
`;
}

async function generateApiResource(resource: string) {
  const name = pascalCase(resource);

  // Generate model
  const modelCode = `export interface ${name} {
  id: string;
  createdAt: Date;
  updatedAt: Date;
  // Add fields here
}
`;
  await fs.writeFile(`src/models/${kebabCase(resource)}.model.ts`, modelCode);

  // Generate service
  const serviceCode = `import { ${name} } from '../models/${kebabCase(resource)}.model';

export class ${name}Service {
  async findAll(): Promise<${name}[]> {
    // Implement
    return [];
  }

  async findById(id: string): Promise<${name} | null> {
    // Implement
    return null;
  }

  async create(data: Partial<${name}>): Promise<${name}> {
    // Implement
    throw new Error('Not implemented');
  }

  async update(id: string, data: Partial<${name}>): Promise<${name}> {
    // Implement
    throw new Error('Not implemented');
  }

  async delete(id: string): Promise<void> {
    // Implement
  }
}
`;
  await fs.writeFile(`src/services/${kebabCase(resource)}.service.ts`, serviceCode);

  // Generate controller
  const controllerCode = `import { Router } from 'express';
import { ${name}Service } from '../services/${kebabCase(resource)}.service';

const router = Router();
const service = new ${name}Service();

router.get('/', async (req, res) => {
  const items = await service.findAll();
  res.json(items);
});

router.get('/:id', async (req, res) => {
  const item = await service.findById(req.params.id);
  if (!item) return res.status(404).json({ error: 'Not found' });
  res.json(item);
});

router.post('/', async (req, res) => {
  const item = await service.create(req.body);
  res.status(201).json(item);
});

router.put('/:id', async (req, res) => {
  const item = await service.update(req.params.id, req.body);
  res.json(item);
});

router.delete('/:id', async (req, res) => {
  await service.delete(req.params.id);
  res.status(204).send();
});

export default router;
`;
  await fs.writeFile(`src/controllers/${kebabCase(resource)}.controller.ts`, controllerCode);

  console.log(`✓ Generated API resource: ${name}`);
}

4. OpenAPI Client Generation

// openapi-client-generator.ts
import SwaggerParser from '@apidevtools/swagger-parser';
import { compile } from 'json-schema-to-typescript';

export class OpenAPIClientGenerator {
  async generate(specPath: string, outputDir: string) {
    const api = await SwaggerParser.parse(specPath);

    // Generate TypeScript types from schemas
    if (api.components?.schemas) {
      for (const [name, schema] of Object.entries(api.components.schemas)) {
        const ts = await compile(schema as any, name, {
          bannerComment: ''
        });
        await fs.writeFile(
          path.join(outputDir, 'types', `${name}.ts`),
          ts
        );
      }
    }

    // Generate API client methods
    for (const [path, pathItem] of Object.entries(api.paths)) {
      for (const [method, operation] of Object.entries(pathItem)) {
        if (['get', 'post', 'put', 'delete', 'patch'].includes(method)) {
          const clientMethod = this.generateClientMethod(
            method,
            path,
            operation as any
          );
          // Write to file...
        }
      }
    }
  }

  private generateClientMethod(
    method: string,
    path: string,
    operation: any
  ): string {
    const functionName = operation.operationId || this.pathToFunctionName(method, path);
    const parameters = operation.parameters || [];

    return `
async ${functionName}(${this.generateParameters(parameters)}): Promise<${this.getResponseType(operation)}> {
  const response = await this.request('${method.toUpperCase()}', '${path}', {
    ${this.generateRequestOptions(parameters)}
  });
  return response.json();
}
`;
  }

  private generateParameters(parameters: any[]): string {
    return parameters
      .map(p => `${p.name}${p.required ? '' : '?'}: ${this.schemaToType(p.schema)}`)
      .join(', ');
  }

  private getResponseType(operation: any): string {
    const successResponse = operation.responses['200'] || operation.responses['201'];
    if (!successResponse) return 'any';

    const schema = successResponse.content?.['application/json']?.schema;
    return schema ? this.schemaToType(schema) : 'any';
  }

  private schemaToType(schema: any): string {
    if (schema.$ref) {
      return schema.$ref.split('/').pop();
    }
    if (schema.type === 'string') return 'string';
    if (schema.type === 'number' || schema.type === 'integer') return 'number';
    if (schema.type === 'boolean') return 'boolean';
    if (schema.type === 'array') return `${this.schemaToType(schema.items)}[]`;
    return 'any';
  }

  private pathToFunctionName(method: string, path: string): string {
    const cleanPath = path.replace(/\{.*?\}/g, 'By').replace(/[^a-zA-Z0-9]/g, '');
    return `${method}${cleanPath}`;
  }
}

5. Database Model Generation

// prisma-schema-generator.ts
export class PrismaSchemaGenerator {
  generateModel(table: DatabaseTable): string {
    return `model ${pascalCase(table.name)} {
${table.columns.map(col => this.generateField(col)).join('\n')}

${this.generateRelations(table.relations)}
${this.generateIndexes(table.indexes)}
}
`;
  }

  private generateField(column: Column): string {
    const optional = !column.required ? '?' : '';
    const unique = column.unique ? ' @unique' : '';
    const defaultValue = column.default ? ` @default(${column.default})` : '';

    return `  ${column.name} ${this.mapType(column.type)}${optional}${unique}${defaultValue}`;
  }

  private mapType(sqlType: string): string {
    const typeMap: Record<string, string> = {
      'varchar': 'String',
      'text': 'String',
      'integer': 'Int',
      'bigint': 'BigInt',
      'boolean': 'Boolean',
      'timestamp': 'DateTime',
      'date': 'DateTime',
      'json': 'Json'
    };
    return typeMap[sqlType.toLowerCase()] || 'String';
  }

  private generateRelations(relations: Relation[]): string {
    return relations.map(rel => {
      if (rel.type === 'hasMany') {
        return `  ${rel.name} ${rel.model}[]`;
      } else if (rel.type === 'belongsTo') {
        return `  ${rel.name} ${rel.model} @relation(fields: [${rel.foreignKey}], references: [id])`;
      }
      return '';
    }).join('\n');
  }
}

6. GraphQL Code Generation

// graphql-codegen.config.ts
import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'http://localhost:4000/graphql',
  documents: ['src/**/*.tsx', 'src/**/*.ts'],
  generates: {
    './src/generated/graphql.ts': {
      plugins: [
        'typescript',
        'typescript-operations',
        'typescript-react-apollo'
      ],
      config: {
        withHooks: true,
        withComponent: false,
        withHOC: false
      }
    },
    './src/generated/introspection.json': {
      plugins: ['introspection']
    }
  }
};

export default config;

7. Plop.js Generator

// plopfile.ts
import { NodePlopAPI } from 'plop';

export default function (plop: NodePlopAPI) {
  // Component generator
  plop.setGenerator('component', {
    description: 'React component',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'Component name:'
      },
      {
        type: 'list',
        name: 'type',
        message: 'Component type:',
        choices: ['functional', 'class']
      }
    ],
    actions: [
      {
        type: 'add',
        path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.tsx',
        templateFile: 'templates/component.hbs'
      },
      {
        type: 'add',
        path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.test.tsx',
        templateFile: 'templates/component.test.hbs'
      },
      {
        type: 'add',
        path: 'src/components/{{pascalCase name}}/index.ts',
        template: "export { {{pascalCase name}} } from './{{pascalCase name}}';\n"
      }
    ]
  });

  // API generator
  plop.setGenerator('api', {
    description: 'API endpoint with full stack',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'Resource name (e.g., user, post):'
      }
    ],
    actions: [
      {
        type: 'add',
        path: 'src/models/{{kebabCase name}}.model.ts',
        templateFile: 'templates/model.hbs'
      },
      {
        type: 'add',
        path: 'src/services/{{kebabCase name}}.service.ts',
        templateFile: 'templates/service.hbs'
      },
      {
        type: 'add',
        path: 'src/controllers/{{kebabCase name}}.controller.ts',
        templateFile: 'templates/controller.hbs'
      },
      {
        type: 'add',
        path: 'src/routes/{{kebabCase name}}.routes.ts',
        templateFile: 'templates/routes.hbs'
      }
    ]
  });
}

Best Practices

✅ DO

  • Use templates for repetitive code patterns
  • Generate TypeScript types from schemas
  • Include tests in generated code
  • Follow project conventions in templates
  • Add comments to explain generated code
  • Version control your templates
  • Make templates configurable
  • Generate documentation alongside code
  • Validate inputs before generating
  • Use consistent naming conventions
  • Keep templates simple and maintainable
  • Provide CLI for easy generation

❌ DON'T

  • Over-generate (avoid unnecessary complexity)
  • Generate code that's hard to maintain
  • Forget to validate generated code
  • Hardcode values in templates
  • Generate code without documentation
  • Create generators for one-off use cases
  • Mix business logic in templates
  • Generate code without formatting
  • Skip error handling in generators
  • Create overly complex templates

Common Patterns

Pattern 1: CRUD Generator

export function generateCRUD(entityName: string) {
  return {
    model: generateModel(entityName),
    service: generateService(entityName),
    controller: generateController(entityName),
    routes: generateRoutes(entityName),
    tests: generateTests(entityName)
  };
}

Pattern 2: Migration Generator

export function generateMigration(name: string, changes: SchemaChange[]) {
  return {
    up: generateUpMigration(changes),
    down: generateDownMigration(changes)
  };
}

Pattern 3: Factory Generator

export function generateFactory(model: Model) {
  return `export const create${model.name} = (overrides?: Partial<${model.name}>): ${model.name} => ({
  ${model.fields.map(f => `${f.name}: ${getDefaultValue(f)}`).join(',\n  ')},
  ...overrides
});`;
}

Tools & Resources

  • Plop: Micro-generator framework
  • Yeoman: Scaffolding tool
  • Hygen: Code generator with templates
  • GraphQL Code Generator: Generate code from GraphQL
  • Prisma: Database ORM with code generation
  • OpenAPI Generator: Generate clients from OpenAPI
  • json-schema-to-typescript: Generate TS types
  • TypeScript Compiler API: AST manipulation