@chriswa/ts-codegen
v1.4.1
Published
A simple, dynamic TypeScript code generator with development watch support
Downloads
28
Maintainers
Readme
@chriswa/ts-codegen
A simple, dynamic TypeScript code generator with development "watch" support.
What it does
Scans the provided directory (and subdirs) for Handlebars templates and generates TypeScript code. Supports two template formats:
- Standalone templates (
.hbsfiles) -example.hbsgeneratesexample.ts - Embedded templates (
.hbs.tsfiles) - Template and generated code in the same file
Uses handlebars-helpers library for template functionality. Primarily used for listing files in a directory and importing them, often with registration in factories or registries.
Installation
pnpm add @chriswa/ts-codegenExample
Import and register classes in a directory with a factory. In watch mode, the output file is updated when class files are created, renamed, and deleted.
Template: src/things/_index.ts.hbs
// Generated code - see *.hbs file
import { myFactory } from '../factories'
// Auto-import all TypeScript files in this directory (excluding templates and outputs)
{{#each (match (readdirRecursive ".") "*.ts")}}
{{#unless (contains (array "_index.ts" "_index.ts" "Base.ts") this)}}
import { {{replace (basename this) ".ts" ""}} } from './{{replace this ".ts" ""}}'
{{/unless}}
{{/each}}
// Register all classes with the factory
{{#each (match (readdirRecursive ".") "*.ts")}}
{{#unless (contains (array "_index.ts" "_index.ts" "Base.ts") this)}}
myFactory.registerClass({{replace (basename this) ".ts" ""}})
{{/unless}}
{{/each}}Generated: src/things/_index.ts
// Generated code - see *.hbs file
import { myFactory } from '../factories'
// Auto-import all TypeScript files in this directory (excluding templates and outputs)
import { FooThing } from './FooThing'
import { BarThing } from './BarThing'
import { BaazThing } from './BaazThing'
// Register all classes with the factory
myFactory.registerClass(FooThing)
myFactory.registerClass(BarThing)
myFactory.registerClass(BaazThing)Embedded Templates
Embedded templates (.hbs.ts files) are an alternative to standalone templates where the template and generated code exist in the same file. The template (as comments) comes first, followed by the generated code.
Before Processing: src/config.hbs.ts
// export const message = 'Hello from World!'
// export const template = '{{taskPathBasename}}'
// ===================== GENERATED CODE BELOW =====================
// Generated by @chriswa/ts-codegen (embedded template)
// Do not edit manually - changes will be overwritten
// ================================================================
// This section will be replaced by the code generatorAfter Processing: src/config.hbs.ts
// export const message = 'Hello from World!'
// export const template = '{{taskPathBasename}}'
// ===================== GENERATED CODE BELOW =====================
// Generated by @chriswa/ts-codegen (embedded template)
// Do not edit manually - changes will be overwritten
// ================================================================
export const message = 'Hello from World!'
export const template = 'config.hbs.ts'Format:
- Template is written as TypeScript comments (lines starting with
//) - Generated code replaces content after the generated code banner
- File is processed in-place, preserving the template for future regeneration
Template Helpers
This package includes all handlebars-helpers plus custom helpers:
readdirRecursive
Recursively reads directory contents and returns file paths relative to the template location.
{{#each (readdirRecursive ".")}}
// Found: {{this}}
{{/each}}Combined with handlebars-helpers
Combine helpers for file processing:
{{#each (match (readdirRecursive ".") "*.ts")}}
{{#unless (contains (array "excluded.ts" "another.ts") this)}}
// Process: {{this}}
{{/unless}}
{{/each}}Common helpers include:
match- Filter arrays with glob patternscontains- Check if array contains valueunless- Conditional exclusionarray- Create arraysbasename- Get filename from pathreplace- String replacement
include
Include and process other template files with parameter passing. Supports relative paths and TypeScript path mapping.
{{include "./shared/entity-template.hbs" entityType="User" items=(array "UserService" "UserModel")}}Path Resolution:
- Relative paths:
./shared/template.hbs,../common/template.hbs - TypeScript paths:
@/shared/template.hbs(requires tsconfig.json with path mapping)
Template Composition Example:
Shared Template (shared/entity-template.hbs):
// Auto-generated {{entityType}} entities
{{#each items}}
import { {{this}} } from './{{this}}'
{{/each}}
export const {{camelcase entityType}}Classes = [
{{#each items}}
{{this}},
{{/each}}
]Consumer Templates:
{{include "./shared/entity-template.hbs" entityType="User" items=(array "UserService" "UserModel")}}{{include "@/shared/entity-template.hbs" entityType="Product" items=(array "ProductService" "ProductModel")}}Examples
For comprehensive examples of how to use ts-codegen, see the examples/ directory. Each example contains:
input/- Template files and supporting codeexpected/- Expected generated outputmeta/- Configuration for handling non-deterministic content (when applicable)
Available Examples:
Basic/- Simple template variable substitutionHandlebarsHelpers/- Using helpers for file processingEmbeddedTemplateErrors/- Error handling in embedded templatesIncludeErrors/- Include template error scenariosOrphanedFiles/- Automatic cleanup of deleted templatesPathMapping/- TypeScript path mapping with includesReaddirFromTemplateDir/- Directory-relative helpersSubdirectories/- Recursive template processingTemplateInclusion/- Template composition with includes
Run the examples with: pnpm test (runs all examples as tests)
Usage
CLI Usage
# Build once
npx ts-codegen build src
# Watch for changes
npx ts-codegen watch src
# Clean generated files
npx ts-codegen clean srcProgrammatic Usage
import { build, watch, clean } from '@chriswa/ts-codegen'
// Build templates
await build('src')
// Watch for changes
watch('src')
// Clean generated files
clean('src')Vite Plugin
// vite.config.ts
import { defineConfig } from 'vite'
import { tsCodegenVitePlugin } from '@chriswa/ts-codegen'
export default defineConfig({
plugins: [
tsCodegenVitePlugin('src'),
],
})TypeScript-First
This package distributes TypeScript source files and uses tsx to run TypeScript directly. This provides IDE support, type safety, and eliminates compilation steps for consumers.
License
MIT
