TSTemplate
TSTemplate is a port of the ESTemplate API for TypeScript! TSTemplate allows you to do template substitution with AST nodes, rather than with text, which I guess is good? Who knows!
Installation:
npm install @phenomnomnominal/tstemplate --save-dev
Examples:
You can substitute "homemade" AST nodes like this:
import { tstemplate } from '@phenomnomnominal/tstemplate';
import { createPrinter, Identifier, NumericLiteral, SourceFile } from 'typescript'
const result: SourceFile = tstemplate('var <%= varName %> = <%= value %> + 1;', {
varName: { kind: SyntaxKind.Identifier, escapedText: 'myVar' } as Identifier,
value: { kind: SyntaxKind.NumericLiteral, text: '123' } as NumericLiteral
});
const printer = createPrinter();
console.log(printer.printFile(result));
Or you can use "real" TS AST nodes from TypeScript):
import { tstemplate } from '@phenomnomnominal/tstemplate';
import { createIdentifier, createPrinter, Identifier, SourceFile } from 'typescript'
const result: SourceFile = tstemplate('function f(%= params %, callback) { }', {
params: [createIdentifier('a'), createIdentifier('b')]
});
const printer = createPrinter();
console.log(printer.printFile(result));
You can even use something like TSQuery
to move nodes from one file to another:
import { tsquery } from '@phenomnomnominal/tsquery';
import { tstemplate } from '@phenomnomnominal/tstemplate';
import { readFileSync } from 'fs';
import { createPrinter } from 'typescript';
const ts = readFileSync('./some-typescript.ts'), 'utf-8');
const body = tsquery(ts, 'ExpressionStatement');
const result = tstemplate('wrap(() => {%= body %});', { body });
const printer = createPrinter();
console.log(printer.printFile(result));
You can also pre-compile the template and then re-use it with different data:
import { tsquery } from '@phenomnomnominal/tsquery';
import { tstemplate } from '@phenomnomnominal/tstemplate';
import { createIdentifier, createPrinter } from 'typescript';
const template = tstemplate.compile('var <%= varName %> = <%= value %> + 1;');
const result1 = template({
varName: createIdentifier('myVar'),
value: tsquery('123', 'NumericLiteral')
});
const result2 = template({
varName: createIdentifier('otherVar'),
value: tsquery('234', 'NumericLiteral')
});
const printer = createPrinter();
console.log(printer.printFile(result1));
console.log(printer.printFile(result2));
Templating syntax:
- Node substitution:
var x = <%= expr %> + 1;
- Array elements:
var a = [%= elements %];
- Function parameters:
function f(%= params %) {}
- Call arguments:
var x = f(%= args %);
- Block statements:
define(function () {%= body %});
- Literals:
var x = "%= 'alpha' + 'beta' %";
You can also combine list substitutions with inline elements:
var a = [0, %= numbers %, Infinity];
function f(%= params %, callback) {}
define(function () { console.time('Module'); %= body %; console.timeEnd('Module'); });