babelfhir-ts 1.6.3 → 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,7 +36,7 @@
36
36
  <a href="https://www.npmjs.com/package/@babelfhir-ts/dicomweb"><img src="https://img.shields.io/npm/v/@babelfhir-ts/dicomweb.svg?label=%40babelfhir-ts%2Fdicomweb" alt="dicomweb"></a>
37
37
  </p>
38
38
 
39
- **BabelFHIR-TS** transforms FHIR® StructureDefinitions into production-ready TypeScript code with full type safety and built-in validation. Unlike generic FHIR type definitions, BabelFHIR-TS generates **profile-aware** interfaces that understand your Implementation Guide's constraints, extensions, and slicing rules.
39
+ **BabelFHIR-TS** transforms FHIR® StructureDefinitions into production-ready TypeScript code with full type safety and built-in validation. BabelFHIR-TS generates **profile-aware** interfaces that understand your Implementation Guide's constraints, extensions, and slicing rules.
40
40
 
41
41
  ### What you get
42
42
 
@@ -48,118 +48,7 @@
48
48
  - **Zero manual mapping**—consume any FHIR package or Implementation Guide directly from registries
49
49
  - **Fast and lightweight**—the CLI pulls no FHIRPath engine of its own; generated packages declare `fhirpath` as a *peer* dependency (`>=4.9.1 <6`), so the host app owns the version
