Programmatic Usage
Use @heco-gen/features directly from your Node.js code. This unlocks automation, custom workflows, and integration with your own tools.
When to use the programmatic API
The CLI is great for manual generation. But the programmatic API shines when you need:
- Batch generation — create multiple features at once
- Custom logic — conditionally generate files based on project state
- Tool integration — build your own CLI, VS Code extension, or scaffolding tool
- CI/CD pipelines — generate features as part of your build process
Installation
bash
npm install @heco-gen/featuresImporting
ts
import {
generateFeature,
loadConfig,
validateConfig,
registerGenerator,
registerTemplateEngine,
writeFile,
} from "@heco-gen/features"Step-by-step: Generate a feature programmatically
1. Load configuration
ts
import { loadConfig } from "@heco-gen/features"
// Load from default location (hfg.config.json in cwd)
const config = await loadConfig()
// Load from a custom path
const config = await loadConfig("./tools/my-config.json")
// Or construct config directly
const config = {
folderNames: {
components: "ui",
hooks: "hooks",
},
basePath: "src/app/features",
}2. Validate configuration
Always validate before generating:
ts
import { validateConfig } from "@heco-gen/features"
const result = validateConfig(config)
if (!result.success) {
console.error("Config validation failed:", result.error)
process.exit(1)
}The validator checks:
- All required fields are present
- Folder names are valid strings
- Generator definitions have the correct structure
- Base path is a valid path string
3. Generate a feature
ts
import { generateFeature } from "@heco-gen/features"
// Simple generation
await generateFeature("user-profile", config)
// With custom options
await generateFeature("blog-post", config, {
overwrite: true, // Overwrite existing files
dryRun: false, // Actually write files
logOutput: true, // Log created files
})4. Register a custom generator
ts
import { registerGenerator } from "@heco-gen/features"
registerGenerator("api-endpoint", {
files: [
{
template: "api/route.ts.hbs",
outputPath: "api/{{camelName}}.ts",
},
{
template: "api/types.ts.hbs",
outputPath: "api/{{camelName}}Types.ts",
},
],
})
// Now use it
await generateFeature("create-user", config, {
generator: "api-endpoint",
})Example: Batch generation
Create multiple features in one script:
ts
import { generateFeature, loadConfig } from "@heco-gen/features"
const config = await loadConfig()
const features = ["user-profile", "blog-post", "auth", "dashboard"]
for (const name of features) {
console.log(`Generating ${name}...`)
await generateFeature(name, config)
console.log(` ✓ ${name} created`)
}Example: Feature generator script
Create a reusable script that accepts a name and generates with progress:
ts
#!/usr/bin/env node
import { generateFeature, loadConfig, validateConfig } from "@heco-gen/features"
async function main() {
const name = process.argv[2]
if (!name) {
console.error("Usage: node generate.mjs <feature-name>")
process.exit(1)
}
console.log(`\n Generating feature: ${name}\n`)
const config = await loadConfig()
const validation = validateConfig(config)
if (!validation.success) {
console.error(" ✗ Invalid config:", validation.error)
process.exit(1)
}
console.log(" ✓ Config loaded and validated")
console.log(` ✓ Base path: ${config.basePath}`)
await generateFeature(name, config, { logOutput: true })
console.log(`\n ✓ Feature "${name}" generated successfully\n`)
}
main().catch(console.error)Example: Conditional generation
Generate different files based on the feature type:
ts
import { generateFeature, registerGenerator, loadConfig } from "@heco-gen/features"
const config = await loadConfig()
// Register generators for different feature types
registerGenerator("page", {
files: [
{ template: "page/page.tsx.hbs", outputPath: "page.tsx" },
{ template: "page/layout.tsx.hbs", outputPath: "layout.tsx" },
],
})
registerGenerator("api", {
files: [
{ template: "api/route.ts.hbs", outputPath: "route.ts" },
{ template: "api/schema.ts.hbs", outputPath: "schema.ts" },
],
})
// Choose generator based on feature type
const type = process.argv[3] || "feature"
await generateFeature(process.argv[2], config, {
generator: type,
logOutput: true,
})Usage:
bash
node generate.mjs dashboard page
node generate.mjs create-user apiCustom template engines
By default, the generator uses Handlebars for templates. You can register a custom engine:
ts
import { registerTemplateEngine } from "@heco-gen/features"
import ejs from "ejs"
registerTemplateEngine("ejs", async (template, context) => {
return ejs.render(template, context)
})The engine receives:
template— the raw template string contentcontext— an object with all naming variables (PascalName,camelName, etc.)
It must return the rendered string.
TypeScript types
The package includes full TypeScript declarations:
ts
import type {
HfgConfig,
GeneratorDefinition,
FileDefinition,
FileWriterHooks,
} from "@heco-gen/features"
// Typed config construction
const config: HfgConfig = {
folderNames: {
components: "ui",
},
basePath: "src/features",
}Error handling
All functions throw descriptive errors for common problems:
ts
try {
await generateFeature("user-profile", config)
} catch (error) {
if (error.message.includes("already exists")) {
console.log("Feature already exists, use --overwrite to replace")
} else if (error.message.includes("Template not found")) {
console.log("Missing template file, check your templates directory")
} else {
console.error("Generation failed:", error)
}
}Next steps
- Templates — create dynamic templates with Handlebars
- Custom Config — explore all configuration options