Writing a TypeScript Code Generator: Templates vs AST
A Software Engineer passionate about public good projects and making technology to serve society en masse.
Search for a command to run...
A Software Engineer passionate about public good projects and making technology to serve society en masse.
No comments yet. Be the first to comment.
HS (Harmonised System) Codes help classify customs authorities and businesses around the world to ensure appropriate import/export control. This system recursively classifies a product into finer granularity of categories. Figure 1: A simple exercis...
Jan allows you to deploy and run LLMs on your Windows or macOS computer! 16 Gigabytes of memory and a M1 chip was enough for me to run Mistral locally. Now how do you take Jan and use libraries like Langchain? https://jan.ai Local API Server Click ...
My talk at PyCon Thailand 2023 on the security aspects and possible attack vectors of LLM Applications, tailored to both product people and engineers! https://youtu.be/_fvk_Qa5OsM Thank you PyCon TH team!
Looking for a flat for rent, with LLMs
Code generators replace mindless coding with productivity; a pure function that produces predictable code, given a (set of) input(s). Generating boilerplate classes or templates — a common use case for Codegen.
We will be generating components (Class) that follow a repetitive yet predictable pattern.
export class HttpBinApi implements ICredentialType {
name = 'httpbinApi';
displayName = 'HttpBin API';
}
Notice how many times the developer has to rewrite “HTTP Bin API” in different cases and styles? Moreover, using the wrong case would cause linter issues and never-ending headaches. Could this be automated?
Simply using JavaScript String functions can take us a long way. Template Strings, joins and possibly a little bit of lodash .
function generateClass(name: string) {
return [
`export class ${pascalCase(name)}}Api implements ICredentialType {`,
` name = '${camelCase(name)}Api';`,
` displayName = '${titleCase(name)} API';`,
`}`,
].join('\n');
}
While this works, it makes me uncomfortable; my mind implicitly sees fragility in this approach. What if the code generator is more complex? What if we need to iterate through arrays or objects? What if the signatures change? It seems unmaintainable.
A more practical approach to string manipulation and using templates to generate code — could be Hygen. It handles file creation, manipulation of existing files gracefully.
The devs call it the “The scalable code generator that saves you time.” It is a code generation utility that integrates seamlessly into your development flow. It uses EJS templates to define your file structures.
---
to: src/credentials/<%= h.changeCase.pascal(name) %>.ts
---
export class <%= h.changeCase.pascal(name) %> implements ICredentialType {
name = "<%= h.changeCase.camel(name) %>";
displayName = "<%= name %>";
}
Check it out here: Hygen
Manipulating whitespace dependent languages like YAML or Python could be challenging with Hygen. — A dev who tried.
Let’s admit it, in our mind, “code generation is supposed to be a bit more complicated”. The simplicity here may be causing the nerves!
What if we could have a more programmatic-way of generating code? Instead of having apparently meaningless string concatenations, we had semantics and meanings?
Introducing ASTs. Code compilers usually do not compile strings of code directly. Instead, it can build up a tree-like structure of branches and objects and conditions.

A tree representation of a simple TypeScript class
For the HttpBinApi class mentioned at the top, the AST representation may look something like this:
factory.createClassDeclaration(
[factory.createToken(ts.SyntaxKind.ExportKeyword)],
factory.createIdentifier("HttpBinApi"),
//...
[
factory.createPropertyDeclaration(
factory.createIdentifier("name"),
//...
factory.createStringLiteral("httpbinApi")
),
factory.createPropertyDeclaration(
factory.createIdentifier("displayName"),
//...
factory.createStringLiteral("HttpBin API")
)
]
);
Do check out the TypeScript AST Viewer to play around with this Syntax Tree.

TypeScript AST Viewer in Action
Okay we went from string manipulation to extra-terrestrial programming in a paragraph. I encourage you to use the AST Viewer and click around for now. A few questions to get you started:
What does a const look like?
How about a let ?
A simple console.log ?
How about adding two numbers?
Okay, looping through an array of numbers?
All along, we’ve been converting TypeScript code to AST. But how do we do the opposite? Reconstructing TypeScript code is easy with the help of the built-in ts.Printer .
Step 1: Create a Printer.
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
Step 2: Create an Instance of a SourceFile .
const sourceFile = ts.createSourceFile(
'HttpBinApi.ts',
'',
ts.ScriptTarget.Latest,
false, // setParentNodes
ts.ScriptKind.TS,
);
Step 3: Render as String.
printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);

Check out a fully working, in-the-browser example right here: StackBlitz #1. Do feel free to play around with it!
Ah yes yes, now we can assemble everything together into a semi-working code generator.
Step 1: Parametrised the AST representation.
const className = `${_.upperFirst(_.camelCase(name))}Api`;
const classIdentifier = factory.createIdentifier(className);
Step 2: With my trusty Co-Pilot, a large language model — I have refactored the code to make more legible.
Check out the refactored version: StackBlitz #2.
console.log(generateClass('Cloud File Transfer'));
❯ ts-node index.ts
export class CloudFileTransferApi implements ICredentialType {
name = "cloudFileTransferApi";
displayName = "Cloud File Transfer";
}
There are no clear-cut winners here. Based on your requirements, you do need to make a call on simplicity vs robustness. Hope you had fun! 🎉
Hygen | Hygen — Code Generation Framework based on EJS Templates
Using the Compiler API · microsoft/TypeScript Wiki (github.com)