@atomic-ehr/codegen 0.0.7 → 0.0.8-canary.20260304203134.178662b
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 +63 -92
- package/assets/api/writer-generator/python/fhirpy_base_model.py +12 -9
- package/assets/api/writer-generator/python/fhirpy_base_model_camel_case.py +23 -0
- package/dist/cli/index.js +7 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2811 -2379
- package/dist/index.js.map +1 -1
- package/package.json +10 -6
package/README.md
CHANGED
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
- [Generation](#generation)
|
|
24
24
|
- [1. Writer-Based Generation (Programmatic)](#1-writer-based-generation-programmatic)
|
|
25
25
|
- [2. Mustache Template-Based Generation (Declarative)](#2-mustache-template-based-generation-declarative)
|
|
26
|
-
- [Roadmap](#roadmap)
|
|
27
26
|
- [Support](#support)
|
|
28
27
|
- [Footnotes](#footnotes)
|
|
29
28
|
|
|
@@ -41,14 +40,32 @@ Guides:
|
|
|
41
40
|
|
|
42
41
|
## Features
|
|
43
42
|
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
43
|
+
- [x] **Multi-Package Support** — Load packages from the [FHIR registry](examples/typescript-r4/), [remote TGZ files](examples/typescript-sql-on-fhir/), or a [local folder with custom StructureDefinitions](examples/local-package-folder/)
|
|
44
|
+
- Tested with hl7.fhir.r4.core, US Core, C-CDA, SQL on FHIR, etc.
|
|
45
|
+
- [x] **Resources & Complex Types** — Generates typed definitions with proper inheritance
|
|
46
|
+
- [x] **Value Set Bindings** — Strongly-typed enums from FHIR terminology bindings
|
|
47
|
+
- [x] **Profiles & Extensions** — Factory methods with auto-populated fixed values and required slices ([R4 profiles](examples/typescript-r4/profile-bp.test.ts), [US Core](examples/typescript-us-core/))
|
|
48
|
+
- Extensions — flat typed accessors (e.g. `setRace()` on US Core Patient), [standalone extension profiles](examples/typescript-r4/extension-profile.test.ts)
|
|
49
|
+
- Slicing — typed get/set accessors with discriminator matching
|
|
50
|
+
- Validation — runtime `validate()` for required fields, fixed values, slice cardinality, enums, references
|
|
51
|
+
- [x] **Extensible Architecture** — Three-stage pipeline: FHIR packages → [TypeSchema](https://www.health-samurai.io/articles/type-schema-a-pragmatic-approach-to-build-fhir-sdk) IR → code generation
|
|
52
|
+
- TypeSchema is a universal intermediate representation — add a new language by writing only the final generation stage
|
|
53
|
+
- Built-in generators: TypeScript, Python/Pydantic, C#, and Mustache templates
|
|
54
|
+
- [x] **TypeSchema Transformations**:
|
|
55
|
+
- [x] Tree Shaking — include only the resources and fields you need; automatically resolves dependencies
|
|
56
|
+
- [x] Logical Model Promotion — promote FHIR logical models (e.g. CDA ClinicalDocument) to first-class resources
|
|
57
|
+
- [ ] Renaming — custom naming conventions for generated types, fields, packages, etc.
|
|
58
|
+
- [ ] **Search Builders** — type-safe FHIR search query construction
|
|
59
|
+
- [ ] **Operation Generation** — type-safe FHIR operation calls
|
|
60
|
+
|
|
61
|
+
| Feature | TypeSchema | TypeScript | Python | C# | Mustache |
|
|
62
|
+
|---|---|---|---|---|---|
|
|
63
|
+
| Resources & Complex Types | yes | yes | yes | yes | template |
|
|
64
|
+
| Value Set Bindings | yes | inline | inline | enum | template |
|
|
65
|
+
| Profiles & Extensions | yes | yes | no | no | no |
|
|
66
|
+
| Tree Shaking | yes | 〃 | 〃 | 〃 | 〃 |
|
|
67
|
+
| Logical Model Promotion | yes | 〃 | 〃 | 〃 | 〃 |
|
|
68
|
+
|
|
52
69
|
|
|
53
70
|
## Versions & Release Cycle
|
|
54
71
|
|
|
@@ -298,107 +315,61 @@ Templates enable flexible code generation for any language or format (Go, Rust,
|
|
|
298
315
|
|
|
299
316
|
### Profile Classes
|
|
300
317
|
|
|
301
|
-
When generating TypeScript with `generateProfile: true`, the generator creates profile wrapper classes that provide a fluent API for working with FHIR profiles
|
|
318
|
+
When generating TypeScript with `generateProfile: true`, the generator creates profile wrapper classes that provide a fluent API for working with FHIR profiles. These classes handle complex profile constraints like slicing and extensions automatically.
|
|
302
319
|
|
|
303
320
|
```typescript
|
|
304
|
-
import {
|
|
305
|
-
import { USCorePatientProfileProfile } from "./fhir-types/hl7-fhir-us-core/profiles/UscorePatientProfile";
|
|
306
|
-
|
|
307
|
-
// Wrap a FHIR resource with a profile class
|
|
308
|
-
const resource: Patient = { resourceType: "Patient" };
|
|
309
|
-
const profile = new USCorePatientProfileProfile(resource);
|
|
321
|
+
import { observation_bpProfile as bpProfile } from "./profiles/Observation_observation_bp";
|
|
310
322
|
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
323
|
+
// create() auto-sets fixed values (code, meta.profile) and required slice stubs
|
|
324
|
+
const bp = bpProfile.create({
|
|
325
|
+
status: "final",
|
|
326
|
+
subject: { reference: "Patient/pt-1" },
|
|
315
327
|
});
|
|
316
328
|
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
329
|
+
// Slice setters — discriminator values (LOINC codes) applied automatically
|
|
330
|
+
// Single-variant choice types (value[x] → valueQuantity) are flattened:
|
|
331
|
+
bp.setVSCat({ text: "Vital Signs" })
|
|
332
|
+
.setSystolicBP({ value: 120, unit: "mmHg" })
|
|
333
|
+
.setDiastolicBP({ value: 80, unit: "mmHg" })
|
|
334
|
+
.setEffectiveDateTime("2024-06-15");
|
|
323
335
|
|
|
324
|
-
//
|
|
325
|
-
const raceExtension = profile.getRaceExtension();
|
|
326
|
-
console.log(raceExtension?.url); // "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race"
|
|
336
|
+
bp.validate(); // [] — valid
|
|
327
337
|
|
|
328
|
-
// Get
|
|
329
|
-
const
|
|
338
|
+
// Get plain FHIR JSON — ready for API calls, storage, etc.
|
|
339
|
+
const obs = bp.toResource();
|
|
340
|
+
// obs.component[0].valueQuantity.value === 120
|
|
341
|
+
// obs.component[0].code.coding[0].code === "8480-6"
|
|
330
342
|
```
|
|
331
343
|
|
|
332
|
-
**Slicing
|
|
333
|
-
|
|
334
|
-
Profile classes also handle FHIR slicing, automatically applying discriminator values:
|
|
344
|
+
**Slicing & Choice Type Flattening:**
|
|
335
345
|
|
|
336
346
|
```typescript
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const obs: Observation = { resourceType: "Observation", status: "final", code: {} };
|
|
341
|
-
const bp = new USCoreBloodPressureProfileProfile(obs);
|
|
347
|
+
// Simplified getter — discriminator stripped, choice type flattened
|
|
348
|
+
bp.getSystolicBP(); // { value: 120, unit: "mmHg" }
|
|
342
349
|
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
bp.setSystolic({ valueQuantity: { value: 120, unit: "mmHg" } });
|
|
346
|
-
bp.setDiastolic({ valueQuantity: { value: 80, unit: "mmHg" } });
|
|
347
|
-
|
|
348
|
-
// Get simplified slice (without discriminator fields)
|
|
349
|
-
const systolic = bp.getSystolic();
|
|
350
|
-
console.log(systolic?.valueQuantity?.value); // 120
|
|
351
|
-
|
|
352
|
-
// Get raw slice (includes discriminator)
|
|
353
|
-
const systolicRaw = bp.getSystolicRaw();
|
|
354
|
-
console.log(systolicRaw?.code?.coding?.[0]?.code); // "8480-6" (LOINC code for systolic BP)
|
|
350
|
+
// Raw getter — full FHIR element including discriminator values
|
|
351
|
+
bp.getSystolicBPRaw(); // { code: { coding: [...] }, valueQuantity: { value: 120, ... } }
|
|
355
352
|
```
|
|
356
353
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
## Roadmap
|
|
360
|
-
|
|
361
|
-
- [x] TypeScript generation
|
|
362
|
-
- [x] FHIR R4 core package support
|
|
363
|
-
- [x] Configuration file support
|
|
364
|
-
- [x] Comprehensive test suite (72+ tests)
|
|
365
|
-
- [x] **Value Set Generation** - Strongly-typed enums from FHIR bindings
|
|
366
|
-
- [x] **Profile & Extension Support** - Basic parsing (US Core in development)
|
|
367
|
-
- [ ] **Complete Multi-Package Support** - Custom packages and dependencies
|
|
368
|
-
- [ ] **Smart Chained Search** - Intelligent search builders
|
|
354
|
+
**Wrapping Existing Resources:**
|
|
369
355
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
.include('Patient:organization')
|
|
378
|
-
.sort('birthdate', 'desc')
|
|
379
|
-
.execute();
|
|
380
|
-
```
|
|
356
|
+
```typescript
|
|
357
|
+
// Wrap any resource to read slices
|
|
358
|
+
const bp2 = bpProfile.from(existingObservation);
|
|
359
|
+
bp2.getSystolicBP(); // { value: 120, unit: "mmHg" }
|
|
360
|
+
bp2.getVSCat(); // { text: "Vital Signs" }
|
|
361
|
+
bp2.getEffectiveDateTime(); // "2024-06-15"
|
|
362
|
+
```
|
|
381
363
|
|
|
382
|
-
|
|
364
|
+
**Validation:**
|
|
383
365
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
resource: patient,
|
|
390
|
-
onlyCertainMatches: true
|
|
391
|
-
})
|
|
392
|
-
.execute();
|
|
393
|
-
```
|
|
366
|
+
```typescript
|
|
367
|
+
const errors = bp.validate();
|
|
368
|
+
// [] — empty means valid
|
|
369
|
+
// ["effective: at least one of effectiveDateTime, effectivePeriod is required"]
|
|
370
|
+
```
|
|
394
371
|
|
|
395
|
-
- [
|
|
396
|
-
- [x] **C# generation**
|
|
397
|
-
- [ ] **Rust generation**
|
|
398
|
-
- [ ] **GraphQL schema generation**
|
|
399
|
-
- [ ] **OpenAPI specification generation**
|
|
400
|
-
- [ ] **Validation functions**
|
|
401
|
-
- [ ] **Mock data generation**
|
|
372
|
+
See [examples/typescript-r4/](examples/typescript-r4/) for R4 profile tests and [examples/typescript-us-core/](examples/typescript-us-core/) for US Core profile examples.
|
|
402
373
|
|
|
403
374
|
## Support
|
|
404
375
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Union, Optional, Iterator, Tuple, Dict
|
|
1
|
+
from typing import Any, ClassVar, Type, Union, Optional, Iterator, Tuple, Dict
|
|
2
2
|
from pydantic import BaseModel, Field
|
|
3
3
|
from typing import Protocol
|
|
4
4
|
|
|
@@ -8,20 +8,23 @@ class ResourceProtocol(Protocol):
|
|
|
8
8
|
id: Union[str, None]
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
class ResourceTypeDescriptor:
|
|
12
|
+
def __get__(self, instance: Optional[BaseModel], owner: Type[BaseModel]) -> str:
|
|
13
|
+
field = owner.model_fields.get("resource_type")
|
|
14
|
+
if field is None:
|
|
15
|
+
raise ValueError("resource_type field not found")
|
|
16
|
+
if field.default is None:
|
|
17
|
+
raise ValueError("resource_type field default value is not set")
|
|
18
|
+
return str(field.default)
|
|
19
|
+
|
|
20
|
+
|
|
11
21
|
class FhirpyBaseModel(BaseModel):
|
|
12
22
|
"""
|
|
13
23
|
This class satisfies ResourceProtocol
|
|
14
24
|
"""
|
|
15
|
-
resource_type: str = Field(alias="resourceType")
|
|
16
25
|
id: Optional[str] = Field(None, alias="id")
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
def resourceType(self) -> str:
|
|
20
|
-
return self.resource_type
|
|
21
|
-
|
|
22
|
-
@resourceType.setter
|
|
23
|
-
def resourceType(self, value: str) -> None:
|
|
24
|
-
self.resource_type = value
|
|
27
|
+
resourceType: ClassVar[ResourceTypeDescriptor] = ResourceTypeDescriptor()
|
|
25
28
|
|
|
26
29
|
def __iter__(self) -> Iterator[Tuple[str, Any]]: # type: ignore[override]
|
|
27
30
|
data = self.model_dump(mode='json', by_alias=True, exclude_none=True)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any, Union, Optional, Iterator, Tuple, Dict
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ResourceProtocol(Protocol):
|
|
7
|
+
resourceType: Any
|
|
8
|
+
id: Union[str, None]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FhirpyBaseModel(BaseModel):
|
|
12
|
+
"""
|
|
13
|
+
This class satisfies ResourceProtocol
|
|
14
|
+
"""
|
|
15
|
+
id: Optional[str] = Field(None, alias="id")
|
|
16
|
+
|
|
17
|
+
def __iter__(self) -> Iterator[Tuple[str, Any]]: # type: ignore[override]
|
|
18
|
+
data = self.model_dump(mode='json', by_alias=True, exclude_none=True)
|
|
19
|
+
return iter(data.items())
|
|
20
|
+
|
|
21
|
+
def serialize(self) -> Dict[str, Any]:
|
|
22
|
+
"""Serialize to dict (compatible with fhirpy's serialize method)"""
|
|
23
|
+
return self.model_dump(mode='json', by_alias=True, exclude_none=True)
|
package/dist/cli/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import x from'picocolors';import et from'yargs';import {hideBin}from'yargs/helpers';import {mkdir,writeFile}from'fs/promises';import {dirname}from'path';import {createHash}from'crypto';import Te from'assert';import {CanonicalManager}from'@atomic-ehr/fhir-canonical-manager';import*as ge from'@atomic-ehr/fhirschema';import {isStructureDefinition}from'@atomic-ehr/fhirschema';var D=class e{options;dryWarnSet=new Set;constructor(t={}){this.options={timestamp:false,level:1,...t};}shouldLog(t){let o=this.options.level??1;return t>=o}static consoleLevelsMap={1:console.log,2:console.warn,3:console.error,0:console.log,4:()=>{}};formatMessage(t,o,i){let n=this.options.timestamp?`${x.gray(new Date().toLocaleTimeString())} `:"",r=this.options.prefix?`${x.cyan(`[${this.options.prefix}]`)} `:"";return `${n}${i(t)} ${r}${o}`}isSuppressed(t){return this.options.suppressLoggingLevel==="all"||this.options.suppressLoggingLevel?.includes(t)||false}tryWriteToConsole(t,o){if(this.isSuppressed(t)||!this.shouldLog(t))return;(e.consoleLevelsMap[t]||console.log)(o);}success(t){this.tryWriteToConsole(1,this.formatMessage("",t,x.green));}error(t,o){if(this.isSuppressed(3)||!this.shouldLog(3))return;console.error(this.formatMessage("X",t,x.red));let i=this.options.level===0;o&&i&&(console.error(x.red(` ${o.message}`)),o.stack&&console.error(x.gray(o.stack)));}warn(t){this.tryWriteToConsole(2,this.formatMessage("!",t,x.yellow));}dryWarn(t){this.dryWarnSet.has(t)||(this.warn(t),this.dryWarnSet.add(t));}info(t){this.tryWriteToConsole(1,this.formatMessage("i",t,x.blue));}debug(t){this.shouldLog(0)&&this.tryWriteToConsole(0,this.formatMessage("\u{1F41B}",t,x.magenta));}step(t){this.tryWriteToConsole(1,this.formatMessage("\u{1F680}",t,x.cyan));}progress(t){this.tryWriteToConsole(1,this.formatMessage("\u23F3",t,x.blue));}plain(t,o=i=>i){let i=this.options.timestamp?`${x.gray(new Date().toLocaleTimeString())} `:"",n=this.options.prefix?`${x.cyan(`[${this.options.prefix}]`)} `:"";this.tryWriteToConsole(1,`${i}${n}${o(t)}`);}dim(t){this.plain(t,x.gray);}child(t){return new e({...this.options,prefix:this.options.prefix?`${this.options.prefix}:${t}`:t})}configure(t){this.options={...this.options,...t};}getLevel(){return this.options.level??1}setLevel(t){this.options.level=t;}},v=new D;function Ce(e){v.success(e);}function k(e,t){v.error(e,t);}function V(e){v.info(e);}function ke(e){v.dim(e);}function K(e){v.configure(e);}function J(e={}){return new D(e)}function Q(e){console.log(),console.log(x.cyan(x.bold(`\u2501\u2501\u2501 ${e} \u2501\u2501\u2501`)));}function X(e,t,o){let i=e;t&&(i+=` ${x.gray(`(${t}ms)`)}`),Ce(i),o&&Object.entries(o).forEach(([n,r])=>{ke(` ${n}: ${r}`);});}function b(e,t="\u2022"){e.forEach(o=>{console.log(x.gray(` ${t} ${o}`));});}var F="Use CodeableReference which is not provided by FHIR R4.",be="Use Availability which is not provided by FHIR R4.",O={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":be,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":F,"http://hl7.org/fhir/StructureDefinition/specimen-additive":F,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":F,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":F,"http://hl7.org/fhir/StructureDefinition/workflow-reason":F},"hl7.fhir.r5.core#5.0.0":{"http://hl7.org/fhir/StructureDefinition/shareablecodesystem":"FIXME: CodeSystem.concept.concept defined by ElementReference. FHIR Schema generator output broken value in it, so we just skip it for now.","http://hl7.org/fhir/StructureDefinition/publishablecodesystem":"Uses R5-only base types not available in R4 generation."}};function I(e,t){let o=`${e.name}#${e.version}`,i=O[o]?.[t];if(i)return {shouldSkip:true,reason:i};let n=O[e.name]?.[t];return n?{shouldSkip:true,reason:n}:{shouldSkip:false}}var S=e=>`${e.name}#${e.version}`,Y=e=>`${e.name}@${e.version}`;var Z=e=>{let t=JSON.stringify(e);return createHash("sha256").update(t).digest("hex").slice(0,16)},ee=(e,t)=>({...e,package_meta:e.package_meta||t,name:e.name,url:e.url,base:e.base});var te=e=>e?.kind==="nested",ne=e=>e?.kind==="profile";var ie=(e,t)=>{if(!e.url)throw new Error("ValueSet must have a URL");if(!e.name)throw new Error("ValueSet must have a name");return {...e,package_meta:e.package_meta||t,name:e.name,url:e.url}};function M(e){let t=e.split("|")[0];return t||e}function ve(e){return e.split("|")[1]}function Fe(e){return e.derivation==="constraint"?"profile":e.kind==="primitive-type"?"primitive-type":e.kind==="complex-type"?"complex-type":e.kind==="resource"?"resource":e.kind==="logical"?"logical":"resource"}function C(e){return {kind:Fe(e),package:e.package_meta.name,version:e.package_meta.version,name:e.name,url:e.url}}var Ee=e=>{let t=e.split("/"),o=t[t.length-1];return o&&o.length>0?o.split(/[-_]/).map(i=>i.charAt(0).toUpperCase()+i.slice(1).toLowerCase()).join(""):e};function L(e,t,o){let i=M(o),n=Ee(i),r={package_meta:{name:"missing_valuesets",version:ve(i)||"0.0.0"},id:o},s=e.resolveVs(t,i)||r,c=s?.id&&!/^[a-zA-Z0-9_-]{20,}$/.test(s.id)?s.id:n;return {kind:"value-set",package:s.package_meta.name,version:s.package_meta.version,name:c,url:i}}function P(e,t,o){let i=o.binding?.bindingName,n=t.join("."),[r,s,c]=i?[{name:"shared",version:"1.0.0"},i,`urn:fhir:binding:${i}`]:[e.package_meta,`${e.name}.${n}_binding`,`${e.url}#${n}_binding`];return {kind:"binding",package:r.name,version:r.version,name:s,url:c}}function B(e,t,o,i){let n=M(o)||o,r=e.resolveVs(t,n);if(r)return De(e,r)}function De(e,t,o){if(t.expansion?.contains)return t.expansion.contains.filter(n=>n.code!==void 0).map(n=>(Te(n.code),{code:n.code,display:n.display,system:n.system}));let i=[];if(t.compose?.include){for(let n of t.compose.include)if(n.concept)for(let r of n.concept)i.push({system:n.system,code:r.code,display:r.display});else if(n.system&&!n.filter)try{let r=e.resolveAny(n.system);if(r?.concept){let s=(c,a)=>{for(let l of c)i.push({system:a,code:l.code,display:l.display}),l.concept&&s(l.concept,a);};s(r.concept,n.system);}}catch{}}return i.length>0?i:void 0}var oe=100,j=new Set(["code","Coding","CodeableConcept","CodeableReference","Quantity","string","uri","Duration"]);function _(e,t,o,i){if(!o.binding)return;let n=o.binding.strength,r=o.binding.valueSet;if(!r)return;if(!j.has(o.type??"")){i?.dryWarn(`eld-11: Binding on non-bindable type '${o.type}' (valueSet: ${r})`);return}if(!(n==="required"||n==="extensible"||n==="preferred"))return;let c=B(e,t.package_meta,r);if(!c||c.length===0)return;let a=c.map(l=>l.code).filter(l=>l&&typeof l=="string"&&l.trim().length>0);if(a.length>oe){i?.dryWarn(`Value set ${r} has ${a.length} which is more than ${oe} codes, which may cause issues with code generation.`);return}if(a.length!==0)return {isOpen:n!=="required",values:a}}function Le(e,t,o,i,n){if(!i.binding?.valueSet)return;let r=P(t,o,i),s=L(e,t.package_meta,i.binding.valueSet),c=_(e,t,i,n);return {identifier:r,valueset:s,strength:i.binding.strength,enum:c,dependencies:[s]}}function re(e,t,o){let i=new Set;if(!t.elements)return [];let n=[];function r(a,l){for(let[u,m]of Object.entries(a)){let h=[...l,u],p=h.join("."),d=e.resolveElementSnapshot(t,h);if(!i.has(p)){if(i.add(p),d.binding){let f=Le(e,t,h,d,o);f&&n.push(f);}m.elements&&r(m.elements,h);}}}r(t.elements,[]),n.sort((a,l)=>a.identifier.name.localeCompare(l.identifier.name));let s=[],c=new Set;for(let a of n)c.has(a.identifier.url)||(c.add(a.identifier.url),s.push(a));return s}function w(e,t,o,i){let n={};if(t.derivation==="constraint"){let m=e.resolveFsSpecializations(t.package_meta,t.url).map(h=>A(e,h,i)).filter(h=>h!==void 0).flat();for(let h of m.reverse())n[h.identifier.name]=h.identifier.url;}let r=o.join("."),s=n[r]??`${t.url}#${r}`,c=s.split("#")[0],l=e.resolveFs(t.package_meta,c)?.package_meta??t.package_meta;return {kind:"nested",package:l.name,version:l.version,name:r,url:s}}function se(e,t,o){let i=[];for(let[n,r]of Object.entries(o)){let s=[...t,n];E(r)&&i.push([s,r]),r.elements&&i.push(...se(e,s,r.elements));}return i}function Pe(e,t,o,i,n){let r={};for(let[s,c]of Object.entries(i)){let a=[...o,s],l=e.resolveElementSnapshot(t,a);E(l)?r[s]=U(e,t,a,l,n):r[s]=N(e,t,a,l,n);}return r}function A(e,t,o){if(!t.elements)return;let i=se(t,[],t.elements).filter(([r,s])=>s.elements&&Object.keys(s.elements).length>0),n=[];for(let[r,s]of i){let c=w(e,t,r,o),a;s.type==="BackboneElement"||!s.type?a="BackboneElement":a=s.type;let l=e.ensureSpecializationCanonicalUrl(a),u=e.resolveFs(t.package_meta,l);if(!u)throw new Error(`Could not resolve base type ${a}`);let m={kind:"complex-type",package:u.package_meta.name,version:u.package_meta.version,name:a,url:l},h=Pe(e,t,r,s.elements??{},o),p={identifier:c,base:m,fields:h};n.push(p);}return n.sort((r,s)=>r.identifier.url.localeCompare(s.identifier.url)),n.length===0?void 0:n}function ae(e){let t=[];for(let o of e){o.base&&t.push(o.base);for(let i of Object.values(o.fields||{}))"type"in i&&i.type&&t.push(i.type),"binding"in i&&i.binding&&t.push(i.binding);}return t}function ce(e,t,o){let i=o[o.length-1];if(!i)throw new Error(`Internal error: fieldName is missing for path ${o.join("/")}`);let n=o.slice(0,-1),r=e.resolveFsGenealogy(t.package_meta,t.url).flatMap(s=>{if(n.length===0)return s.required||[];if(!s.elements)return [];let c=s;for(let a of n)c=c?.elements?.[a];return c?.required||[]});return new Set(r).has(i)}function le(e,t,o){let i=o[o.length-1];if(!i)throw new Error(`Internal error: fieldName is missing for path ${o.join("/")}`);let n=o.slice(0,-1),r=e.resolveFsGenealogy(t.package_meta,t.url).flatMap(s=>{if(n.length===0)return s.excluded||[];if(!s.elements)return [];let c=s;for(let a of n)c=c?.elements?.[a];return c?.excluded||[]});return new Set(r).has(i)}var we=(e,t,o)=>{if(o.refers)return o.refers.map(i=>{let n=e.ensureSpecializationCanonicalUrl(i),r=e.resolveFs(t.package_meta,n);if(!r)throw new Error(`Failed to resolve fs for ${n}`);return C(r)})},Ne=e=>{let t=new Set,o=new Set;if(e.required)for(let i of e.required)t.add(i);if(e.excluded)for(let i of e.excluded)o.add(i);if(e.elements)for(let[i,n]of Object.entries(e.elements))n.min!==void 0&&n.min>0&&t.add(i);return {required:t.size>0?Array.from(t):void 0,excluded:o.size>0?Array.from(o):void 0}},pe=e=>{let t=e.slicing;if(!t)return;let o={};for(let[i,n]of Object.entries(t.slices??{})){if(!n)continue;let{required:r,excluded:s}=n.schema?Ne(n.schema):{};o[i]={min:n.min,max:n.max,match:n.match,required:r,excluded:s};}return {discriminator:t.discriminator,rules:t.rules,ordered:t.ordered,slices:Object.keys(o).length>0?o:void 0}};function $(e,t,o,i,n){if(i.elementReference){let r=i.elementReference.slice(1).filter((s,c)=>c%2===1);return w(e,t,r,n)}else if(i.type){let r=e.ensureSpecializationCanonicalUrl(i.type),s=e.resolveFs(t.package_meta,r);if(!s)throw new Error(`Could not resolve field type: <${t.url}>.${o.join(".")}: <${i.type}> (pkg: '${S(t.package_meta)}'))`);return C(s)}else {if(i.choices)return;if(t.derivation==="constraint")return;n?.dryWarn(`Can't recognize element type: <${t.url}>.${o.join(".")} (pkg: '${S(t.package_meta)}'): missing type info`);return}}var N=(e,t,o,i,n)=>{let r,s;i.binding&&(r=P(t,o,i),j.has(i.type??"")&&(s=_(e,t,i,n)));let c=$(e,t,o,i,n);return c||n?.dryWarn(`Field type not found for '${t.url}#${o.join(".")}' (${t.derivation})`),{type:c,required:ce(e,t,o),excluded:le(e,t,o),reference:we(e,t,i),array:i.array||false,min:i.min,max:i.max,slicing:pe(i),choices:i.choices,choiceOf:i.choiceOf,binding:r,enum:s}};function E(e){let t=e.type==="BackboneElement",o=e.type==="Element"&&e.elements!==void 0&&Object.keys(e.elements).length>0,i=e.type===void 0&&e.choiceOf===void 0&&e.elements!==void 0&&Object.keys(e.elements).length>0;return t||o||i}function U(e,t,o,i,n){return {type:w(e,t,o,n),array:i.array||false,required:ce(e,t,o),excluded:le(e,t,o),slicing:pe(i)}}function Ue(e,t,o,i,n){if(!i)return;let r={};for(let s of e.getAllElementKeys(i)){let c=[...o,s],a=e.resolveElementSnapshot(t,c),l=a.type?e.ensureSpecializationCanonicalUrl(a.type):void 0;if(l&&I(t.package_meta,l).shouldSkip){n?.warn(`Skipping field ${c} for ${l} due to skip hack ${I(t.package_meta,l).reason}`);continue}E(a)?r[s]=U(e,t,c,a,n):r[s]=N(e,t,c,a,n);}return r}function $e(e){let t=[];for(let o of Object.values(e))"type"in o&&o.type&&t.push(o.type),"binding"in o&&o.binding&&t.push(o.binding);return t}function He(e,t){return !!(e.base==="Extension"||e.base==="http://hl7.org/fhir/StructureDefinition/Extension"||e.url?.includes("/extension/")||e.url?.includes("-extension")||e.name?.toLowerCase().includes("extension")||e.type==="Extension")}async function de(e,t,o){if(!t.url)throw new Error("ValueSet URL is required");let i=L(e,t.package_meta,t.url),n=B(e,t.package_meta,t.url);return {identifier:i,description:t.description,concept:n,compose:n?void 0:t.compose}}function Ve(e,t,o,i){let n=[];t&&n.push(t),o&&n.push(...$e(o)),i&&n.push(...ae(i));let r={};for(let a of n)a.url!==e.url&&(r[a.url]=a);let s=new Set(i?.map(a=>a.identifier.url)),c=Object.values(r).filter(a=>ne(e)||!te(a)?true:!s.has(a.url)).sort((a,l)=>a.url.localeCompare(l.url));return c.length>0?c:void 0}function Oe(e,t,o){let i=C(t),n;if(t.base&&t.type!=="Element"){let p=e.resolveFs(t.package_meta,e.ensureSpecializationCanonicalUrl(t.base));if(!p)throw new Error(`Base resource not found '${t.base}' for <${t.url}> from ${S(t.package_meta)}`);n=C(p);}let r=Ue(e,t,[],t.elements,o),s=A(e,t,o),c=t.derivation==="constraint"?Ae(e,t,o):void 0,a=Ve(i,n,r,s),l=c?.flatMap(p=>p.valueTypes??[])??[],u=(()=>{if(!a&&l.length===0)return a;let p={};for(let d of a??[])p[d.url]=d;for(let d of l)p[d.url]=d;return Object.values(p)})(),m={identifier:i,base:n,fields:r,nested:s,description:t.description,dependencies:u,...c&&c.length>0?{extensions:c}:{}},h=re(e,t,o);return [m,...h]}function Me(e,t,o,i){let n=e.resolveFs(t.package_meta,o);if(!n?.elements)return;let r=[];for(let[c,a]of Object.entries(n.elements)){if(a.choiceOf!=="value"&&!c.startsWith("value"))continue;let l=$(e,n,[c],a,i);l&&r.push(l);}if(r.length===0)return;let s=new Map(r.map(c=>[c.url,c]));return Array.from(s.values())}var Be=(e,t,o)=>{let i=[];if(!t.elements)return i;for(let[n,r]of Object.entries(t.elements)){if(!n.startsWith("extension:"))continue;let s=n.split(":")[1];if(!s)continue;let c;for(let[a,l]of Object.entries(r.elements??{}))if(!(l.choiceOf!=="value"&&!a.startsWith("value"))&&(c=$(e,t,[n,a],l,o),c))break;i.push({name:s,url:r.url??s,valueType:c,min:r.min,max:r.max!==void 0?String(r.max):void 0});}return i},je=e=>{let t=[],i=e.elements?.extension?.slicing?.slices;if(!i||typeof i!="object")return t;for(let[n,r]of Object.entries(i)){let s=r,c=s.schema;if(!c)continue;let a;for(let[l,u]of Object.entries(c.elements??{})){let m=u;if(!(m.choiceOf!=="value"&&!l.startsWith("value"))&&m.type){a={kind:"complex-type",package:e.package_meta.name,version:e.package_meta.version,name:m.type,url:`http://hl7.org/fhir/StructureDefinition/${m.type}`};break}}t.push({name:n,url:s.match?.url??n,valueType:a,min:c._required?1:c.min??0,max:c.max!==void 0?String(c.max):c.array?"*":"1"});}return t},_e=(e,t,o,i)=>{let n=e.resolveFs(t.package_meta,o);if(!n?.elements)return;let r=Be(e,n,i),s=je(n),c=[...r,...s];return c.length>0?c:void 0};function Ae(e,t,o){let i=[],n=(s,c,a)=>{let l=a.url,u=l?Me(e,t,l,o):void 0,m=l?_e(e,t,l,o):void 0,h=m!==void 0&&m.length>0;i.push({name:c,path:[...s,"extension"].join("."),url:l,min:a.min,max:a.max!==void 0?String(a.max):void 0,mustSupport:a.mustSupport,valueTypes:u,subExtensions:m,isComplex:h});},r=(s,c)=>{if(c.extensions)for(let[a,l]of Object.entries(c.extensions))n(s,a,l);if(c.elements)for(let[a,l]of Object.entries(c.elements))r([...s,a],l);};if(t.extensions)for(let[s,c]of Object.entries(t.extensions))n([],s,c);if(t.elements)for(let[s,c]of Object.entries(t.elements))r([s],c);return i}async function ue(e,t,o){let i=Oe(e,t,o);if(He(t,C(t))){let n=i[0];if(!n)throw new Error("Expected schema to be defined");n.metadata={isExtension:true};}return i}var Ge=(e,t)=>{let o={};for(let r of e){let s=`${r.schema.identifier.url}|${r.schema.identifier.package}`,c=Z(r.schema);o[s]??={},o[s][c]??={typeSchema:r.schema,sources:[]},o[s][c].sources.push(r);}let i=[],n={};for(let r of Object.values(o)){let s=Object.values(r).sort((a,l)=>l.sources.length-a.sources.length),c=s[0];if(c&&(i.push(c.typeSchema),s.length>1)){let a=c.typeSchema.identifier.package,l=c.typeSchema.identifier.url;t?.dryWarn(`'${l}' from '${a}'' has ${s.length} versions`),n[a]??={},n[a][l]=s.flatMap(u=>u.sources.map(m=>({typeSchema:u.typeSchema,sourcePackage:m.sourcePackage,sourceCanonical:m.sourceCanonical})));}}return {schemas:i,collisions:n}},me=async(e,t)=>{let o=[];for(let i of e.allFs()){let n=S(i.package_meta),r=I(i.package_meta,i.url);if(r.shouldSkip){t?.dryWarn(`Skip ${i.url} from ${n}. Reason: ${r.reason}`);continue}for(let s of await ue(e,i,t))o.push({schema:s,sourcePackage:n,sourceCanonical:i.url});}for(let i of e.allVs())o.push({schema:await de(e,i),sourcePackage:S(i.package_meta),sourceCanonical:i.url});return Ge(o,t)};var G=e=>e!==null&&typeof e=="object"&&e.resourceType==="CodeSystem";var H=e=>e!==null&&typeof e=="object"&&e.resourceType==="ValueSet";var qe=async(e,t)=>{let o=await e.packageJson(t.name);if(!o)return [];let i=o.dependencies;return i!==void 0?Object.entries(i).map(([n,r])=>({name:n,version:r})):[]},he=e=>({pkg:e,canonicalResolution:{},fhirSchemas:{},valueSets:{}}),ye=async(e,t,o,i,n)=>{let r=S(t);if(n?.info(`${" ".repeat(o*2)}+ ${r}`),i[r])return i[r];let s=he(t);for(let a of await e.search({package:t})){let l=a.url;if(!l||!(isStructureDefinition(a)||H(a)||G(a)))continue;let u=l;s.canonicalResolution[u]&&n?.dryWarn(`Duplicate canonical URL: ${u} at ${r}.`),s.canonicalResolution[u]=[{deep:o,pkg:t,pkgId:r,resource:a}];}let c=await qe(e,t);for(let a of c){let{canonicalResolution:l}=await ye(e,a,o+1,i,n);for(let[u,m]of Object.entries(l)){let h=u;s.canonicalResolution[h]=[...s.canonicalResolution[h]||[],...m];}}for(let a of Object.values(s.canonicalResolution))a.sort((l,u)=>l.deep-u.deep);return i[r]=s,s},fe=(e,t)=>{for(let{pkg:o,canonicalResolution:i}of Object.values(e)){let n=S(o);if(!e[n])throw new Error(`Package ${n} not found`);for(let[s,c]of Object.entries(i)){let a=c[0];if(!a)throw new Error("Resource not found");let l=a.resource,u=a.pkg;if(isStructureDefinition(l)){let m=ge.translate(l),h=ee(m,u);e[n].fhirSchemas[h.url]=h;}if(H(l)){let m=ie(l,u);e[n].valueSets[m.url]=m;}}}},ze=(e,t,o)=>{let i=Object.values(e).flatMap(n=>n.canonicalResolution[t]);if(!i)throw new Error(`No canonical resolution found for ${t} in any package`);return i[0]?.resource},Ke=async(e,{logger:t,focusedPackages:o})=>{let i=o??await e.packages(),n={};for(let p of i)await ye(e,p,0,n,t);fe(n);let r=(p,d)=>{let f=n[S(p)];if(f){let g=f.canonicalResolution[d]?.[0];if(g)return n[g.pkgId]?.fhirSchemas[d]}for(let g of Object.values(n)){let y=g.fhirSchemas[d];if(y&&y.package_meta.name===p.name)return y}for(let g of Object.values(n)){let y=g.fhirSchemas[d];if(y)return y}},s=(p,d)=>{let f=n[S(p)];if(f){let g=f.canonicalResolution[d]?.[0];if(g)return n[g.pkgId]?.valueSets[d]}for(let g of Object.values(n)){let y=g.valueSets[d];if(y&&y.package_meta.name===p.name)return y}for(let g of Object.values(n)){let y=g.valueSets[d];if(y)return y}},c=p=>(p.includes("|")&&(p=p.split("|")[0]),p.match(/^[a-zA-Z0-9]+$/)?`http://hl7.org/fhir/StructureDefinition/${p}`:p),a=(p,d)=>{let f=r(p,d);if(f===void 0)throw new Error(`Failed to resolve FHIR Schema: '${d}'`);let g=[f];for(;f?.base;){let y=f.package_meta,R=c(f.base);if(f=r(y,R),f===void 0)throw new Error(`Failed to resolve FHIR Schema base for '${d}'. Problem: '${R}' from '${S(y)}'`);g.push(f);}return g},l=(p,d)=>a(p,d).filter(f=>f.derivation==="specialization"),u=(p,d)=>{let f=a(p.package_meta,p.url),g=Je(f,d);return Qe(g)},m=p=>{let d=new Set;for(let[f,g]of Object.entries(p)){d.add(f);for(let y of g?.choices||[])p[y]||d.add(y);}return Array.from(d)},h;return {testAppendFs(p){let d=S(p.package_meta);n[d]||(n[d]=he(p.package_meta)),n[d].fhirSchemas[p.url]=p,h=void 0;},resolveFs:r,resolveFsGenealogy:a,resolveFsSpecializations:l,ensureSpecializationCanonicalUrl:c,resolveSd:(p,d)=>{let f=n[S(p)]?.canonicalResolution[d]?.[0]?.resource;if(isStructureDefinition(f))return f},allSd:()=>Object.values(n).flatMap(p=>Object.values(p.canonicalResolution).flatMap(d=>d.map(f=>{let g=f.resource;return g.package_name?g:{...g,package_name:p.pkg.name,package_version:p.pkg.version}}))).filter(p=>isStructureDefinition(p)).sort((p,d)=>p.url.localeCompare(d.url)),patchSd:p=>{Object.values(n).flatMap(d=>Object.values(d.canonicalResolution).forEach(f=>{f.forEach(g=>{if(isStructureDefinition(g.resource)){let y=g.resource,R=p(d.pkg,y);if(y.url!==R.url)throw new Error(`Patch update StructureDefinition URL: ${y.url} !== ${R.url}`);g.resource=R;}});})),fe(n),h=void 0;},allFs:()=>Object.values(n).flatMap(p=>Object.values(p.fhirSchemas)),allVs:()=>Object.values(n).flatMap(p=>Object.values(p.valueSets)),resolveVs:s,resolveAny:p=>ze(n,p),resolveElementSnapshot:u,getAllElementKeys:m,resolver:n,resolutionTree:()=>{if(h)return h;let p={};for(let[d,f]of Object.entries(n)){let g=f.pkg.name;p[g]={};for(let[y,R]of Object.entries(f.canonicalResolution)){let q=y;p[g][q]=[];for(let z of R)p[g][q].push({deep:z.deep,pkg:z.pkg});}}return h=p,p}}},xe=async(e,t)=>{let o=e.map(Y);t?.logger?.step(`Loading FHIR packages: ${o.join(", ")}`);let i=CanonicalManager({packages:o,workingDir:"tmp/fhir",registry:t.registry||void 0});return await i.init(),await Ke(i,{...t,focusedPackages:e})},Je=(e,t)=>{let[o,...i]=t;return o===void 0?[]:e.map(n=>{if(!n.elements)return;let r=n.elements?.[o];for(let s of i)r=r?.elements?.[s];return r}).filter(n=>n!==void 0)};function Qe(e){let t=e.reverse(),o=Object.assign({},...t);return o.elements=void 0,o}var Se={command:"generate <packages..>",describe:"Generate TypeSchema files from FHIR packages",builder:{packages:{type:"string",array:true,demandOption:true,describe:"FHIR packages to process (e.g., hl7.fhir.r4.core@4.0.1)"},output:{alias:"o",type:"string",describe:"Output file or directory",default:"./schemas.ndjson"},format:{alias:"f",type:"string",choices:["ndjson","json"],default:"ndjson",describe:"Output format for TypeSchema files"},treeshake:{alias:"t",type:"string",array:true,describe:"Only generate TypeSchemas for specific ResourceTypes (treeshaking)"},singleFile:{alias:"s",type:"boolean",default:false,describe:"Generate single TypeSchema file instead of multiple files (NDJSON format)"},verbose:{alias:"v",type:"boolean",default:false,describe:"Enable verbose output"},registry:{alias:"r",type:"string",describe:"Custom FHIR package registry URL (default: https://fs.get-ig.org/pkgs/)"}},handler:async e=>{let t=J({prefix:"TypeSchema"});try{t.step("Generating TypeSchema from FHIR packages"),t.info(`Packages: ${e.packages.join(", ")}`),t.info(`Output: ${e.output}`);let o=e.singleFile?"ndjson":e.format;t.debug(`Format: ${o}${e.singleFile&&e.format==="json"?" (forced from json due to singleFile)":""}`),e.treeshake&&e.treeshake.length>0&&t.info(`Treeshaking enabled for ResourceTypes: ${e.treeshake.join(", ")}`),e.singleFile&&t.info("Single file output enabled (NDJSON format)"),e.registry&&t.info(`Using custom registry: ${e.registry}`);let i=Date.now(),n=e.packages.map(u=>{if(u.includes("@")){let m=u.lastIndexOf("@");return {name:u.slice(0,m),version:u.slice(m+1)||"latest"}}return {name:u,version:"latest"}});t.progress(`Processing packages: ${n.map(u=>`${u.name}@${u.version}`).join(", ")}`);let r=await xe(n,{logger:t,registry:e.registry,focusedPackages:n}),{schemas:s}=await me(r,t);if(s.length===0)throw new Error("No schemas were generated from the specified packages");let c=e.output;if(!c)throw new Error("Output format not specified");await mkdir(dirname(c),{recursive:!0});let a;o==="json"?a=JSON.stringify(s,null,2):a=s.map(u=>JSON.stringify(u)).join(`
|
|
3
|
-
`),await writeFile(c,
|
|
2
|
+
import S from'picocolors';import at from'yargs';import {hideBin}from'yargs/helpers';import {mkdir,writeFile}from'fs/promises';import {dirname}from'path';import {createHash}from'crypto';import Ue from'assert';import {CanonicalManager}from'@atomic-ehr/fhir-canonical-manager';import*as pe from'@atomic-ehr/fhirschema';import {isStructureDefinition}from'@atomic-ehr/fhirschema';var T=class t{options;dryWarnSet=new Set;constructor(e={}){this.options={timestamp:false,level:1,...e};}shouldLog(e){let i=this.options.level??1;return e>=i}static consoleLevelsMap={1:console.log,2:console.warn,3:console.error,0:console.log,4:()=>{}};formatMessage(e,i,n){let o=this.options.timestamp?`${S.gray(new Date().toLocaleTimeString())} `:"",r=this.options.prefix?`${S.cyan(`[${this.options.prefix}]`)} `:"";return `${o}${n(e)} ${r}${i}`}isSuppressed(e){return this.options.suppressLoggingLevel==="all"||this.options.suppressLoggingLevel?.includes(e)||false}tryWriteToConsole(e,i){if(this.isSuppressed(e)||!this.shouldLog(e))return;(t.consoleLevelsMap[e]||console.log)(i);}success(e){this.tryWriteToConsole(1,this.formatMessage("",e,S.green));}error(e,i){if(this.isSuppressed(3)||!this.shouldLog(3))return;console.error(this.formatMessage("X",e,S.red));let n=this.options.level===0;i&&n&&(console.error(S.red(` ${i.message}`)),i.stack&&console.error(S.gray(i.stack)));}warn(e){this.tryWriteToConsole(2,this.formatMessage("!",e,S.yellow));}dryWarn(e){this.dryWarnSet.has(e)||(this.warn(e),this.dryWarnSet.add(e));}info(e){this.tryWriteToConsole(1,this.formatMessage("i",e,S.blue));}debug(e){this.shouldLog(0)&&this.tryWriteToConsole(0,this.formatMessage("\u{1F41B}",e,S.magenta));}step(e){this.tryWriteToConsole(1,this.formatMessage("\u{1F680}",e,S.cyan));}progress(e){this.tryWriteToConsole(1,this.formatMessage("\u23F3",e,S.blue));}plain(e,i=n=>n){let n=this.options.timestamp?`${S.gray(new Date().toLocaleTimeString())} `:"",o=this.options.prefix?`${S.cyan(`[${this.options.prefix}]`)} `:"";this.tryWriteToConsole(1,`${n}${o}${i(e)}`);}dim(e){this.plain(e,S.gray);}child(e){return new t({...this.options,prefix:this.options.prefix?`${this.options.prefix}:${e}`:e})}configure(e){this.options={...this.options,...e};}getLevel(){return this.options.level??1}setLevel(e){this.options.level=e;}},I=new T;function Ee(t){I.success(t);}function R(t,e){I.error(t,e);}function $(t){I.info(t);}function Te(t){I.dim(t);}function Y(t){I.configure(t);}function Z(t={}){return new T(t)}function ee(t){console.log(),console.log(S.cyan(S.bold(`\u2501\u2501\u2501 ${t} \u2501\u2501\u2501`)));}function te(t,e,i){let n=t;e&&(n+=` ${S.gray(`(${e}ms)`)}`),Ee(n),i&&Object.entries(i).forEach(([o,r])=>{Te(` ${o}: ${r}`);});}function k(t,e="\u2022"){t.forEach(i=>{console.log(S.gray(` ${e} ${i}`));});}var v="Use CodeableReference which is not provided by FHIR R4.",De="Use Availability which is not provided by FHIR R4.",j={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":De,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":v,"http://hl7.org/fhir/StructureDefinition/specimen-additive":v,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":v,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":v,"http://hl7.org/fhir/StructureDefinition/workflow-reason":v},"hl7.fhir.r5.core#5.0.0":{"http://hl7.org/fhir/StructureDefinition/shareablecodesystem":"FIXME: CodeSystem.concept.concept defined by ElementReference. FHIR Schema generator output broken value in it, so we just skip it for now.","http://hl7.org/fhir/StructureDefinition/publishablecodesystem":"Uses R5-only base types not available in R4 generation."}};function C(t,e){let i=`${t.name}#${t.version}`,n=j[i]?.[e];if(n)return {shouldSkip:true,reason:n};let o=j[t.name]?.[e];return o?{shouldSkip:true,reason:o}:{shouldSkip:false}}var x=t=>`${t.name}#${t.version}`,ne=t=>`${t.name}@${t.version}`;var ie=t=>{let e=JSON.stringify(t);return createHash("sha256").update(e).digest("hex").slice(0,16)},oe=(t,e)=>({...t,package_meta:t.package_meta||e,name:t.name,url:t.url,base:t.base});var re=t=>t?.kind==="nested",se=t=>t?.kind==="profile",F=(...t)=>{let e=t.filter(n=>n!==void 0).flatMap(n=>n.map(o=>[o.url,o]));return e.length===0?void 0:Object.values(Object.fromEntries(e)).sort((n,o)=>n.url.localeCompare(o.url))};var ae=(t,e)=>{if(!t.url)throw new Error("ValueSet must have a URL");if(!t.name)throw new Error("ValueSet must have a name");return {...t,package_meta:t.package_meta||e,name:t.name,url:t.url}};function M(t){let e=t.split("|")[0];return e||t}function we(t){return t.split("|")[1]}function Pe(t){return t.derivation==="constraint"?"profile":t.kind==="primitive-type"?"primitive-type":t.kind==="complex-type"?"complex-type":t.kind==="resource"?"resource":t.kind==="logical"?"logical":"resource"}function b(t){return {kind:Pe(t),package:t.package_meta.name,version:t.package_meta.version,name:t.name,url:t.url}}var Ne=t=>{let e=t.split("/"),i=e[e.length-1];return i&&i.length>0?i.split(/[-_]/).map(n=>n.charAt(0).toUpperCase()+n.slice(1).toLowerCase()).join(""):t};function D(t,e,i){let n=M(i),o=Ne(n),r={package_meta:{name:"missing_valuesets",version:we(n)||"0.0.0"},id:i},s=t.resolveVs(e,n)||r,a=s?.id&&!/^[a-zA-Z0-9_-]{20,}$/.test(s.id)?s.id:o;return {kind:"value-set",package:s.package_meta.name,version:s.package_meta.version,name:a,url:n}}function L(t,e,i){let n=i.binding?.bindingName,o=e.join("."),[r,s,a]=n?[{name:"shared",version:"1.0.0"},n,`urn:fhir:binding:${n}`]:[t.package_meta,`${t.name}.${o}_binding`,`${t.url}#${o}_binding`];return {kind:"binding",package:r.name,version:r.version,name:s,url:a}}function B(t,e,i,n){let o=M(i)||i,r=t.resolveVs(e,o);if(r)return He(t,r)}function He(t,e,i){if(e.expansion?.contains)return e.expansion.contains.filter(o=>o.code!==void 0).map(o=>(Ue(o.code),{code:o.code,display:o.display,system:o.system}));let n=[];if(e.compose?.include){for(let o of e.compose.include)if(o.concept)for(let r of o.concept)n.push({system:o.system,code:r.code,display:r.display});else if(o.system&&!o.filter)try{let r=t.resolveAny(o.system);if(r?.concept){let s=(a,c)=>{for(let l of a)n.push({system:c,code:l.code,display:l.display}),l.concept&&s(l.concept,c);};s(r.concept,o.system);}}catch{}}return n.length>0?n:void 0}var ce=100,_=new Set(["code","Coding","CodeableConcept","CodeableReference","Quantity","string","uri","Duration"]);function A(t,e,i,n){if(!i.binding)return;let o=i.binding.strength,r=i.binding.valueSet;if(!r)return;if(!_.has(i.type??"")){n?.dryWarn(`eld-11: Binding on non-bindable type '${i.type}' (valueSet: ${r})`);return}if(!(o==="required"||o==="extensible"||o==="preferred"))return;let a=B(t,e.package_meta,r);if(!a||a.length===0)return;let c=a.map(l=>l.code).filter(l=>l&&typeof l=="string"&&l.trim().length>0);if(c.length>ce){n?.dryWarn(`Value set ${r} has ${c.length} which is more than ${ce} codes, which may cause issues with code generation.`);return}if(c.length!==0)return {isOpen:o!=="required",values:c}}function Ve(t,e,i,n,o){if(!n.binding?.valueSet)return;let r=L(e,i,n),s=D(t,e.package_meta,n.binding.valueSet),a=A(t,e,n,o);return {identifier:r,valueset:s,strength:n.binding.strength,enum:a,dependencies:[s]}}function le(t,e,i){let n=new Set;if(!e.elements)return [];let o=[];function r(c,l){for(let[d,m]of Object.entries(c)){let y=[...l,d],p=y.join("."),u=t.resolveElementSnapshot(e,y);if(!n.has(p)){if(n.add(p),u.binding){let f=Ve(t,e,y,u,i);f&&o.push(f);}m.elements&&r(m.elements,y);}}}r(e.elements,[]),o.sort((c,l)=>c.identifier.name.localeCompare(l.identifier.name));let s=[],a=new Set;for(let c of o)a.has(c.identifier.url)||(a.add(c.identifier.url),s.push(c));return s}var G=t=>t!==null&&typeof t=="object"&&t.resourceType==="CodeSystem";var w=t=>t!==null&&typeof t=="object"&&t.resourceType==="ValueSet";var $e=async(t,e)=>{let i=await t.packageJson(e.name);if(!i)return [];let n=i.dependencies;return n!==void 0?Object.entries(n).map(([o,r])=>({name:o,version:r})):[]},de=t=>({pkg:t,canonicalResolution:{},fhirSchemas:{},valueSets:{}}),ue=async(t,e,i,n,o)=>{let r=x(e);if(o?.info(`${" ".repeat(i*2)}+ ${r}`),n[r])return n[r];let s=de(e);for(let c of await t.search({package:e})){let l=c.url;if(!l||!(isStructureDefinition(c)||w(c)||G(c)))continue;let d=l;s.canonicalResolution[d]&&o?.dryWarn(`Duplicate canonical URL: ${d} at ${r}.`),s.canonicalResolution[d]=[{deep:i,pkg:e,pkgId:r,resource:c}];}let a=await $e(t,e);for(let c of a){let{canonicalResolution:l}=await ue(t,c,i+1,n,o);for(let[d,m]of Object.entries(l)){let y=d;s.canonicalResolution[y]=[...s.canonicalResolution[y]||[],...m];}}for(let c of Object.values(s.canonicalResolution))c.sort((l,d)=>l.deep-d.deep);return n[r]=s,s},je=(t,e)=>{for(let{pkg:i,canonicalResolution:n}of Object.values(t)){let o=x(i);if(!t[o])throw new Error(`Package ${o} not found`);for(let[s,a]of Object.entries(n)){let c=a[0];if(!c)throw new Error("Resource not found");let l=c.resource,d=c.pkg;if(isStructureDefinition(l)){let m=pe.translate(l),y=oe(m,d);t[o].fhirSchemas[y.url]=y;}if(w(l)){let m=ae(l,d);t[o].valueSets[m.url]=m;}}}},Me=(t,e,i)=>{let n=Object.values(t).flatMap(o=>o.canonicalResolution[e]);if(!n)throw new Error(`No canonical resolution found for ${e} in any package`);return n[0]?.resource},Be=async(t,{logger:e,focusedPackages:i})=>{let n=i??await t.packages(),o={};for(let p of n)await ue(t,p,0,o,e);je(o);let r=(p,u)=>{let f=o[x(p)];if(f){let g=f.canonicalResolution[u]?.[0];if(g)return o[g.pkgId]?.fhirSchemas[u]}for(let g of Object.values(o)){let h=g.fhirSchemas[u];if(h&&h.package_meta.name===p.name)return h}for(let g of Object.values(o)){let h=g.fhirSchemas[u];if(h)return h}},s=(p,u)=>{let f=o[x(p)];if(f){let g=f.canonicalResolution[u]?.[0];if(g)return o[g.pkgId]?.valueSets[u]}for(let g of Object.values(o)){let h=g.valueSets[u];if(h&&h.package_meta.name===p.name)return h}for(let g of Object.values(o)){let h=g.valueSets[u];if(h)return h}},a=p=>(p.includes("|")&&(p=p.split("|")[0]),p.match(/^[a-zA-Z0-9]+$/)?`http://hl7.org/fhir/StructureDefinition/${p}`:p),c=(p,u)=>{let f=r(p,u);if(f===void 0)throw new Error(`Failed to resolve FHIR Schema: '${u}'`);let g=[f];for(;f?.base;){let h=f.package_meta,E=a(f.base);if(f=r(h,E),f===void 0)throw new Error(`Failed to resolve FHIR Schema base for '${u}'. Problem: '${E}' from '${x(h)}'`);g.push(f);}return g},l=(p,u)=>c(p,u).filter(f=>f.derivation==="specialization"),d=(p,u)=>{let f=c(p.package_meta,p.url),g=N(f,u);return W(g)},m=p=>{let u=new Set;for(let[f,g]of Object.entries(p)){u.add(f);for(let h of g?.choices||[])p[h]||u.add(h);}return Array.from(u)},y;return {testAppendFs(p){let u=x(p.package_meta);o[u]||(o[u]=de(p.package_meta)),o[u].fhirSchemas[p.url]=p,y=void 0;},resolveFs:r,resolveFsGenealogy:c,resolveFsSpecializations:l,ensureSpecializationCanonicalUrl:a,resolveSd:(p,u)=>{let f=o[x(p)]?.canonicalResolution[u]?.[0]?.resource;if(isStructureDefinition(f))return f},allSd:()=>Object.values(o).flatMap(p=>Object.values(p.canonicalResolution).flatMap(u=>u.map(f=>{let g=f.resource;return g.package_name?g:{...g,package_name:p.pkg.name,package_version:p.pkg.version}}))).filter(p=>isStructureDefinition(p)).sort((p,u)=>p.url.localeCompare(u.url)),allFs:()=>Object.values(o).flatMap(p=>Object.values(p.fhirSchemas)),allVs:()=>Object.values(o).flatMap(p=>Object.values(p.valueSets)),resolveVs:s,resolveAny:p=>Me(o,p),resolveElementSnapshot:d,getAllElementKeys:m,resolver:o,resolutionTree:()=>{if(y)return y;let p={};for(let[u,f]of Object.entries(o)){let g=f.pkg.name;p[g]={};for(let[h,E]of Object.entries(f.canonicalResolution)){let Q=h;p[g][Q]=[];for(let X of E)p[g][Q].push({deep:X.deep,pkg:X.pkg});}}return y=p,p}}},me=async(t,e)=>{let i=t.map(ne);e?.logger?.step(`Loading FHIR packages: ${i.join(", ")}`);let n=CanonicalManager({packages:i,workingDir:"tmp/fhir",registry:e.registry||void 0});return await n.init(),await Be(n,{...e,focusedPackages:t})},N=(t,e)=>{let[i,...n]=e;return i===void 0?[]:t.map(o=>{if(!o.elements)return;let r=o.elements?.[i];for(let s of n)r=r?.elements?.[s];return r}).filter(o=>o!==void 0)};function W(t){let e=t.reverse(),i=Object.assign({},...e);return i.elements=void 0,i}var fe=(t,e,i)=>{let n=t.resolveFsSpecializations(e.package_meta,e.url),o=N(n,i),r=W(o).type,s;if(r){let a=t.ensureSpecializationCanonicalUrl(r),l=t.resolveFsGenealogy(e.package_meta,a).flatMap(d=>Object.keys(d.elements??{}));l.length>0&&(s=new Set(l));}for(let a of o)if(!(!a.elements||Object.keys(a.elements).length===0)&&!(s&&!Object.keys(a.elements).some(c=>!s.has(c))))return true;return false},q=(t,e,i,n,o)=>n.type==="BackboneElement"?true:!o?.elements||o.choiceOf!==void 0?false:fe(t,e,i),_e=t=>t.elements?new Set(z(t,[],t.elements).filter(([e,i])=>i.elements&&Object.keys(i.elements).length>0).map(([e])=>e.join("."))):new Set;function U(t,e,i){let n={},o=e.derivation==="constraint"?t.resolveFsSpecializations(e.package_meta,e.url):t.resolveFsGenealogy(e.package_meta,e.url);for(let d of [...o].reverse()){let m=_e(d);for(let y of m)n[y]=`${d.url}#${y}`;}let r=i.join("."),s=n[r]??`${e.url}#${r}`,a=s.split("#")[0],l=t.resolveFs(e.package_meta,a)?.package_meta??e.package_meta;return {kind:"nested",package:l.name,version:l.version,name:r,url:s}}function z(t,e,i){let n=[];for(let[o,r]of Object.entries(i)){let s=[...e,o];r.elements&&r.choiceOf===void 0&&n.push([s,r]),r.elements&&n.push(...z(t,s,r.elements));}return n}function Ae(t,e,i,n,o){let r={},s=t.resolveFsGenealogy(e.package_meta,e.url),a=N(s,i),c=new Set;for(let l of a)if(l.elements)for(let d of Object.keys(l.elements))c.add(d);for(let l of c){let d=[...i,l],m=t.resolveElementSnapshot(e,d);q(t,e,d,m,n[l])?r[l]=V(t,e,d,m):r[l]=H(t,e,d,m,o);}return r}function ge(t,e,i){if(!e.elements)return;let n=z(e,[],e.elements).filter(([r,s])=>!s.elements||Object.keys(s.elements).length===0?false:s.type!=="BackboneElement"?fe(t,e,r):true),o=[];for(let[r,s]of n){let a=U(t,e,r),c;s.type==="BackboneElement"||!s.type?c="BackboneElement":c=s.type;let l=t.ensureSpecializationCanonicalUrl(c),d=t.resolveFs(e.package_meta,l);if(!d)throw new Error(`Could not resolve base type ${c}`);let m={kind:"complex-type",package:d.package_meta.name,version:d.package_meta.version,name:c,url:l},y=Ae(t,e,r,s.elements??{},i),p={identifier:a,base:m,fields:y};o.push(p);}return o.sort((r,s)=>r.identifier.url.localeCompare(s.identifier.url)),o.length===0?void 0:o}function ye(t){let e=[];for(let i of t){i.base&&e.push(i.base);for(let n of Object.values(i.fields||{}))"type"in n&&n.type&&e.push(n.type),"binding"in n&&n.binding&&e.push(n.binding);}return e}function he(t,e,i){let n=i[i.length-1];if(!n)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let o=i.slice(0,-1),r=t.resolveFsGenealogy(e.package_meta,e.url).flatMap(s=>{if(o.length===0)return s.required||[];if(!s.elements)return [];let a=s;for(let c of o)a=a?.elements?.[c];return a?.required||[]});return new Set(r).has(n)}function Se(t,e,i){let n=i[i.length-1];if(!n)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let o=i.slice(0,-1),r=t.resolveFsGenealogy(e.package_meta,e.url).flatMap(s=>{if(o.length===0)return s.excluded||[];if(!s.elements)return [];let a=s;for(let c of o)a=a?.elements?.[c];return a?.excluded||[]});return new Set(r).has(n)}var Ge=(t,e,i)=>{if(i.refers)return i.refers.map(n=>{let o=t.ensureSpecializationCanonicalUrl(n),r=t.resolveFs(e.package_meta,o);if(!r)throw new Error(`Failed to resolve fs for ${o}`);return b(r)})},We=t=>{let e=new Set,i=new Set;if(t.required)for(let o of t.required)e.add(o);if(t.excluded)for(let o of t.excluded)i.add(o);if(t.elements)for(let[o,r]of Object.entries(t.elements))r.min!==void 0&&r.min>0&&e.add(o);let n=t.elements?Object.keys(t.elements):void 0;return {required:e.size>0?Array.from(e):void 0,excluded:i.size>0?Array.from(i):void 0,elements:n&&n.length>0?n:void 0}},qe=t=>!t||typeof t=="object"&&Object.keys(t).length===0,K=(t,e,i)=>{let n=t;for(let r=0;r<e.length-1;r++){let s=e[r];(!n[s]||typeof n[s]!="object")&&(n[s]={}),n=n[s];}let o=e[e.length-1];n[o]=i;},ze=(t,e)=>{let i=t;for(let n of e)if(i&&typeof i=="object"&&!Array.isArray(i))i=i[n];else return;return i},xe=(t,e,i,n)=>{if(i>=e.length||!t.elements)return;let o=e[i],r=t.elements[o];if(r){if(i===e.length-1&&r.fixed?.value!==void 0){K(n,e,r.fixed.value);return}if(r.slicing?.slices){let s=e.slice(i+1);for(let a of Object.values(r.slicing.slices)){if(!a.min||a.min<1||!a.match||typeof a.match!="object")continue;let c=a.match;if(Object.keys(c).length!==0)if(s.length>0){let l=ze(c,s);l!==void 0&&K(n,e,l);}else K(n,e.slice(0,i+1),c);}return}xe(r,e,i+1,n);}},Ke=(t,e)=>{if(!e?.elements||!t||t.length===0)return;let i={};for(let n of t){let o=n.path.split(".");xe(e,o,0,i);}return Object.keys(i).length>0?i:void 0},Re=t=>{let e=t.slicing;if(!e)return;let i={};for(let[n,o]of Object.entries(e.slices??{})){if(!o)continue;let{required:r,excluded:s,elements:a}=o.schema?We(o.schema):{};i[n]={min:o.min,max:o.max,match:qe(o.match)?Ke(e.discriminator??[],o.schema):o.match,required:r,excluded:s,elements:a};}return {discriminator:e.discriminator,rules:e.rules,ordered:e.ordered,slices:Object.keys(i).length>0?i:void 0}};function O(t,e,i,n,o){if(n.elementReference){let r=n.elementReference.slice(1).filter((s,a)=>a%2===1);return U(t,e,r)}else if(n.type){let r=t.ensureSpecializationCanonicalUrl(n.type),s=t.resolveFs(e.package_meta,r);if(!s)throw new Error(`Could not resolve field type: <${e.url}>.${i.join(".")}: <${n.type}> (pkg: '${x(e.package_meta)}'))`);return b(s)}else {if(n.choices)return;if(e.derivation==="constraint")return;o?.dryWarn(`Can't recognize element type: <${e.url}>.${i.join(".")} (pkg: '${x(e.package_meta)}'): missing type info`);return}}var H=(t,e,i,n,o,r)=>{let s,a;n.binding&&(s=L(e,i,n),_.has(n.type??"")&&(a=A(t,e,n,o)));let c=O(t,e,i,n,o);c||o?.dryWarn(`Field type not found for '${e.url}#${i.join(".")}' (${e.derivation})`);let l;n.pattern?l={kind:"pattern",type:n.pattern.type,value:n.pattern.value}:n.fixed&&(l={kind:"fixed",type:n.fixed.type,value:n.fixed.value});let d=r??n;if(!l&&d.elements?.coding?.slicing?.slices){let m=d.elements.coding.slicing.slices,y=Object.values(m);if(y.length>0&&y.every(u=>u.min!==void 0&&u.min>=1&&u.match&&typeof u.match=="object"&&Object.keys(u.match).length>0)){let u=y.map(f=>f.match);l={kind:"fixed",type:"CodeableConcept",value:{coding:u.length===1?[u[0]]:u}};}}return {type:c,required:he(t,e,i),excluded:Se(t,e,i),reference:Ge(t,e,n),array:n.array||false,min:n.min,max:n.max,slicing:Re(n),choices:n.choices,choiceOf:n.choiceOf,binding:s,enum:a,valueConstraint:l}};function V(t,e,i,n){return {type:U(t,e,i),array:n.array||false,required:he(t,e,i),excluded:Se(t,e,i),slicing:Re(n)}}var Je=(t,e,i,n)=>{let o=t.resolveFs(e.package_meta,i);if(!o?.elements)return;let r=[];for(let[s,a]of Object.entries(o.elements)){if(a.choiceOf!=="value"&&!s.startsWith("value"))continue;let c=O(t,o,[s],a,n);c&&r.push(c);}return F(r)},Qe=(t,e,i)=>{let n=[];if(!e.elements)return n;for(let[o,r]of Object.entries(e.elements)){if(!o.startsWith("extension:"))continue;let s=o.split(":")[1];if(!s)continue;let a;for(let[c,l]of Object.entries(r.elements??{}))if(!(l.choiceOf!=="value"&&!c.startsWith("value"))&&(a=O(t,e,[o,c],l,i),a))break;n.push({name:s,url:r.url??s,valueType:a,min:r.min,max:r.max!==void 0?String(r.max):void 0});}return n},Xe=t=>{let e=[],n=t.elements?.extension?.slicing?.slices;if(!n||typeof n!="object")return e;for(let[o,r]of Object.entries(n)){let s=r,a=s.schema;if(!a)continue;let c;for(let[l,d]of Object.entries(a.elements??{})){let m=d;if(!(m.choiceOf!=="value"&&!l.startsWith("value"))&&m.type){c={kind:"complex-type",package:t.package_meta.name,version:t.package_meta.version,name:m.type,url:`http://hl7.org/fhir/StructureDefinition/${m.type}`};break}}e.push({name:o,url:s.match?.url??o,valueType:c,min:a._required?1:a.min??0,max:a.max!==void 0?String(a.max):a.array?"*":"1"});}return e},Ye=(t,e,i,n)=>{let o=t.resolveFs(e.package_meta,i);if(!o?.elements)return;let r=Qe(t,o,n),s=Xe(o),a=[...r,...s];return a.length>0?a:void 0},ke=(t,e,i)=>{let n=[],o=(s,a,c)=>{let l=c.url,d=l?Je(t,e,l,i):void 0,m=l?Ye(t,e,l,i):void 0;if(!l){let p=e.elements?.extension?.slicing?.slices?.[a]?.schema;if(p){l=p.elements?.url?.fixed?.value??a;for(let[u,f]of Object.entries(p.elements??{})){let g=f;if(g.choiceOf==="value"&&g.type){d=[{kind:"complex-type",package:e.package_meta.name,version:e.package_meta.version,name:g.type,url:`http://hl7.org/fhir/StructureDefinition/${g.type}`}];break}}}}let y=m&&m.length>0;n.push({name:a,path:[...s,"extension"].join("."),url:l,min:c.min,max:c.max!==void 0?String(c.max):void 0,mustSupport:c.mustSupport,valueTypes:d,subExtensions:m,isComplex:y});},r=(s,a)=>{if(a.extensions)for(let[c,l]of Object.entries(a.extensions))o(s,c,l);if(a.elements)for(let[c,l]of Object.entries(a.elements))r([...s,c],l);};return r([],e),n.length===0?void 0:n};function Ze(t,e,i,n,o){if(!n)return;let r={};for(let s of t.getAllElementKeys(n)){let a=[...i,s],c=t.resolveElementSnapshot(e,a),l=c.type?t.ensureSpecializationCanonicalUrl(c.type):void 0;if(l&&C(e.package_meta,l).shouldSkip){o?.warn(`Skipping field ${a} for ${l} due to skip hack ${C(e.package_meta,l).reason}`);continue}q(t,e,a,c,n[s])?r[s]=V(t,e,a,c):r[s]=H(t,e,a,c,o,n[s]);}return r}function et(t){let e=[];for(let i of Object.values(t))"type"in i&&i.type&&e.push(i.type),"binding"in i&&i.binding&&e.push(i.binding);return e}async function Ce(t,e,i){if(!e.url)throw new Error("ValueSet URL is required");let n=D(t,e.package_meta,e.url),o=B(t,e.package_meta,e.url);return {identifier:n,description:e.description,concept:o,compose:o?void 0:e.compose}}function tt(t,e,i,n){let o=[];e&&o.push(e),i&&o.push(...et(i)),n&&o.push(...ye(n));let r=new Set(n?.map(a=>a.identifier.url)),s=o.filter(a=>a.url===t.url?false:se(t)||!re(a)?true:!r.has(a.url));return F(s)}function nt(t,e,i){let n=b(e),o;if(e.base){let y=t.resolveFs(e.package_meta,t.ensureSpecializationCanonicalUrl(e.base));if(!y)throw new Error(`Base resource not found '${e.base}' for <${e.url}> from ${x(e.package_meta)}`);o=b(y);}let r=Ze(t,e,[],e.elements,i),s=ge(t,e,i),a=e.derivation==="constraint"?ke(t,e,i):void 0,c=a?.flatMap(y=>y.valueTypes??[])??[],l=tt(n,o,r,s),d={identifier:n,base:o,fields:r,nested:s,description:e.description,dependencies:F(l,c),extensions:a},m=le(t,e,i);return [d,...m]}async function be(t,e,i){return nt(t,e,i)}var it=(t,e)=>{let i={};for(let r of t){let s=`${r.schema.identifier.url}|${r.schema.identifier.package}`,a=ie(r.schema);i[s]??={},i[s][a]??={typeSchema:r.schema,sources:[]},i[s][a].sources.push(r);}let n=[],o={};for(let r of Object.values(i)){let s=Object.values(r).sort((c,l)=>l.sources.length-c.sources.length),a=s[0];if(a&&(n.push(a.typeSchema),s.length>1)){let c=a.typeSchema.identifier.package,l=a.typeSchema.identifier.url;e?.dryWarn(`'${l}' from '${c}'' has ${s.length} versions`),o[c]??={},o[c][l]=s.flatMap(d=>d.sources.map(m=>({typeSchema:d.typeSchema,sourcePackage:m.sourcePackage,sourceCanonical:m.sourceCanonical})));}}return {schemas:n,collisions:o}},Ie=async(t,e)=>{let i=[];for(let n of t.allFs()){let o=x(n.package_meta),r=C(n.package_meta,n.url);if(r.shouldSkip){e?.dryWarn(`Skip ${n.url} from ${o}. Reason: ${r.reason}`);continue}for(let s of await be(t,n,e))i.push({schema:s,sourcePackage:o,sourceCanonical:n.url});}for(let n of t.allVs())i.push({schema:await Ce(t,n),sourcePackage:x(n.package_meta),sourceCanonical:n.url});return it(i,e)};var ve={command:"generate <packages..>",describe:"Generate TypeSchema files from FHIR packages",builder:{packages:{type:"string",array:true,demandOption:true,describe:"FHIR packages to process (e.g., hl7.fhir.r4.core@4.0.1)"},output:{alias:"o",type:"string",describe:"Output file or directory",default:"./schemas.ndjson"},format:{alias:"f",type:"string",choices:["ndjson","json"],default:"ndjson",describe:"Output format for TypeSchema files"},treeshake:{alias:"t",type:"string",array:true,describe:"Only generate TypeSchemas for specific ResourceTypes (treeshaking)"},singleFile:{alias:"s",type:"boolean",default:false,describe:"Generate single TypeSchema file instead of multiple files (NDJSON format)"},verbose:{alias:"v",type:"boolean",default:false,describe:"Enable verbose output"},registry:{alias:"r",type:"string",describe:"Custom FHIR package registry URL (default: https://fs.get-ig.org/pkgs/)"}},handler:async t=>{let e=Z({prefix:"TypeSchema"});try{e.step("Generating TypeSchema from FHIR packages"),e.info(`Packages: ${t.packages.join(", ")}`),e.info(`Output: ${t.output}`);let i=t.singleFile?"ndjson":t.format;e.debug(`Format: ${i}${t.singleFile&&t.format==="json"?" (forced from json due to singleFile)":""}`),t.treeshake&&t.treeshake.length>0&&e.info(`Treeshaking enabled for ResourceTypes: ${t.treeshake.join(", ")}`),t.singleFile&&e.info("Single file output enabled (NDJSON format)"),t.registry&&e.info(`Using custom registry: ${t.registry}`);let n=Date.now(),o=t.packages.map(d=>{if(d.includes("@")){let m=d.lastIndexOf("@");return {name:d.slice(0,m),version:d.slice(m+1)||"latest"}}return {name:d,version:"latest"}});e.progress(`Processing packages: ${o.map(d=>`${d.name}@${d.version}`).join(", ")}`);let r=await me(o,{logger:e,registry:t.registry,focusedPackages:o}),{schemas:s}=await Ie(r,e);if(s.length===0)throw new Error("No schemas were generated from the specified packages");let a=t.output;if(!a)throw new Error("Output format not specified");await mkdir(dirname(a),{recursive:!0});let c;i==="json"?c=JSON.stringify(s,null,2):c=s.map(d=>JSON.stringify(d)).join(`
|
|
3
|
+
`),await writeFile(a,c,"utf-8");let l=Date.now()-n;if(te(`Generated ${s.length} TypeSchema definitions`,l,{schemas:s.length}),e.dim(`Output: ${a}`),t.verbose){e.debug("Generated schemas:");let d=s.map(m=>`${m.identifier?.name||"Unknown"} (${m.identifier?.kind||"unknown"})`);k(d);}}catch(i){e.error("Failed to generate TypeSchema",i instanceof Error?i:new Error(String(i))),process.exit(1);}}};var Fe={command:"typeschema [subcommand]",describe:"TypeSchema operations - generate, validate and merge schemas",builder:t=>t.command(ve).help().example("$0 typeschema generate hl7.fhir.r4.core@4.0.1","Generate TypeSchema from FHIR R4 core package"),handler:t=>{if(!t.subcommand&&t._.length===1){$("Available typeschema subcommands:"),k(["generate Generate TypeSchema files from FHIR packages"]),console.log(`
|
|
4
4
|
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),console.log(`
|
|
5
|
-
Examples:`),
|
|
6
|
-
`)
|
|
7
|
-
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};function
|
|
5
|
+
Examples:`),k(["atomic-codegen typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson","atomic-codegen typeschema validate schemas.ndjson","atomic-codegen typeschema merge schema1.ndjson schema2.ndjson -o merged.ndjson"]);return}t.subcommand&&!["generate","validate","merge"].includes(t.subcommand)&&(R(`Unknown typeschema subcommand: ${t.subcommand}
|
|
6
|
+
`),$("Available typeschema subcommands:"),k(["generate Generate TypeSchema files from FHIR packages","validate Validate TypeSchema files for correctness and consistency","merge Merge multiple TypeSchema files into a single file"]),console.log(`
|
|
7
|
+
Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};function lt(t){return t?{debug:0,info:1,warn:2,error:3,silent:4}[t.toLowerCase()]:void 0}async function pt(t){let e=lt(t.logLevel);e===void 0&&(t.debug||t.verbose?e=0:e=1),Y({timestamp:t.debug,level:e});}function dt(){return at(hideBin(process.argv)).scriptName("atomic-codegen").usage("$0 <command> [options]").middleware(pt).command(Fe).option("verbose",{alias:"v",type:"boolean",description:"Enable verbose output",default:false,global:true}).option("debug",{alias:"d",type:"boolean",description:"Enable debug output with detailed logging",default:false,global:true}).option("log-level",{alias:"l",type:"string",choices:["debug","info","warn","error","silent"],description:"Set the log level (default: info)",global:true}).demandCommand(0).middleware(t=>{t._.length===0&&(ee("Welcome to Atomic Codegen!"),console.log("Available commands:"),console.log(" typeschema Generate, validate and merge TypeSchema files"),console.log(`
|
|
8
8
|
Use 'atomic-codegen <command> --help' for more information about a command.`),console.log(`
|
|
9
9
|
Quick examples:`),console.log(" atomic-codegen typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson"),console.log(`
|
|
10
|
-
Use 'atomic-codegen --help' to see all options.`),process.exit(0));}).help().version("0.1.0").example("$0 typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson","Generate TypeSchemas from FHIR package").fail((e,
|
|
11
|
-
Use --help for usage information`),process.exit(1);}).wrap(Math.min(120,process.stdout.columns||80))}async function
|
|
10
|
+
Use 'atomic-codegen --help' to see all options.`),process.exit(0));}).help().version("0.1.0").example("$0 typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson","Generate TypeSchemas from FHIR package").fail((t,e,i)=>{e?R(e.message,e):R(t),R(`
|
|
11
|
+
Use --help for usage information`),process.exit(1);}).wrap(Math.min(120,process.stdout.columns||80))}async function J(){await dt().parseAsync();}import.meta.main&&J().catch(t=>{t("Unexpected error:",t),process.exit(1);});J().catch(t=>{console.error("CLI Error:",t instanceof Error?t.message:t),process.exit(1);});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as FS from '@atomic-ehr/fhirschema';
|
|
2
2
|
import { FHIRSchema, StructureDefinition as StructureDefinition$1, FHIRSchemaElement } from '@atomic-ehr/fhirschema';
|
|
3
|
-
import { CanonicalManager } from '@atomic-ehr/fhir-canonical-manager';
|
|
3
|
+
import { CanonicalManager, PreprocessContext } from '@atomic-ehr/fhir-canonical-manager';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* CodeGen Logger
|
|
@@ -800,7 +800,6 @@ type Register = {
|
|
|
800
800
|
resolveFsGenealogy(pkg: PackageMeta, canonicalUrl: CanonicalUrl): RichFHIRSchema[];
|
|
801
801
|
resolveFsSpecializations(pkg: PackageMeta, canonicalUrl: CanonicalUrl): RichFHIRSchema[];
|
|
802
802
|
allSd(): RichStructureDefinition[];
|
|
803
|
-
patchSd(fn: (pkg: PackageMeta, sd: StructureDefinition$1) => StructureDefinition$1): void;
|
|
804
803
|
/** Returns all FHIRSchemas from all packages in the resolver */
|
|
805
804
|
allFs(): RichFHIRSchema[];
|
|
806
805
|
/** Returns all ValueSets from all packages in the resolver */
|
|
@@ -991,6 +990,7 @@ declare class APIBuilder {
|
|
|
991
990
|
constructor(userOpts?: Partial<APIBuilderOptions> & {
|
|
992
991
|
manager?: ReturnType<typeof CanonicalManager>;
|
|
993
992
|
register?: Register;
|
|
993
|
+
preprocessPackage?: (context: PreprocessContext) => PreprocessContext;
|
|
994
994
|
logger?: CodegenLogger;
|
|
995
995
|
});
|
|
996
996
|
fromPackage(packageName: string, version?: string): APIBuilder;
|