50
50
  - **Type-safe FHIR client** — generated client extends [`@babelfhir-ts/client-r4`](https://www.npmjs.com/package/@babelfhir-ts/client-r4) / [`client-r4b`](https://www.npmjs.com/package/@babelfhir-ts/client-r4b) / [`client-r5`](https://www.npmjs.com/package/@babelfhir-ts/client-r5) with profile-specific methods (e.g., `.uSCorePatientProfile()`, `.pASClaim()`) on top of base resource accessors
51
- - **Install any FHIR profile as a node module**—use `babelfhir-ts install` to add Implementation Guides directly to your project
52
-
53
- <!-- PARITY-BADGES:START - Do not remove or modify this section -->
54
- ## Continuous Validation
55
-
56
- Every push to `develop` and `main` runs the parity pipeline, which validates generated code against real-world FHIR Implementation Guides. (Pull requests run the faster `CI` workflow: typecheck, unit tests, and generated-artifact drift checks.) For each IG, the pipeline:
57
-
58
- 1. Downloads the FHIR package from a registry
59
- 2. Generates TypeScript interfaces, validators, and classes
60
- 3. Compiles the output with `tsc` (zero errors required)
61
- 4. Generates `empty()` and `random()` test resources for every profile
62
- 5. Validates those resources against two independent external FHIR validators
63
-
64
- ### Validated Implementation Guides (31)
65
-
66
- Every parity run validates **31 real-world IGs** (29 R4, 2 R5). The list is not duplicated here — it is generated from the parity suite's own source of truth into [`parity-matrix.json`](./parity-matrix.json).
67
-
68
- Each validated IG is also published as a ready-to-install package — `@max-health-inc/fhir-<name>` — so you do not have to generate it yourself:
69
-
70
- **[→ Browse the FHIR IG registry](https://github.com/orgs/Max-Health-Inc/packages?ecosystem=npm&q=fhir-)**
71
-
72
- ```bash
73
- # GitHub Packages needs the scope mapped, and a token with read:packages
74
- echo "@max-health-inc:registry=https://npm.pkg.github.com" >> .npmrc
75
- npm install @max-health-inc/fhir-us-core
76
- ```
77
-
78
- Published by [Max-Health-Inc/fhir-igs](https://github.com/Max-Health-Inc/fhir-igs), which pins a babelfhir-ts version and republishes an IG only when the IG version, the pinned generator, or the generation flags actually change.
79
-
80
- ### Validation with the Firely SDK Validator
81
-
82
- The `firely` job validates generated resources using the [Firely SDK Validator](https://docs.fire.ly/projects/Firely-NET-SDK/validation.html) (`Firely.Fhir.Validation`, v3.x) running on the Firely .NET SDK (`Hl7.Fhir`, v6.x) — two separately versioned packages. Results are published as live badges:
83
-
84
- <details><summary>Per-IG results</summary>
85
-
86
- ![US Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-us-core.json)
87
- ![QI-Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-qicore.json)
88
- ![mCODE](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-mcode.json)
89
- ![SDOH Clinical Care](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-sdoh.json)
90
- ![NDH (National Directory)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ndh.json)
91
- ![CARIN BB](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-carin-bb.json)
92
- ![CQF Measures](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-cqfmeasures.json)
93
- ![Physical Activity](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-physical-activity.json)
94
- ![DaVinci PAS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-pas.json)
95
- ![DaVinci CDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-cdex.json)
96
- ![DaVinci PDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-pdex.json)
97
- ![DaVinci DTR](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-dtr.json)
98
- ![DaVinci Alerts](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-alerts.json)
99
- ![DaVinci DEQM](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-deqm.json)
100
- ![DaVinci Drug Formulary](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-drug-formulary.json)
101
- ![IPS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ips.json)
102
- ![SMART App Launch](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-smart.json)
103
- ![SDC (Structured Data Capture)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-sdc.json)
104
- ![Genomics Reporting](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-genomics-reporting.json)
105
- ![CPG (Clinical Practice Guidelines)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-cpg.json)
106
- ![ISiK Basis](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-isik-basis.json)
107
- ![KBV eRezept](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-kbv-erp.json)
108
- ![DE Basisprofil](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-de-basisprofil.json)
109
- ![ISiK Medikation](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-isik-medikation.json)
110
- ![CH Core (Switzerland)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ch-core.json)
111
- ![AU Core (Australia)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-au-core.json)
112
- ![PIXm](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-pixm.json)
113
- ![MHD](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-mhd.json)
114
- ![vitals](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-vitals.json)
115
-
116
- </details>
117
-
118
- ### Validation with HL7 Java Validator
119
-
120
- The `hl7` job validates the same artifacts using the [official HL7 FHIR Validator](https://confluence.hl7.org/display/FHIR/Using+the+FHIR+Validator), the reference implementation for FHIR conformance checking:
121
-
122
- <details><summary>Per-IG results</summary>
123
-
124
- ![US Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-us-core.json)
125
- ![QI-Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-qicore.json)
126
- ![mCODE](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-mcode.json)
127
- ![SDOH Clinical Care](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-sdoh.json)
128
- ![NDH (National Directory)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ndh.json)
129
- ![CARIN BB](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-carin-bb.json)
130
- ![CQF Measures](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-cqfmeasures.json)
131
- ![Physical Activity](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-physical-activity.json)
132
- ![DaVinci PAS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-pas.json)
133
- ![DaVinci CDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-cdex.json)
134
- ![DaVinci PDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-pdex.json)
135
- ![DaVinci DTR](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-dtr.json)
136
- ![DaVinci Alerts](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-alerts.json)
137
- ![DaVinci DEQM](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-deqm.json)
138
- ![DaVinci Drug Formulary](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-drug-formulary.json)
139
- ![IPS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ips.json)
140
- ![SMART App Launch](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-smart.json)
141
- ![SDC (Structured Data Capture)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-sdc.json)
142
- ![Genomics Reporting](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-genomics-reporting.json)
143
- ![CPG (Clinical Practice Guidelines)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-cpg.json)
144
- ![ISiK Basis](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-isik-basis.json)
145
- ![KBV eRezept](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-kbv-erp.json)
146
- ![DE Basisprofil](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-de-basisprofil.json)
147
- ![ISiK Medikation](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-isik-medikation.json)
148
- ![CH Core (Switzerland)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ch-core.json)
149
- ![AU Core (Australia)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-au-core.json)
150
- ![PIXm](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-pixm.json)
151
- ![MHD](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-mhd.json)
152
- ![vitals](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-vitals.json)
153
-
154
- </details>
155
-
156
- > External-validator badges cover the 29 R4/R4B IGs. R5 packages are generated and typechecked, but neither external validator publishes R5 badges yet.
157
-
158
- > Terminology validation requires a tx server. The pipeline uses `--tx-server https://tx.fhir.org/{r4|r5}` (matching the package's FHIR version) during generation to expand ValueSets and produce valid codes.
159
-
160
- 📊 **[Full Report](https://max-health-inc.github.io/BabelFHIR-TS/)**
161
- <!-- HL7-PARITY-BADGES:END -->
162
- <!-- PARITY-BADGES:END -->
51
+ - **Install any FHIR profile as a node module**—use `babelfhir-ts install` to add Implementation Guides (FHIR Packages) directly to your project
163
52
 
164
53
  ## Installation
165
54
 
@@ -274,6 +163,117 @@ Full documentation is available at **[max-health-inc.github.io/BabelFHIR-TS/docs
274
163
  - [Limitations](https://max-health-inc.github.io/BabelFHIR-TS/docs/limitations) — edge cases, random() caveats
275
164
  - [Contributing](https://max-health-inc.github.io/BabelFHIR-TS/docs/contributing) — dev setup, scripts, project structure
276
165
 
166
+ <!-- PARITY-BADGES:START - Do not remove or modify this section -->
167
+ ## Continuous Validation
168
+
169
+ Every push to `develop` and `main` runs the parity pipeline, which validates generated code against real-world FHIR Implementation Guides. (Pull requests run the faster `CI` workflow: typecheck, unit tests, and generated-artifact drift checks.) For each IG, the pipeline:
170
+
171
+ 1. Downloads the FHIR package from a registry
172
+ 2. Generates TypeScript interfaces, validators, and classes
173
+ 3. Compiles the output with `tsc` (zero errors required)
174
+ 4. Generates `empty()` and `random()` test resources for every profile
175
+ 5. Validates those resources against two independent external FHIR validators
176
+
177
+ ### Validated Implementation Guides (31)
178
+
179
+ Every parity run validates **31 real-world IGs** (29 R4, 2 R5). The list is not duplicated here — it is generated from the parity suite's own source of truth into [`parity-matrix.json`](./parity-matrix.json).
180
+
181
+ Each validated IG is also published as a ready-to-install package — `@max-health-inc/fhir-<name>` — so you do not have to generate it yourself:
182
+
183
+ **[→ Browse the FHIR IG registry](https://github.com/orgs/Max-Health-Inc/packages?ecosystem=npm&q=fhir-)**
184
+
185
+ ```bash
186
+ # GitHub Packages needs the scope mapped, and a token with read:packages
187
+ echo "@max-health-inc:registry=https://npm.pkg.github.com" >> .npmrc
188
+ npm install @max-health-inc/fhir-us-core
189
+ ```
190
+
191
+ Published by [Max-Health-Inc/fhir-igs](https://github.com/Max-Health-Inc/fhir-igs), which pins a babelfhir-ts version and republishes an IG only when the IG version, the pinned generator, or the generation flags actually change.
192
+
193
+ ### Validation with the Firely SDK Validator
194
+
195
+ The `firely` job validates generated resources using the [Firely SDK Validator](https://docs.fire.ly/projects/Firely-NET-SDK/validation.html) (`Firely.Fhir.Validation`, v3.x) running on the Firely .NET SDK (`Hl7.Fhir`, v6.x) — two separately versioned packages. Results are published as live badges:
196
+
197
+ <details><summary>Per-IG results</summary>
198
+
199
+ ![US Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-us-core.json)
200
+ ![QI-Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-qicore.json)
201
+ ![mCODE](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-mcode.json)
202
+ ![SDOH Clinical Care](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-sdoh.json)
203
+ ![NDH (National Directory)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ndh.json)
204
+ ![CARIN BB](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-carin-bb.json)
205
+ ![CQF Measures](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-cqfmeasures.json)
206
+ ![Physical Activity](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-physical-activity.json)
207
+ ![DaVinci PAS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-pas.json)
208
+ ![DaVinci CDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-cdex.json)
209
+ ![DaVinci PDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-pdex.json)
210
+ ![DaVinci DTR](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-dtr.json)
211
+ ![DaVinci Alerts](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-alerts.json)
212
+ ![DaVinci DEQM](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-deqm.json)
213
+ ![DaVinci Drug Formulary](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-drug-formulary.json)
214
+ ![IPS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ips.json)
215
+ ![SMART App Launch](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-smart.json)
216
+ ![SDC (Structured Data Capture)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-sdc.json)
217
+ ![Genomics Reporting](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-genomics-reporting.json)
218
+ ![CPG (Clinical Practice Guidelines)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-cpg.json)
219
+ ![ISiK Basis](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-isik-basis.json)
220
+ ![KBV eRezept](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-kbv-erp.json)
221
+ ![DE Basisprofil](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-de-basisprofil.json)
222
+ ![ISiK Medikation](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-isik-medikation.json)
223
+ ![CH Core (Switzerland)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ch-core.json)
224
+ ![AU Core (Australia)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-au-core.json)
225
+ ![PIXm](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-pixm.json)
226
+ ![MHD](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-mhd.json)
227
+ ![vitals](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-vitals.json)
228
+
229
+ </details>
230
+
231
+ ### Validation with HL7 Java Validator
232
+
233
+ The `hl7` job validates the same artifacts using the [official HL7 FHIR Validator](https://confluence.hl7.org/display/FHIR/Using+the+FHIR+Validator), the reference implementation for FHIR conformance checking:
234
+
235
+ <details><summary>Per-IG results</summary>
236
+
237
+ ![US Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-us-core.json)
238
+ ![QI-Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-qicore.json)
239
+ ![mCODE](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-mcode.json)
240
+ ![SDOH Clinical Care](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-sdoh.json)
241
+ ![NDH (National Directory)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ndh.json)
242
+ ![CARIN BB](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-carin-bb.json)
243
+ ![CQF Measures](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-cqfmeasures.json)
244
+ ![Physical Activity](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-physical-activity.json)
245
+ ![DaVinci PAS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-pas.json)
246
+ ![DaVinci CDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-cdex.json)
247
+ ![DaVinci PDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-pdex.json)
248
+ ![DaVinci DTR](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-dtr.json)
249
+ ![DaVinci Alerts](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-alerts.json)
250
+ ![DaVinci DEQM](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-deqm.json)
251
+ ![DaVinci Drug Formulary](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-drug-formulary.json)
252
+ ![IPS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ips.json)
253
+ ![SMART App Launch](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-smart.json)
254
+ ![SDC (Structured Data Capture)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-sdc.json)
255
+ ![Genomics Reporting](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-genomics-reporting.json)
256
+ ![CPG (Clinical Practice Guidelines)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-cpg.json)
257
+ ![ISiK Basis](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-isik-basis.json)
258
+ ![KBV eRezept](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-kbv-erp.json)
259
+ ![DE Basisprofil](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-de-basisprofil.json)
260
+ ![ISiK Medikation](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-isik-medikation.json)
261
+ ![CH Core (Switzerland)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ch-core.json)
262
+ ![AU Core (Australia)](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-au-core.json)
263
+ ![PIXm](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-pixm.json)
264
+ ![MHD](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-mhd.json)
265
+ ![vitals](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-vitals.json)
266
+
267
+ </details>
268
+
269
+ > External-validator badges cover the 29 R4/R4B IGs. R5 packages are generated and typechecked, but neither external validator publishes R5 badges yet.
270
+
271
+ > Terminology validation requires a tx server. The pipeline uses `--tx-server https://tx.fhir.org/{r4|r5}` (matching the package's FHIR version) during generation to expand ValueSets and produce valid codes.
272
+
273
+ 📊 **[Full Report](https://max-health-inc.github.io/BabelFHIR-TS/)**
274
+ <!-- HL7-PARITY-BADGES:END -->
275
+ <!-- PARITY-BADGES:END -->
276
+
277
277
  ## License
278
278
 
279
279
  ISC © Maximilian Nussbaumer
@@ -5,7 +5,7 @@ import { primitivePlaceholder, generateCodeDefault, makeCodeableConcept, chooseC
5
5
  import { generateSliceElement, buildNestedRequirementsObject } from './sliceElementGenerator.js';
6
6
  import { COMPLEX_SKELETON_MAP, propKey, buildValueExpression, buildCrossReferencedEntryArray, } from './classGeneratorHelpers.js';
7
7
  import { renderClassTemplate } from './classTemplate.js';
8
- export function generateClass(className, interfaceName, baseResource, requiredFields = [], profileUrl, fieldPatterns = [], forbiddenFields = [], valueSetBindings = {}, fieldOrder = [], codeableConceptBindings = []) {
8
+ export function generateClass(className, interfaceName, baseResource, requiredFields = [], profileUrl, fieldPatterns = [], forbiddenFields = [], valueSetBindings = {}, fieldOrder = [], codeableConceptBindings = [], hasValueSetRegistry = false) {
9
9
  // Decide whether to emit resourceType. If baseResource points at a known resource or ends with 'Resource'.
10
10
  const CORE_RESOURCE_BASES = ctx().coreResourceBases;
11
11
  const addResourceType = !!baseResource && CORE_RESOURCE_BASES.has(baseResource);
@@ -578,6 +578,6 @@ export function generateClass(className, interfaceName, baseResource, requiredFi
578
578
  profileUrl, constructorMetaProfile, setterMetaProfile,
579
579
  randomMetaProfileInit, resourceTypeLine, baseResource,
580
580
  fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder,
581
- codeableConceptBindings,
581
+ codeableConceptBindings, hasValueSetRegistry,
582
582
  });
583
583
  }
@@ -93,12 +93,13 @@ export function buildCrossReferencedEntryArray(sliceElements) {
93
93
  return `(() => { ${decls.join(' ')} return [${rewritten.join(', ')}]; })()`;
94
94
  }
95
95
  /** Generate the static pattern/forbidden/order/binding metadata properties for a class. */
96
- export function generatePatternMetadata(fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder = [], codeableConceptBindings = []) {
96
+ export function generatePatternMetadata(fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder = [], codeableConceptBindings = [],
97
+ /** Whether the class file imports `getRandomConceptByUrl` — see renderClassTemplate. */
98
+ emitCodeResolver = false) {
97
99
  const patternMap = {};
98
100
  for (const fp of fieldPatterns) {
99
101
  patternMap[fp.fieldName] = fp.pattern;
100
102
  }
101
- const hasBindings = Object.keys(valueSetBindings).length > 0;
102
103
  return `
103
104
  /**
104
105
  * Pattern constraints this profile fixes on its fields, keyed by field path
@@ -127,16 +128,10 @@ export function generatePatternMetadata(fieldPatterns, forbiddenFields, valueSet
127
128
  */
128
129
  protected static readonly _codeableConceptBindings: string[] = ${JSON.stringify(codeableConceptBindings)};
129
130
 
130
- /** Code resolver for ValueSet bindings - returns a random valid code from a ValueSet by URL */
131
- protected static readonly _codeResolver: ((url: string) => { code: string; system: string; display?: string } | undefined) | undefined = ${hasBindings ? `(() => {
132
- // Try to load the ValueSetRegistry - it may not exist if no ValueSets were generated
133
- try {
134
- const registry = __require('./valuesets/index.js') as Record<string, unknown>;
135
- if (registry && typeof registry.getRandomConceptByUrl === 'function') {
136
- return registry.getRandomConceptByUrl as (url: string) => { code: string; system: string; display?: string } | undefined;
137
- }
138
- } catch { /* ValueSetRegistry not available */ }
139
- return undefined;
140
- })()` : 'undefined'};
131
+ /**
132
+ * Random-example code resolver for ValueSet bindings. \`undefined\` when this package emitted no
133
+ * ValueSet registry; enrichResource and resolveSliceCode both fall back to a placeholder.
134
+ */
135
+ protected static readonly _codeResolver: ((url: string) => { code: string; system: string; display?: string } | undefined) | undefined = ${emitCodeResolver ? 'getRandomConceptByUrl' : 'undefined'};
141
136
  `;
142
137
  }
@@ -1,7 +1,7 @@
1
1
  import { COMPLEX_SKELETON_MAP, generatePatternMetadata } from './classGeneratorHelpers.js';
2
2
  /** Render the final class file content from pre-computed template parameters. */
3
3
  export function renderClassTemplate(params) {
4
- const { interfaceName, className, requiredInitBlock, enableMetaProfile, profileUrl, constructorMetaProfile, setterMetaProfile, randomMetaProfileInit, resourceTypeLine, baseResource, fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings, } = params;
4
+ const { interfaceName, className, requiredInitBlock, enableMetaProfile, profileUrl, constructorMetaProfile, setterMetaProfile, randomMetaProfileInit, resourceTypeLine, baseResource, fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings, hasValueSetRegistry, } = params;
5
5
  // Determine which skeleton helpers are actually used in requiredInitBlock
6
6
  const usedSkeletons = new Set();
7
7
  for (const helper of Object.values(COMPLEX_SKELETON_MAP)) {
@@ -24,14 +24,17 @@ export function renderClassTemplate(params) {
24
24
  helperImports.add(helper);
25
25
  }
26
26
  const helperImportList = Array.from(helperImports).join(', ');
27
- const hasVsBindings = Object.keys(valueSetBindings).length > 0;
27
+ // Both halves needed: bindings can all point at ValueSets this package does not emit, and a
28
+ // registry with no bindings is dead weight.
29
+ const emitCodeResolver = Object.keys(valueSetBindings).length > 0 && hasValueSetRegistry;
28
30
  return `
29
31
  import { validate${interfaceName}, type ${interfaceName} } from "./${interfaceName}.js";
30
32
  import type { ValidatorOptions } from "./ValidatorOptions.js";
31
33
  // Only import helpers actually referenced below (dynamic based on required fields)
32
34
  import { ${helperImportList} } from "./random/index.js";
33
- ${hasVsBindings ? `import { createRequire } from 'module';
34
- const __require = createRequire(import.meta.url);` : ''}
35
+ ${emitCodeResolver ? `// Static on purpose: a Node-only runtime require here dies at module init under any bundler
36
+ // that strips module metadata, which kept this package off Workers and Deno.
37
+ import { getRandomConceptByUrl } from "./valuesets/index.js";` : ''}
35
38
 
36
39
  // Helper emitted only when meta.profile enforcement is applicable (resource profiles)
37
40
  ${enableMetaProfile ? `type WithMeta = { meta?: { profile?: string[] } };
@@ -54,7 +57,7 @@ function safeClone<T>(value: T): T {
54
57
  }
55
58
 
56
59
  export class ${className} {
57
- ${generatePatternMetadata(fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings)}
60
+ ${generatePatternMetadata(fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings, emitCodeResolver)}
58
61
  private resource: ${interfaceName};
59
62
 
60
63
  // Declared and assigned rather than written as a parameter property, which
@@ -128,33 +128,41 @@ function resolveGeneratorTypeRoots() {
128
128
  }
129
129
  return [];
130
130
  }
131
+ /**
132
+ * The tsconfig generated output is compiled with.
133
+ *
134
+ * `types: []` is load-bearing and pairs with the emitters: generated code imports no node
135
+ * builtins, so naming a type package here is a promise to ship one. `['node']` was that promise,
136
+ * kept by writing an @types/node stub into the output; both go together or neither does.
137
+ */
138
+ export function buildOutputTsconfig() {
139
+ return {
140
+ compilerOptions: {
141
+ target: 'ES2020',
142
+ module: 'ESNext',
143
+ moduleResolution: 'Bundler',
144
+ declaration: true,
145
+ outDir: '.',
146
+ rootDir: '.',
147
+ skipLibCheck: true,
148
+ esModuleInterop: true,
149
+ allowSyntheticDefaultImports: true,
150
+ strict: true,
151
+ resolveJsonModule: true,
152
+ // Relative to the output dir; the generator's own @types is appended absolute so
153
+ // `@types/fhir` resolves even when the output's deps were skipped.
154
+ typeRoots: ['./node_modules/@types', ...resolveGeneratorTypeRoots()],
155
+ types: []
156
+ },
157
+ include: ['./**/*.ts'],
158
+ exclude: ['node_modules']
159
+ };
160
+ }
131
161
  /** Compile TypeScript files to JavaScript with declaration files */
132
162
  async function compileTypeScriptToJS(dir) {
133
163
  return new Promise((resolve, reject) => {
134
164
  const tscCmd = process.platform === 'win32' ? 'tsc.cmd' : 'tsc';
135
- // Create a temporary tsconfig.json for compilation
136
- // Paths are relative to tsconfig location (which is `dir` itself); the
137
- // generator's own @types (absolute) is appended so `@types/fhir` resolves
138
- // even when the output's deps were skipped (see resolveGeneratorTypeRoots).
139
- const tsconfig = {
140
- compilerOptions: {
141
- target: 'ES2020',
142
- module: 'ESNext',
143
- moduleResolution: 'Bundler',
144
- declaration: true,
145
- outDir: '.',
146
- rootDir: '.',
147
- skipLibCheck: true,
148
- esModuleInterop: true,
149
- allowSyntheticDefaultImports: true,
150
- strict: true,
151
- resolveJsonModule: true,
152
- typeRoots: ['./node_modules/@types', ...resolveGeneratorTypeRoots()],
153
- types: ['node']
154
- },
155
- include: ['./**/*.ts'],
156
- exclude: ['node_modules']
157
- };
165
+ const tsconfig = buildOutputTsconfig();
158
166
  const tsconfigPath = path.join(dir, 'tsconfig.temp.json');
159
167
  fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
160
168
  // shell required on Windows for .cmd wrappers; disabled on Unix to prevent injection
@@ -611,11 +619,6 @@ export async function generateIntoPackage(packageArchivePath, outArchivePath, fl
611
619
  // Install fhirpath type stub so tsc can resolve validator imports
612
620
  const { installFhirpathStub, removeFhirpathStub } = await import('./emitters/validator/fhirpathStubInstaller.js');
613
621
  installFhirpathStub(outputDir);
614
- // Install minimal @types/node stub so tsc can resolve `import { createRequire } from 'module'`
615
- const nodeTypesDir = path.join(outputDir, 'node_modules', '@types', 'node');
616
- fs.mkdirSync(nodeTypesDir, { recursive: true });
617
- fs.writeFileSync(path.join(nodeTypesDir, 'index.d.ts'), `declare module 'module' {\n export function createRequire(filename: string | URL): NodeRequire;\n}\n`);
618
- fs.writeFileSync(path.join(nodeTypesDir, 'package.json'), JSON.stringify({ name: '@types/node', version: '0.0.0-stub', types: 'index.d.ts' }));
619
622
  // Compile TypeScript to JavaScript
620
623
  endPhase = startPhase('compile');
621
624
  logger.log('Compiling TypeScript to JavaScript...');
@@ -623,11 +626,6 @@ export async function generateIntoPackage(packageArchivePath, outArchivePath, fl
623
626
  endPhase(); // compile
624
627
  // Remove fhirpath stub — the real package is a peer dependency
625
628
  removeFhirpathStub(outputDir);
626
- // Remove @types/node stub — only needed for compilation
627
- try {
628
- fs.rmSync(path.join(outputDir, 'node_modules', '@types'), { recursive: true, force: true });
629
- }
630
- catch { /* ignore */ }
631
629
  // Remove base client type stubs — they were only needed for tsc to resolve
632
630
  // @babelfhir-ts/client-<version> imports during compilation. The real package is
633
631
  // installed by the consumer via npm.
@@ -843,19 +841,11 @@ export async function generateIntoPackageDirect(packageArchivePath, flags) {
843
841
  }
844
842
  const { installFhirpathStub, removeFhirpathStub } = await import('./emitters/validator/fhirpathStubInstaller.js');
845
843
  installFhirpathStub(outputDir);
846
- const nodeTypesDir = path.join(outputDir, 'node_modules', '@types', 'node');
847
- fs.mkdirSync(nodeTypesDir, { recursive: true });
848
- fs.writeFileSync(path.join(nodeTypesDir, 'index.d.ts'), `declare module 'module' {\n export function createRequire(filename: string | URL): NodeRequire;\n}\n`);
849
- fs.writeFileSync(path.join(nodeTypesDir, 'package.json'), JSON.stringify({ name: '@types/node', version: '0.0.0-stub', types: 'index.d.ts' }));
850
844
  endPhase = startPhase('compile');
851
845
  logger.log('Compiling TypeScript to JavaScript...');
852
846
  await compileTypeScriptToJS(outputDir);
853
847
  endPhase(); // compile
854
848
  removeFhirpathStub(outputDir);
855
- try {
856
- fs.rmSync(path.join(outputDir, 'node_modules', '@types'), { recursive: true, force: true });
857
- }
858
- catch { /* ignore */ }
859
849
  const babelfhirDir = path.join(outputDir, 'node_modules', '@babelfhir-ts');
860
850
  if (fs.existsSync(babelfhirDir)) {
861
851
  for (const entry of fs.readdirSync(babelfhirDir)) {
@@ -6,6 +6,7 @@
6
6
  * Helpers and types live in sdProcessorHelpers.ts.
7
7
  * Required-field dedup lives in sdProcessorRequiredFields.ts.
8
8
  */
9
+ import fs from 'fs';
9
10
  import path from 'path';
10
11
  import { generateClass } from './emitters/class/classGenerator.js';
11
12
  import { generateInterfaces } from './emitters/interface/interfaceGenerator.js';
@@ -733,7 +734,10 @@ export async function processStructureDefinition(sd, ctx) {
733
734
  }
734
735
  // ── Emit artifacts ───────────────────────────────────────────────
735
736
  const { fieldPatterns, forbiddenFields, valueSetBindings, codeableConceptBindings, fieldOrder } = await extractFieldPatternsAndMetadata([parsed.newFields || [], aligned.alignedNewFields || [], parsed.oldFields || []], baseResource, sd, requiredFields, candidateRequiredFields, nestedRequirementsMap, resolvedProfilePatterns);
736
- const classContent = generateClass(`${interfaceName}Class`, interfaceName, baseResource, requiredFields, sd.url, fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings);
737
+ // Read off disk, not threaded through ctx: emitValueSetFiles has already run by now, and ten
738
+ // call sites would otherwise carry a flag most of them always pass false.
739
+ const hasValueSetRegistry = fs.existsSync(path.join(outputDir, 'valuesets', 'index.ts'));
740
+ const classContent = generateClass(`${interfaceName}Class`, interfaceName, baseResource, requiredFields, sd.url, fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings, hasValueSetRegistry);
737
741
  ensureRandomSupportFile(outputDir);
738
742
  ensureValidatorOptionsFile(outputDir);
739
743
  writeInterfaceAndValidatorToFile(outputDir, interfaceName, finalInterfaceContent, validateFn);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babelfhir-ts",
3
- "version": "1.6.3",
3
+ "version": "1.6.5",
4
4
  "description": "BabelFHIR-TS: generate TypeScript interfaces, validators, and helper classes from FHIR R4/R4B/R5 StructureDefinitions (profiles) directly inside package archives.",
5
5
  "type": "module",
6
6
  "main": "out/src/main.js",