A utility library for code generation and template processing in Node.js. Provides helpers for template rendering (EJS, Handlebars, Pug), string manipulation, file operations, command execution, CLI parameter parsing, a scaffold engine, a template pipeline, and a file watcher.
Written in TypeScript with full type definitions. Supports both ESM and CommonJS.
npm install @tiveor/scg// ESM
import {
StringHelper,
FileHelper,
CommandHelper,
ParamHelper,
TemplateBuilder,
Pipeline,
Scaffold,
Watcher,
TEMPLATE_HANDLERS
} from '@tiveor/scg';
// CommonJS
const { TemplateBuilder, TEMPLATE_HANDLERS } = require('@tiveor/scg');Full API documentation is available via TypeDoc:
npm run docs # Generates HTML docs in ./docsUnified interface to render templates with EJS, Handlebars, Pug, or any custom engine.
const builder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
// Render from string
const html = await builder.render('Hello <%= name %>', { name: 'World' });
// Render from file
const page = await builder.renderFile('template.ejs', { title: 'Home' });Available handlers: TEMPLATE_HANDLERS.EJS, TEMPLATE_HANDLERS.HANDLEBARS, TEMPLATE_HANDLERS.PUG
Register custom template engines without modifying the library:
import nunjucks from 'nunjucks';
TemplateBuilder.registerEngine('nunjucks', {
render: async (source, data) => nunjucks.renderString(source, data),
renderFile: async (file, data) => nunjucks.render(file, data),
});
const builder = new TemplateBuilder('nunjucks');
const result = await builder.render('Hello {{ name }}', { name: 'World' });
// List all available engines
TemplateBuilder.getRegisteredEngines();
// => ['HANDLEBARS', 'EJS', 'PUG', 'nunjucks']Chain transformations on template output:
import { Pipeline } from '@tiveor/scg';
const result = await new Pipeline()
.fromTemplate('component.ejs', { name: 'Button' }, 'EJS')
.transform((content) => content.toUpperCase())
.transform(addLicenseHeader)
.writeTo('src/components/Button.tsx');
// Other input methods
new Pipeline().fromString('raw content');
new Pipeline().fromFile('input.txt');
new Pipeline().fromTemplateString('<%= name %>', { name: 'World' }, 'EJS');Generate directory structures from manifests:
import { Scaffold } from '@tiveor/scg';
const result = await Scaffold.from({
engine: 'EJS',
templateDir: './templates/react-component',
outputDir: './src/components/{{name}}',
variables: { name: 'UserProfile', style: 'module' },
structure: [
{ template: 'component.ejs', output: '{{name}}.tsx' },
{ template: 'styles.ejs', output: '{{name}}.module.css' },
{ template: 'test.ejs', output: '{{name}}.test.tsx' },
{ template: 'index.ejs', output: 'index.ts' },
]
});
console.log(result.files); // List of created file paths
// Preview without writing files
const preview = await Scaffold.from({ ...options, dryRun: true });Watch templates and regenerate on changes:
import { Watcher } from '@tiveor/scg';
const watcher = new Watcher({
templateDir: './templates',
outputDir: './generated',
engine: 'EJS',
variables: { project: 'MyApp' },
onRebuild: (file) => console.log(`Rebuilt: ${file}`),
onError: (err, file) => console.error(`Error in ${file}: ${err.message}`),
});
watcher.start();
// watcher.stop();Static methods for string manipulation.
// Replace all occurrences of a token (regex-safe)
StringHelper.replace('Hello {{name}}!', '{{name}}', 'World');
// => "Hello World!"
// Works safely with regex special characters
StringHelper.replace('Price: $10.00', '$10.00', '$20.00');
// => "Price: $20.00"
// Capitalize first character
StringHelper.capitalize('hello');
// => "Hello"
// Escape regex special characters
StringHelper.escapeRegex('$100.00 (test)');
// => "\\$100\\.00 \\(test\\)"Static methods for file system operations (sync and async).
// Sync
const content = FileHelper.readFileToString('config.txt');
const config = FileHelper.convertJsonFileToObject('config.json');
FileHelper.createFolder('output/components');
FileHelper.removeFolder('output/temp');
FileHelper.removeFile('output/old.txt');
// Async
const data = await FileHelper.readFileAsync('config.txt');
const json = await FileHelper.readJsonFileAsync('config.json');
await FileHelper.writeFileAsync('output/file.txt', 'content');
await FileHelper.createFolderAsync('output/components');
await FileHelper.removeFolderAsync('output/temp');
await FileHelper.removeFileAsync('output/old.txt');
const exists = await FileHelper.existsAsync('some/path');
// Generate file from template with variable replacement
await FileHelper.createFileFromFile({
template: 'templates/component.txt',
newFile: 'output/Button.tsx',
variables: [
{ token: '{{name}}', value: 'Button' },
{ token: '{{style}}', value: 'primary' }
]
});Execute shell commands as promises (with input sanitization).
// Run a command
const output = await CommandHelper.run('.', 'echo hello');
// Chain multiple commands
const result = await CommandHelper.run('.', 'git add .', 'git status');
// Run and clean output (strips newlines)
const version = await CommandHelper.runClean('.', 'node --version');Parse CLI parameters from process.argv.
// Add custom parameters
ParamHelper.addCustomParam('--env=production');
// Get parameter by index
const script = ParamHelper.getCommandByIndex(1);
// Parse all --key=value parameters
// Example: node script.js --name=Alice --port=3000
const params = ParamHelper.getParams();
// => { name: "Alice", port: "3000" }SCG includes a command-line interface for scaffolding and template rendering.
# Initialize a scaffold manifest
npx @tiveor/scg init
# Generate files from a scaffold manifest
npx @tiveor/scg generate --manifest=scaffold.json --vars=name=Button
# Preview without writing files
npx @tiveor/scg generate --manifest=scaffold.json --vars=name=Button --dry-run
# Render a single template
npx @tiveor/scg render template.ejs --data='{"name":"World"}'
# Render and save to file
npx @tiveor/scg render template.ejs --data='{"name":"World"}' --output=output.htmlSCG ships with ready-to-use template packs in the templates/ directory:
| Pack | Files | Description |
|---|---|---|
| react-component | component, test, styles, index | React TSX component with CSS modules |
| vue-component | component, test | Vue 3 SFC with <script setup> |
| express-route | routes, controller, service | Express REST route with MVC pattern |
| github-action | workflow | GitHub Actions CI workflow |
Each pack includes a scaffold.json manifest. Use them with the CLI:
npx @tiveor/scg generate --manifest=templates/react-component/scaffold.json --vars=name=Button,style=moduleOr programmatically:
import { Scaffold } from '@tiveor/scg';
import manifest from './templates/react-component/scaffold.json';
await Scaffold.from({ ...manifest, variables: { name: 'Button', style: 'module' } });See EXAMPLES.md for full documentation on all runnable examples:
- Basic Examples — Template rendering, Pipeline API, Scaffold engine, Plugin system
- Full Demo — CRUD API Generator (Express + TypeScript + Zod, 18 files, all 9 SCG features)
- Landing Page Demo — Vite + React + TypeScript + Vercel deploy (16 files)
npm testnpm run build # Build CJS + ESM + .d.ts
npm run dev # Build in watch mode
npm test # Run tests
npm run test:watch # Run tests in watch mode
npm run lint # Lint source code
npm run typecheck # Type check with tsc
npm run format # Format with Prettier
npm run docs # Generate API docs with TypeDocMIT - Alvaro Orellana - AlvaroTech.dev
