Skip to content

Releases: atomic-ehr/codegen

v0.0.16

Choose a tag to compare

@ryukzak ryukzak released this 22 Jun 07:53

The big one: Python now supports profiles. The Python generator has mostly caught up with TypeScript this release — profile classes, generic Bundle[T], and nicer defaults (fhirpy + camelCase out of the box). Plus some lint tightening, a tidier examples layout, and a couple of package-resolution fixes.

Python profiles 🎉

generateProfile: true now spits out a typed wrapper class for each FHIR profile, just like the TypeScript side. You get create() / apply() / from_resource() constructors, to_resource() to unwrap, and a validate() that checks required fields, fixed values, slice cardinality, must-support, prohibited choices, enums, and reference targets. Fields, extensions, and slices all get typed get_X / set_X accessors (extensions can return flat values, a raw Extension, or a wrapped profile). A profile_helpers.py runtime ships with each profiles/ package. — @MikhailArtemyev in #167

# before — raw Pydantic, every fixed value by hand
obs = Observation(resource_type="Observation", status="final",
    code=CodeableConcept(coding=[Coding(code="85354-9", system="http://loinc.org")]),
    component=[ObservationComponent(...)], ...)

# after — the profile class fills fixed values, slices, and meta.profile for you
bp = UscoreBloodPressureProfile.create(status="final", subject=Reference(reference="Patient/123"))

👉 See it end-to-end in the US Core profiles example.

