JSPM

  • Created
  • Published
  • Downloads 65
  • Score
    100M100P100Q81747F
  • License MIT

FHIR TypeScript code generator from HL7 StructureDefinitions and SearchParameters

Package Exports

  • @fhir-dsl/generator

Readme

@fhir-dsl/generator

FHIR TypeScript code generation engine. Parses HL7 StructureDefinitions and SearchParameters to emit fully typed TypeScript interfaces, search parameter registries, and profile types.

This is the engine behind @fhir-dsl/cli. Most users should use the CLI directly — install this package only if you're building custom tooling on top of the generator.

Install

npm install @fhir-dsl/generator

Usage

Generate types programmatically

import { generate } from "@fhir-dsl/generator";

await generate({
  version: "r4",
  outDir: "./src/fhir",
  igs: ["hl7.fhir.us.core@6.1.0"],
});

Emit markdown spec alongside types

Pass includeSpec: true to write a parallel spec/ tree (resources/*.md, profiles/*.md, index.md) summarizing every emitted resource. Built from the same StructureDefinition data used for code generation — no extra network calls — and intended as context for AI assistants working against the generated types.

await generate({
  version: "r4",
  outDir: "./src/fhir",
  resources: ["Patient", "Observation"],
  includeSpec: true,
});

Load and parse FHIR specs

import { downloadSpec, downloadIG, loadLocalSpec } from "@fhir-dsl/generator";

// Download from official registry
const spec = await downloadSpec("r4");

// Download an Implementation Guide
const ig = await downloadIG("hl7.fhir.us.core@6.1.0");

// Or load from a local directory
const local = await loadLocalSpec("./fhir-definitions");

Parse individual definitions

import { parseStructureDefinition, parseProfile, parseSearchParameters } from "@fhir-dsl/generator";

const resource = parseStructureDefinition(structureDef);
const profile = parseProfile(profileDef);
const searchParams = parseSearchParameters(searchParamDefs);

Emit a runnable MCP server alongside the typed client

Pass mcp: { outDir } (or --mcp <dir> from the CLI) to scaffold a full MCP server next to the generated types — server.ts shim, mcp.config.json seeded with the IG's resource types, and a README. Launch it with FHIR_BASE_URL=… node mcp-server/server.ts.

await generate({
  version: "r4",
  outDir: "./src/fhir",
  igs: ["hl7.fhir.us.core@6.1.0"],
  mcp: { outDir: "./mcp-server" },
});

Standard Schema validators with auto-wired invariants

Pass validator: "native" | "zod" to emit Standard Schema V1 validators for every resource, datatype, binding, and profile. From v0.49.0 onward, every emitted schema with ElementDefinition.constraint[*] is wrapped in s.refine(...) (native) or .superRefine(...) (zod) that calls validateInvariants after structural validation succeeds — so .validate() rejects resources that pass the shape check but fail an invariant. Opt out with noInvariants: true. Generated projects need @fhir-dsl/fhirpath as a runtime dependency when invariants are wired.

await generate({
  version: "r4",
  outDir: "./src/fhir",
  validator: "native",          // or "zod"
  strictExtensible: false,      // treat extensible bindings as open (default) vs. closed
  // noInvariants: true,        // optional: skip the FHIRPath invariant wiring
});

Boolean-existence search-param emitter (v1.0.1, fixes #45)

When a search parameter's expression matches the <X>.exists() and <X> != false pattern (FHIR's idiomatic "is the boolean true?" shape — used by Patient.active, Account.active, …), the emitter now narrows the typed value to TokenParam<"true" | "false"> instead of leaving it as a free-form token. Round-trip with .where("active", "eq", "true") is type-safe.

Profile slice → typed extension narrowing (v1.0.1, fixes #46)

Profiles are emitted with an ExtensionTypeMap so slice fields whose type[].profile references a generated Extension<URL> interface are narrowed to that exact branded interface. For example, US Core Patient's extension_usCoreRace? is typed as Extension<"http://hl7.org/fhir/us/core/StructureDefinition/us-core-race">, not the open Extension union — the .value[x] payload, the .url constant, and any nested slices come along for the ride.

What Gets Generated

out/
  index.ts           # FhirSchema type and re-exports
  primitives.ts      # FHIR primitive types
  datatypes.ts       # Complex datatypes
  registry.ts        # Resource type registry
  search-params.ts   # Typed search parameters per resource
  resources/         # One file per resource
  profiles/          # One file per profile (when IGs are included)
  schemas/           # Standard Schema validators (when validator is set)
  spec/              # Markdown spec files (when includeSpec: true)
  client.ts          # Pre-configured FhirClient type with typed createClient()

When mcp: { outDir } is also set:

mcp-server/
  server.ts          # Runnable MCP shim that calls createServer({ ... })
  mcp.config.json    # IG-seeded config (resource-type allowlist, defaults)
  README.md          # Launch instructions

License

MIT