Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
.codegen-cache/
bundle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# US Core Profiles in TypeScript with @atomic-ehr/codegen

A small CSV-to-FHIR converter demonstrating [`@atomic-ehr/codegen`](https://github.com/atomic-ehr/codegen) profile class generation for US Core. Companion to the blog post [Tutorial: US Core Profiles in TypeScript with @atomic-ehr/codegen](https://www.health-samurai.io/articles/atomic-ehr-codegen-typescript-us-core-profiles).

The example:

1. generates profile classes for [US Core Patient](https://www.hl7.org/fhir/us/core/StructureDefinition-us-core-patient.html) and [US Core Blood Pressure](https://www.hl7.org/fhir/us/core/StructureDefinition-us-core-blood-pressure.html) plus base `Bundle` from `hl7.fhir.r4.core`,
2. loads `patients.csv` (5 rows: MRN, name, demographics, race, one BP reading each),
3. converts each row into a validated `USCorePatientProfile` + `USCoreBloodPressureProfile`,
4. packages them as a transaction `Bundle` with `urn:uuid` cross-references,
5. reads the bundle back with typed getters and prints the average BP.

## Files

| File | Purpose |
|------|---------|
| `generate.ts` | Runs `@atomic-ehr/codegen` to produce typed profile classes in `fhir-types/` |
| `fhir-types/` | Generated output (committed so you can browse without running the generator) |
| `patients.csv` | Sample input (5 rows) |
| `load.ts` | Parses CSV, builds the Bundle, computes avg BP from the bundle |

## Run It

```bash
npm install
npx tsx generate.ts # regenerate fhir-types/ (optional -- already committed)
npx tsx load.ts # reads patients.csv, writes bundle.json, prints avg BP
```

Expected output:

```
Loaded 5 rows
Wrote bundle with 10 entries
Avg BP: 125.2/82.0 mmHg (n=5)
```

## POST to a FHIR Server (Optional)

Any FHIR-compliant server accepts the generated `bundle.json` at its root endpoint. If you want to try it end-to-end, [run Aidbox in Docker](https://docs.aidbox.app/getting-started/run-aidbox/run-aidbox-locally) in two minutes and then:

```bash
curl -u root:secret -X POST \
-H "Content-Type: application/fhir+json" \
-d @bundle.json http://localhost:8080/fhir
```

Aidbox resolves the `urn:uuid` references to concrete Patient IDs during the transaction commit -- check with:

```bash
curl -u root:secret "http://localhost:8080/fhir/Patient?family=Lovelace"
curl -u root:secret "http://localhost:8080/fhir/Observation?code=http://loinc.org|85354-9" \
| jq '.entry[].resource.subject.reference'
```

## Notes on the Code

- **`Row` is all strings.** The parser doesn't narrow types; each converter (`rowToPatient`, `rowToBP`) casts or converts where needed (`gender as Patient["gender"]`, `Number(row.systolic)`).
- **Must-support base fields** (`gender`, `birthDate`) are set via `Object.assign(patient.toResource(), ...)` because US Core doesn't profile them further, so the profile class doesn't emit setters for them.
- **`urn:uuid` references work directly.** The generated `Reference.reference` is typed as a union covering every FHIR literal reference form (`Patient/${id}`, absolute `http://...`, `urn:uuid:...`, `urn:oid:...`, `#fragment`). Transaction Bundle placeholder UUIDs drop right in; the server rewrites them to real `Patient/<id>` on commit.
- **Generator warnings** are noisy (duplicate schemas, missing fields in upstream packages). They don't block generation; the output is usable.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Element } from "../hl7-fhir-r4-core/Element";
import type { Period } from "../hl7-fhir-r4-core/Period";

export type { Element } from "../hl7-fhir-r4-core/Element";
export type { Period } from "../hl7-fhir-r4-core/Period";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/Address (pkg: hl7.fhir.r4.core#4.0.1)
export interface Address extends Element {
city?: string;
_city?: Element;
country?: string;
_country?: Element;
district?: string;
_district?: Element;
line?: string[];
_line?: (Element | null)[];
period?: Period;
postalCode?: string;
_postalCode?: Element;
state?: string;
_state?: Element;
text?: string;
_text?: Element;
type?: ("postal" | "physical" | "both");
_type?: Element;
use?: ("home" | "work" | "temp" | "old" | "billing");
_use?: Element;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Quantity } from "../hl7-fhir-r4-core/Quantity";

export type { Quantity } from "../hl7-fhir-r4-core/Quantity";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/Age (pkg: hl7.fhir.r4.core#4.0.1)
export interface Age extends Quantity {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Element } from "../hl7-fhir-r4-core/Element";
import type { Reference } from "../hl7-fhir-r4-core/Reference";

export type { Element } from "../hl7-fhir-r4-core/Element";
export type { Reference } from "../hl7-fhir-r4-core/Reference";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/Annotation (pkg: hl7.fhir.r4.core#4.0.1)
export interface Annotation extends Element {
authorReference?: Reference<"Organization" | "Patient" | "Practitioner" | "RelatedPerson">;
authorString?: string;
_authorString?: Element;
text: string;
_text?: Element;
time?: string;
_time?: Element;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Element } from "../hl7-fhir-r4-core/Element";

export type { Element } from "../hl7-fhir-r4-core/Element";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/Attachment (pkg: hl7.fhir.r4.core#4.0.1)
export interface Attachment extends Element {
contentType?: string;
_contentType?: Element;
creation?: string;
_creation?: Element;
data?: string;
_data?: Element;
hash?: string;
_hash?: Element;
language?: ("ar" | "bn" | "cs" | "da" | "de" | "de-AT" | "de-CH" | "de-DE" | "el" | "en" | "en-AU" | "en-CA" | "en-GB" | "en-IN" | "en-NZ" | "en-SG" | "en-US" | "es" | "es-AR" | "es-ES" | "es-UY" | "fi" | "fr" | "fr-BE" | "fr-CH" | "fr-FR" | "fy" | "fy-NL" | "hi" | "hr" | "it" | "it-CH" | "it-IT" | "ja" | "ko" | "nl" | "nl-BE" | "nl-NL" | "no" | "no-NO" | "pa" | "pl" | "pt" | "pt-BR" | "ru" | "ru-RU" | "sr" | "sr-RS" | "sv" | "sv-SE" | "te" | "zh" | "zh-CN" | "zh-HK" | "zh-SG" | "zh-TW" | string);
_language?: Element;
size?: number;
_size?: Element;
title?: string;
_title?: Element;
url?: string;
_url?: Element;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Element } from "../hl7-fhir-r4-core/Element";
import type { Extension } from "../hl7-fhir-r4-core/Extension";

export type { Element } from "../hl7-fhir-r4-core/Element";
export type { Extension } from "../hl7-fhir-r4-core/Extension";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/BackboneElement (pkg: hl7.fhir.r4.core#4.0.1)
export interface BackboneElement extends Element {
modifierExtension?: Extension[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { BackboneElement } from "../hl7-fhir-r4-core/BackboneElement";
import type { Identifier } from "../hl7-fhir-r4-core/Identifier";
import type { Resource } from "../hl7-fhir-r4-core/Resource";
import type { Signature } from "../hl7-fhir-r4-core/Signature";

import type { Element } from "../hl7-fhir-r4-core/Element";
export type { BackboneElement } from "../hl7-fhir-r4-core/BackboneElement";
export type { Identifier } from "../hl7-fhir-r4-core/Identifier";
export type { Signature } from "../hl7-fhir-r4-core/Signature";

export interface BundleEntry<T extends Resource = Resource> extends BackboneElement {
fullUrl?: string;
link?: BundleLink[];
request?: BundleEntryRequest;
resource?: T;
response?: BundleEntryResponse;
search?: BundleEntrySearch;
}

export interface BundleEntryRequest extends BackboneElement {
ifMatch?: string;
ifModifiedSince?: string;
ifNoneExist?: string;
ifNoneMatch?: string;
method: ("GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "PATCH");
url: string;
}

export interface BundleEntryResponse<T extends Resource = Resource> extends BackboneElement {
etag?: string;
lastModified?: string;
location?: string;
outcome?: T;
status: string;
}

export interface BundleEntrySearch extends BackboneElement {
mode?: ("match" | "include" | "outcome");
score?: number;
}

export interface BundleLink extends BackboneElement {
relation: string;
url: string;
}

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/Bundle (pkg: hl7.fhir.r4.core#4.0.1)
export interface Bundle extends Resource {
resourceType: "Bundle";

entry?: BundleEntry[];
identifier?: Identifier;
link?: BundleLink[];
signature?: Signature;
timestamp?: string;
_timestamp?: Element;
total?: number;
_total?: Element;
type: ("document" | "message" | "transaction" | "transaction-response" | "batch" | "batch-response" | "history" | "searchset" | "collection");
_type?: Element;
}
export const isBundle = (resource: unknown): resource is Bundle => {
return resource !== null && typeof resource === "object" && (resource as {resourceType: string}).resourceType === "Bundle";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Coding } from "../hl7-fhir-r4-core/Coding";
import type { Element } from "../hl7-fhir-r4-core/Element";

export type { Coding } from "../hl7-fhir-r4-core/Coding";
export type { Element } from "../hl7-fhir-r4-core/Element";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/CodeableConcept (pkg: hl7.fhir.r4.core#4.0.1)
export interface CodeableConcept<T extends string = string> extends Element {
coding?: Coding<T>[];
text?: string;
_text?: Element;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Element } from "../hl7-fhir-r4-core/Element";

export type { Element } from "../hl7-fhir-r4-core/Element";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/Coding (pkg: hl7.fhir.r4.core#4.0.1)
export interface Coding<T extends string = string> extends Element {
code?: T;
_code?: Element;
display?: string;
_display?: Element;
system?: string;
_system?: Element;
userSelected?: boolean;
_userSelected?: Element;
version?: string;
_version?: Element;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { ContactPoint } from "../hl7-fhir-r4-core/ContactPoint";
import type { Element } from "../hl7-fhir-r4-core/Element";

export type { ContactPoint } from "../hl7-fhir-r4-core/ContactPoint";
export type { Element } from "../hl7-fhir-r4-core/Element";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/ContactDetail (pkg: hl7.fhir.r4.core#4.0.1)
export interface ContactDetail extends Element {
name?: string;
_name?: Element;
telecom?: ContactPoint[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Element } from "../hl7-fhir-r4-core/Element";
import type { Period } from "../hl7-fhir-r4-core/Period";

export type { Element } from "../hl7-fhir-r4-core/Element";
export type { Period } from "../hl7-fhir-r4-core/Period";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/ContactPoint (pkg: hl7.fhir.r4.core#4.0.1)
export interface ContactPoint extends Element {
period?: Period;
rank?: number;
_rank?: Element;
system?: ("phone" | "fax" | "email" | "pager" | "url" | "sms" | "other");
_system?: Element;
use?: ("home" | "work" | "temp" | "old" | "mobile");
_use?: Element;
value?: string;
_value?: Element;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { ContactDetail } from "../hl7-fhir-r4-core/ContactDetail";
import type { Element } from "../hl7-fhir-r4-core/Element";

export type { ContactDetail } from "../hl7-fhir-r4-core/ContactDetail";
export type { Element } from "../hl7-fhir-r4-core/Element";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/Contributor (pkg: hl7.fhir.r4.core#4.0.1)
export interface Contributor extends Element {
contact?: ContactDetail[];
name: string;
_name?: Element;
type: ("author" | "editor" | "reviewer" | "endorser");
_type?: Element;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// WARNING: This file is autogenerated by @atomic-ehr/codegen.
// GitHub: https://github.com/atomic-ehr/codegen
// Any manual changes made to this file may be overwritten.

import type { Quantity } from "../hl7-fhir-r4-core/Quantity";

export type { Quantity } from "../hl7-fhir-r4-core/Quantity";

// CanonicalURL: http://hl7.org/fhir/StructureDefinition/Count (pkg: hl7.fhir.r4.core#4.0.1)
export interface Count extends Quantity {
}
Loading