Problem
I'm building a FHIR app framework (proc-ts) where every function lives in its own file with export default. I need to generate FHIR types that follow this convention:
// fhir/Patient.ts — our convention: one default export per file
export interface Patient { ... }
export default function isPatient(resource: unknown): resource is Patient {
return resource?.resourceType === "Patient";
}
The built-in .typescript() generator produces export const isPatient = ... which doesn't work for our module system. I want to write a custom writer that generates files in our format.
What I tried
- Extend
TypeScript class — not possible, TypeScript is not exported from the package
- Extend
Writer base class — not possible, Writer is not exported
- Use
.mustache() API — works for simple cases but lacks programmatic control (conditions, name transformations, type resolution)
- Post-process
.typescript() output — current workaround, but fragile regex replacement
What's needed
Export the writer infrastructure so users can build custom generators:
Minimum viable exports
// These are currently internal but needed to write a custom generator:
export { Writer, FileSystemWriter } from "./api/writer-generator/writer";
export type { WriterOptions, FileSystemWriterOptions, FileBuffer } from "./api/writer-generator/writer";
// TypeSchema types needed to iterate over FHIR definitions:
export type {
TypeSchema, SpecializationTypeSchema, NestedTypeSchema,
TypeIdentifier, Field, EnumDefinition, CanonicalUrl,
} from "./typeschema/types";
export {
isResourceTypeSchema, isComplexTypeIdentifier, isPrimitiveIdentifier,
isSpecializationTypeSchema, isChoiceDeclarationField,
} from "./typeschema/types";
// Utilities for grouping/sorting schemas:
export { groupByPackages, sortAsDeclarationSequence } from "./typeschema/utils";
export type { TypeSchemaIndex } from "./typeschema/utils";
// Helper utilities:
export { uppercaseFirstLetter, pascalCase, snakeCase, camelCase } from "./api/writer-generator/utils";
Registration API
A way to register a custom writer with APIBuilder:
// Option A: pass a writer class
builder.custom(MyWriter, { /* options */ })
// Option B: pass a factory function
builder.custom((tsIndex, options) => {
// generate files using tsIndex.collectResources(), etc.
})
Example usage
import { Writer, APIBuilder } from "@atomic-ehr/codegen";
import type { TypeSchemaIndex, SpecializationTypeSchema } from "@atomic-ehr/codegen";
class ProcTsWriter extends Writer {
async generate(tsIndex: TypeSchemaIndex) {
for (const schema of tsIndex.collectResources()) {
this.cd("/", () => {
this.cat(`${schema.identifier.name}.ts`, () => {
// generate interface...
// generate export default type guard
});
});
}
}
}
const builder = new APIBuilder()
.fromPackage("hl7.fhir.r4.core", "4.0.1")
.custom(ProcTsWriter, { /* options */ })
.outputTo("./fhir")
.generate();
Context
The Python and TypeScript writers in the repo (src/api/writer-generator/typescript/writer.ts, src/api/writer-generator/python.ts) demonstrate the pattern perfectly — they extend Writer and use TypeSchemaIndex to iterate schemas. But since these base types aren't exported, external users can't do the same.
The .mustache() API is a partial solution but doesn't cover cases requiring programmatic logic (conditional generation, custom naming, different file-per-type strategies).
Current workaround
We use .typescript() + post-process: flatten hl7-fhir-r4-core/ subfolder, regex replace export const isX → export default function isX. It works but is fragile and doesn't allow deeper customization.
Problem
I'm building a FHIR app framework (proc-ts) where every function lives in its own file with
export default. I need to generate FHIR types that follow this convention:The built-in
.typescript()generator producesexport const isPatient = ...which doesn't work for our module system. I want to write a custom writer that generates files in our format.What I tried
TypeScriptclass — not possible,TypeScriptis not exported from the packageWriterbase class — not possible,Writeris not exported.mustache()API — works for simple cases but lacks programmatic control (conditions, name transformations, type resolution).typescript()output — current workaround, but fragile regex replacementWhat's needed
Export the writer infrastructure so users can build custom generators:
Minimum viable exports
Registration API
A way to register a custom writer with
APIBuilder:Example usage
Context
The Python and TypeScript writers in the repo (
src/api/writer-generator/typescript/writer.ts,src/api/writer-generator/python.ts) demonstrate the pattern perfectly — they extendWriterand useTypeSchemaIndexto iterate schemas. But since these base types aren't exported, external users can't do the same.The
.mustache()API is a partial solution but doesn't cover cases requiring programmatic logic (conditional generation, custom naming, different file-per-type strategies).Current workaround
We use
.typescript()+ post-process: flattenhl7-fhir-r4-core/subfolder, regex replaceexport const isX→export default function isX. It works but is fragile and doesn't allow deeper customization.