Other Python goodies

  • Generic Bundle[T]. Bundle, BundleEntry, BundleEntryResponse, and DomainResource are now generic — Bundle[Patient] narrows statically, and bare Bundle.from_json() still dispatches by resourceType at runtime. No more ResourceFamily union. — @MikhailArtemyev in #164

    bundle: Bundle[Patient] = Bundle[Patient].model_validate(response.json())   # typed
    bundle = Bundle.from_json('{"type":"collection","entry":[...]}')            # still polymorphic
  • Nicer defaults. Two config changes worth knowing about:

    • fhirpy is now the default client. The boolean fhirpyClient is deprecated (still works) — use client: "fhirpy" | "none" instead, or just omit it. — @ryukzak in #187
    • fieldFormat now defaults to camelCase, so models keep their FHIR spelling instead of converting to snake_case. Opt back in with .python({ fieldFormat: "snake_case" }). — @ryukzak in #189
    .python({ client: "none" })            // plain Pydantic, no fhirpy
    .python({ fieldFormat: "snake_case" }) // old snake_case behavior
  • Fixes. Extensions now serialize with proper FHIR aliases (valueCoding, not value_coding) and the profile generator honors fieldFormat end-to-end (#178), profile_helpers.py moved into the generated profiles/ package (#179), and the python-us-core example is mypy --strict clean (#180, #183). — @MikhailArtemyev, @ryukzak

Elsewhere

  • TypeSchema: stop recursing forever on packages with cyclic dependencies. — @ryukzak in #174
  • API: fix SQL-on-FHIR generation by adding the missing hl7.fhir.r5.core dependency. — @ryukzak in #175
  • Lint: turn on a batch of stricter Biome rules and fix everything they flagged. — @ryukzak in #182
  • Examples: consolidate the example dirs — typescript-r4-us-core, python-r4-us-core, CCDA moved to on-the-fly/ccda, and deduped TS profile tests. — @ryukzak in #184

Contributors

@MikhailArtemyev, @ryukzak

Full Changelog: v0.0.15...v0.0.16

v0.0.15

Choose a tag to compare

@ryukzak ryukzak released this 03 Jun 09:36

This release focuses on TypeScript profile correctness — generated validate() methods and choice setters now match what a FHIR server accepts, closing several gaps where invalid resources passed client-side validation only to be rejected at write time.

Highlights (TypeScript profiles)

  • Inherited required fields are now validated. Profile snapshots silently dropped any base-resource cardinality the profile differential didn't re-state, so validate() skipped inherited required fields (e.g. Provenance.target, Provenance.recorded). These now emit validateRequired() calls. — by @sussdorff in #166

  • choice[x] mutual exclusion is enforced in setters. A polymorphic value[x] permits at most one variant, but setters assigned independently — populating two left both set and serialized invalid FHIR. Setters now clear sibling variants, and a public clearValue() / clearEffective() helper lets you drop a choice entirely. — by @ryukzak in #172

    // before — both survive (invalid)
    obs.setValueQuantity({ value: 120, unit: "mmHg" });
    obs.setValueCodeableConcept({ text: "unable to obtain" });
    // => { valueQuantity: {...}, valueCodeableConcept: {...} }
    
    // after — setting one clears the others
    // => { valueCodeableConcept: {...} }
    obs.clearValue(); // or drop it explicitly
  • Fixed CodeableConcept codings are preserved. apply() now merges fixed values instead of replacing them, so caller-provided secondary codings survive while missing fixed codings are added. — by @sussdorff in #165

Fixes

  • Skip base choice[x] declarations when collecting inherited required fields — previously emitted a validateRequired(res, profile, "value[x]") check against a key that never exists in FHIR JSON. — by @ryukzak in #170
  • Placeholder-only ValueSet expansions (e.g. a sole UNK code) no longer generate enum validation constraints. — by @sussdorff in #165
  • Profiles that relax a base field to min: 0 no longer emit a spurious required check. — by @sussdorff in #166

Internal

  • Introduce SnapshotProfileTypeSchema — a writer-ready profile shape that moves profile method derivation out of the TS writer into TypeSchema (output byte-identical seam for upcoming work). — by @ryukzak in #158
  • Fix test-fixture pollution causing platform-dependent snapshot failures. — by @sussdorff in #155

Examples & CI

  • Align the typescript-us-core example with the tutorial and demo Bundle<T>. — by @ryukzak in #157
  • Add an example demo for inherited base-required field validation. — by @ryukzak in #171
  • Bump Node to 22 for the package-managers CI job. — by @ryukzak in #156

Contributors

@sussdorff, @ryukzak

Full Changelog: v0.0.14...v0.0.15

v0.0.14

Choose a tag to compare

@ryukzak ryukzak released this 04 May 13:28

Highlights

  • TS: Bundle<T> and any specialization carrying typeFamily-rooted fields (top-level or nested) now exposes generic parameters, so callers can narrow Bundle<Patient | Observation> and entry[].resource is typed accordingly. Defaults preserve every existing call site. (#148)
  • TS: profile classes now emit a static is(resource): resource is Base type guard, so (bundle.entry ?? []).map(e => e.resource).filter(USCoreBloodPressureProfile.is) narrows without a hand-rolled predicate. (#147)

Improvements

  • TS: Reference<T> accepts every FHIR literal reference form — Type/id, http(s)://…, urn:uuid:…, urn:oid:…, #fragment — by @ryukzak in #144
  • API: prettyReport groups generated files by language/generator and adds a fileLimit option to truncate long lists — by @ryukzak in #143
  • TypeSchema: npm-style scoped package names (@scope/name) now emit valid kebab-case directories — by @jkiddo in #152

Fixes

  • TypeSchema: skip R5-only types when generating R4-target extensions and emit a clearer error pointing at the offending reference — by @ryukzak in #153

New Contributors

Full Changelog: v0.0.13...v0.0.14

v0.0.13

Choose a tag to compare

@ryukzak ryukzak released this 20 Apr 15:48

What's Changed

Fixes

  • PY: Fix to_json() omitting resourceType from serialized output — @ryukzak in #136
  • TS: Fix duplicate meta key in createResource when meta is a profile factory param (#137) — @sussdorff in #138

Improvements

  • API: Add ignorePackageIndex option to force .index.json regeneration — @ryukzak in #139
  • CI: Add on-the-fly generation examples for Norge R4 and KBV R4 — @ryukzak in #139

New Contributors

Full Changelog: v0.0.12...v0.0.13

v0.0.12

Choose a tag to compare

@ryukzak ryukzak released this 17 Apr 07:26

What's Changed

  • Fix work in CJS mode. CI: Rework package-managers job and update deps by @ryukzak in #135
  • TypeSchema: Replace inline FHIRValue casts with proper FHIRCoding import by @ryukzak in #133
  • TypeSchema: Precompute base names for profile methods by @ryukzak in #132

Full Changelog: v0.0.11...v0.0.12

v0.0.11

Choose a tag to compare

@ryukzak ryukzak released this 08 Apr 12:29

Highlights

This release focuses on the TypeScript Profile API — making generated profile classes more type-safe, more complete in validation, and easier to use with slices.

Python: Extension support (#107)

Extension support for the Python/Pydantic code generator.

TypeScript Profile API

Profile apply() / create() fixes (#121)

  • apply() now sets fixed-value fields and auto-populates discriminator-only slice stubs, matching create() behavior
  • Fixed-value fields get a getter but no setter
  • Extension apply() sets URL, uses upsert for single extensions

Remove buildResource, fix type safety (#126)

  • Remove buildResource<T>() helper — createResource now uses plain object literals for better type checking
  • Generate Reference<string /* Resource */> for family type references so narrower references like Reference<"Patient"> are assignable to base type fields
  • Fix tryPromoteChoice to correctly resolve reference targets with generic params

SliceFlat / SliceFlatAll type split (#127)

Slice flat types are now split into two:

  • SliceFlat — setter input, discriminator fields omitted (auto-applied)
  • SliceFlatAll — getter return, includes readonly discriminator literal types
setVSCat(input?: VSCatSliceFlat): this              // no discriminators needed
getVSCat(): VSCatSliceFlatAll | undefined            // includes { coding: [...] }

Array API for unbounded slices (#129)

Slices with max: * now use array-based setters/getters instead of single-element API:

// Before — second call replaces first
bundle.setOrganizationEntry({ resource: org1 });
bundle.setOrganizationEntry({ resource: org2 });

// After — set all at once
bundle.setOrganizationEntry([{ resource: org1 }, { resource: org2 }]);

Slice field validation (#130)

validate() now checks required fields inside matched slice elements. For example, BP profile reports missing valueQuantity in component slices:

profile.validate().errors
// [
//   "component[SystolicBP].valueQuantity is required",
//   "component[DiastolicBP].valueQuantity is required",
// ]

Cleanup (#131)

  • Remove dead stripMatchKeys export
  • Document Profile API in CLAUDE.md

Contributors

Full Changelog: v0.0.10...v0.0.11

v0.0.10

Choose a tag to compare

@ryukzak ryukzak released this 27 Mar 09:18

Features

TypeSchema: Auto-collect extension dependencies during tree shake (#103)

  • Extension definitions used by profiles are now included automatically — no need to list them manually in tree shake config
  • Add ignoreExtensions tree shake rule for excluding specific extensions by canonical URL

TypeSchema/TS: Choice type narrowing and validation for profiles (#105)

  • Restrict ChoiceFieldDeclaration.choices to only the variants declared by the most derived constraint
  • Emit validateExcluded for disallowed choice variants in profile validation (e.g. body weight only permits valueQuantity, 10 others are excluded)

TypeSchema/API: Collision resolution config (#106)

  • When multiple FHIR schemas produce a binding enum with the same name (e.g. ObservationCategory from Observation and DiagnosticReport), the generator must pick one — previously it auto-selected the most common source and emitted a warning
  • Add resolveCollisions option to .typeSchema() for explicit control over which source wins
  • IR report now shows (selected) / (auto) marks and suggests config snippets for unresolved collisions

TS: Type discriminator support for slicing (#108)

  • Support type discriminator in slicing — match slices by resourceType field
  • Generate typed getters/setters for type-discriminated slices (e.g. getPatientEntry() / setPatientEntry())
  • Example: Bundle Profile SD, profile-typed-bundle.test.ts.

TS: Generic type-family fields (#109)

  • Emit generic type parameters for fields typed as a resource base type (Resource, DomainResource)
  • BundleEntry<T extends Resource = Resource>, DomainResource<T> — unparameterized usage is unchanged
  • Profile slices use narrowed generics: BundleEntry<Patient>, BundleEntry<Organization>

TypeSchema refactoring

  • Renames (#114, #117):
    • RegularTypeSchemaSpecializationTypeSchema
    • IdentifierTypeIdentifier
    • NestedTypeSchemaNestedType
  • Remove generated profile override interface (#104)
  • Narrow FieldSlicing discriminator type from string to literal union (#110)
  • Add typeFamily.complexTypes, remove resourceChildren (#111)
  • Make SpecializationTypeSchema a discriminated union: ResourceTypeSchema | ComplexTypeTypeSchema | LogicalTypeSchema (#113)
  • Split resolve into resolve(Identifier) and resolveType(TypeIdentifier) (#113)
  • Split dependency types: Identifier[] for specializations, TypeIdentifier[] for profiles (#118)

Maintenance

  • Update @atomic-ehr/fhirschema to 0.0.9 (#119)
  • Remove dead code found by knip (#120)

Full Changelog: v0.0.9...v0.0.10

v0.0.9

Choose a tag to compare

@ryukzak ryukzak released this 12 Mar 18:01

Highlights

US Core profile support — generated profile classes now cover US Core IG with typed extension setters, component slice accessors, and validate() returning { errors, warnings } with must-support field tracking. See the blog post and working examples.

What's Changed

TypeScript:

  • Fix: skip choice flattening for primitive variant types by @ryukzak in #99
  • Refactor TypeScript profile codegen: typed helpers, reduced casts, resolved references by @ryukzak in #101
  • US Core profile support, unified getter/setter API, validate() with errors/warnings and must-support by @ryukzak in #102

Python:

Internal:

Full Changelog: v0.0.8...v0.0.9

v0.0.8

Choose a tag to compare

@ryukzak ryukzak released this 05 Mar 07:39

What's Changed

  • TS: Fix primitive array extension types and add extension tests by @ryukzak in #76
  • TS: Enhance profile code generation with factory methods, extensions, and pattern values by @ryukzak in #81
  • Python: feat: improve support for fhirpy client (rebased) by @ruscoder, @MikhailArtemyev in #88
  • Fix logic-promotion + Improve test coverage by @MikhailArtemyev in #73
  • Detect non-BackboneElement nested types via elements-based analysis by @ryukzak in #83
  • Unify FHIR package patching via preprocessPackage hook by @ryukzak in #84
  • Add profile class enhancements: getters, validation, and BP support by @ryukzak in #90
  • Auto-populate required slices in profile createResource() by @ryukzak in #91
  • Preserve original SD slice name casing in generated methods by @ryukzak in #94
  • Flatten single-variant choice types and optional slice auto-fields by @ryukzak in #95

Internal:

  • Refactor TypeScript writer into modular file structure by @ryukzak in #82
  • Update docs, README, and blog posts by @ryukzak in #93
  • Fix US Core example imports and add Makefile target by @ryukzak in #92

Full Changelog: v0.0.7...v0.0.8

v0.0.7

Choose a tag to compare

@ryukzak ryukzak released this 14 Feb 07:20

What's Changed

  • Export profile base interface alongside the profile class by @aartaka in #68
  • TypeSchema: collision detection, open enum bindings, and file overwrite warnings by @ryukzak in #69
  • Add CCDA (not CDA) tests by @aartaka in #70
  • refactor: cleanup and reduce code complexity by @ryukzak in #71
  • Export registerFromPackageMetas for use in CCDA converter by @aartaka in #72
  • Improve cross-package type resolution and add Norwegian FHIR package support by @ryukzak in #75

Full Changelog: v0.0.6...v0.0.7