The scripts that consume our templates are mostly very simple ~15 line affairs but there are a few very complex, 1000+ line affairs that use the Typescript type checker API to codegen model classes and test data generators from hand-written interface types. Those things read ASTs but writing ASTs seems like a huge waste of time to me. AST is only nice if you need to very carefully morph existing code, and even then I usually end up doing a string replacement of an AST node’s position in its original file. In all that code I think the only thing that writes using an AST is import statement stuff.
Luckily that super complex stuff runs on every commit so it can’t break. It’s the one-off codegen commands like “make me a new component” or “make me an integration test” that are in danger of going stale, and even those we could write some CI tests for like “make a new thingy, check that it typechecks”.
Anyways here’s a full example template file:
/*__FILE_METADATA__*/
/* ================================================================================
__TEMPLATE_CLASS_NAME__.
Docs: https://dev.notion.so/notion/Record-Framework-1f41f97e1cc746628a6af57ba75d75ad
THIS IS FILE IS PARTIALLY GENERATED. ONLY EDIT THE EDITABLE REGION BELOW.
__GENERATED_BY__
__GENERATED_FROM__
================================================================================ */
import type {
/*__VALUE_IMPORT__*/ BlockValue as __VALUE_TYPE__,
/*__TABLE_IMPORT__*/ BlockTable as __TABLE__,
} from /*__SCHEMA_IMPORT__*/ "../schemas/Block"
import { Model } from "./Model"
/*__REMOVE_LINE__*/ // : Value <Value> as __MODEL__<Value> | undefined <- Conform to template args in RecordStore.
/**
* This class is generated from {@link __VALUE_TYPE__}.
* To customize, edit the section in {@link __TEMPLATE_CLASS_NAME__} below.
*/
abstract class Generated__TEMPLATE_CLASS_NAME__<
Value extends __VALUE_TYPE__ = __VALUE_TYPE__
> extends Model<Value, __TABLE__> {
/*__REMOVE_LINE__*/
__BODY__: undefined // Put the goods here.
}
/**
* Read and interpret the data of a __RECORD__ record.
*/
export class __TEMPLATE_CLASS_NAME__<
Value extends __VALUE_TYPE__ = __VALUE_TYPE__
> extends Generated__TEMPLATE_CLASS_NAME__<Value> {
/*__USER_EDITABLE_SECTION__*/
}