@atomic-ehr/codegen 0.0.16 → 0.0.17-canary.20260727063227.c50c42b

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Atomic EHR Team
3
+ Copyright (c) 2025-2026 Atomic EHR Team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -16,6 +16,7 @@
16
16
  - [Quick Start](#quick-start)
17
17
  - [Usage Examples](#usage-examples)
18
18
  - [Architecture](#architecture)
19
+ - [Generator Options](#generator-options)
19
20
  - [Input - FHIR packages & resolves canonicals](#input---fhir-packages--resolves-canonicals)
20
21
  - [Load Local StructureDefinitions & TGZ Archives](#load-local-structuredefinitions--tgz-archives)
21
22
  - [Intermediate - Type Schema](#intermediate---type-schema)
@@ -188,6 +189,44 @@ const builder = new APIBuilder()
188
189
 
189
190
  Each method returns the builder instance, allowing method chaining. The `generate()` method executes the pipeline and returns a report with success status and generated file details.
190
191
 
192
+ ### Generator Options
193
+
194
+ Each language generator accepts its own option object. All options are optional; the tables below list the defaults.
195
+
196
+ **TypeScript** — `.typescript({ ... })`
197
+
198
+ | Option | Type | Default | Description |
199
+ |--------|------|---------|-------------|
200
+ | `generateProfile` | `boolean` | `true` | Generate profile wrapper classes (factories, typed slice/extension accessors, `validate()`). |
201
+ | `primitiveTypeExtension` | `boolean` | `true` | Emit sibling `_field` properties for [primitive element extensions](https://www.hl7.org/fhir/element.html#json). |
202
+ | `openResourceTypeSet` | `boolean` | `false` | For resource families (`Resource`, `DomainResource`), keep the `resourceType` union open by adding a `string` fallback instead of a closed literal union. |
203
+ | `extensionGetterDefault` | `"flat" \| "profile" \| "raw"` | `"flat"` | Default return shape for generated extension getters. |
204
+ | `sliceGetterDefault` | `"flat" \| "raw"` | `"flat"` | Default return shape for generated slice getters (`flat` strips discriminators, `raw` returns the full FHIR element). |
205
+ | `lineWidth` | `number` | `120` | Maximum line width before wrapping. |
206
+ | `withDebugComment` | `boolean` | `false` | Emit comments tracing each generated type back to its source schema. |
207
+
208
+ **Python** — `.python({ ... })`
209
+
210
+ | Option | Type | Default | Description |
211
+ |--------|------|---------|-------------|
212
+ | `client` | `"fhirpy" \| "none"` | `"fhirpy"` | Client integration baked into the models: `"fhirpy"` makes models extend `FhirpyBaseModel` for the fhirpy async client; `"none"` emits plain Pydantic models. |
213
+ | `fieldFormat` | `"camelCase" \| "snake_case" \| "PascalCase"` | `"camelCase"` | Naming convention for generated model fields. |
214
+ | `generateProfile` | `boolean` | `false` | Generate profile wrapper classes (`create()`, typed accessors, `validate()`) around the Pydantic models. |
215
+ | `primitiveTypeExtension` | `boolean` | `false` | Emit primitive element extension fields. |
216
+ | `allowExtraFields` | `boolean` | `false` | Allow fields not present in the schema on generated models (Pydantic `extra`). |
217
+ | `rootPackageName` | `string` | `"fhir_types"` | Root Python package name for the generated module tree. |
218
+ | `withDebugComment` | `boolean` | `false` | Emit comments tracing each generated type back to its source schema. |
219
+
220
+ > `fhirpyClient?: boolean` is **deprecated** — use `client` instead (`true` → `"fhirpy"`, `false` → `"none"`).
221
+
222
+ **C#** — `.csharp({ ... })`
223
+
224
+ | Option | Type | Default | Description |
225
+ |--------|------|---------|-------------|
226
+ | `rootNamespace` | `string` | `"Fhir.Types"` | Root namespace for generated classes. |
227
+ | `staticSourceDir` | `string` | — | Directory of static `.cs` source files copied verbatim into the output. |
228
+ | `withDebugComment` | `boolean` | `false` | Emit comments tracing each generated type back to its source schema. |
229
+
191
230
  ### Input - FHIR packages & resolves canonicals
192
231
 
193
232
  The input stage leverages [Canonical Manager](https://github.com/atomic-ehr/canonical-manager) to handle FHIR package management and dependency resolution. It processes FHIR packages from multiple sources (registry, local files, TGZ archives) and resolves all canonical URLs to their concrete definitions, ensuring all references between resources are properly linked before transformation.
@@ -240,7 +279,7 @@ Tree shaking optimizes the generated output by including only the resources you
240
279
  })
241
280
  ```
242
281
 
243
- This feature automatically resolves and includes all dependencies (referenced types, base resources, nested types, and extension definitions used by profiles) while excluding unused resources, significantly reducing the size of generated code and improving compilation times.
282
+ This feature automatically resolves and includes all dependencies (field types, base resources, nested types, and extension definitions used by profiles) while excluding unused resources, significantly reducing the size of generated code and improving compilation times. Reference targets are not dependencies: a field typed `Reference<"Patient">` does not pull the `Patient` type into the output, since the reference is rendered as a string literal.
244
283
 
245
284
  ##### Field-Level Tree Shaking
246
285
 
@@ -272,6 +311,33 @@ Beyond resource-level filtering, tree shaking supports fine-grained field select
272
311
 
273
312
  FHIR choice types (like `multipleBirth[x]` which can be boolean or integer) are handled intelligently. Selecting/ignoring the base field affects all variants, while targeting specific variants only affects those types.
274
313
 
314
+ ##### Following Reference Targets
315
+
316
+ To also generate types for a schema's reference targets — both the base resources (`reference.resource`) and the target profiles (`reference.profiles`) — enable `followReferences` on the rule (default: `false`):
317
+
318
+ ```typescript
319
+ .typeSchema({
320
+ treeShake: {
321
+ "kbv.basis": {
322
+ "https://fhir.kbv.de/StructureDefinition/KBV_PR_Base_Condition_Diagnosis": {
323
+ followReferences: true
324
+ }
325
+ }
326
+ }
327
+ })
328
+ ```
329
+
330
+ With this rule, `Condition.subject` targeting `KBV_PR_Base_Patient` pulls the Patient profile (and the `Patient`/`Group` resources) into the generated output, including their regular dependencies. Following is **non-transitive**: the pulled-in types keep their own reference targets as plain string literals, so a single flag cannot drag in the whole package. If a followed target is also listed as a tree-shake root, the root's rule wins.
331
+
332
+ To enable it for every tree-shake root at once, use `treeShakeDefaults` (a rule's own `followReferences` still wins over the default):
333
+
334
+ ```typescript
335
+ .typeSchema({
336
+ treeShake: { ... },
337
+ treeShakeDefaults: { followReferences: true }
338
+ })
339
+ ```
340
+
275
341
  #### Logical Model Promotion
276
342
 
277
343
  Some implementation guides expose logical models (logical-kind StructureDefinitions) that are intended to be used like resources in generated SDKs. The code generator supports promoting selected logical models to behave as resources during generation.
@@ -1,5 +1,6 @@
1
1
  from typing import Any, Union, Optional, Iterator, Tuple, Dict
2
2
  from pydantic import BaseModel, Field
3
+ from pydantic_core import PydanticUndefined
3
4
  from typing import Protocol
4
5
 
5
6
 
@@ -22,7 +23,10 @@ class FhirpyBaseModel(BaseModel):
22
23
  def __pydantic_init_subclass__(cls, **kwargs: Any) -> None:
23
24
  super().__pydantic_init_subclass__(**kwargs)
24
25
  field = cls.model_fields.get("resource_type") or cls.model_fields.get("resourceType")
25
- if field is not None and field.default is not None:
26
+ # Only concrete resources carry a default resourceType. Abstract/family base types
27
+ # (Resource, DomainResource) leave it unset, so we skip them to avoid registering a
28
+ # class attribute that concrete subclasses would shadow.
29
+ if field is not None and field.default is not None and field.default is not PydanticUndefined:
26
30
  type.__setattr__(cls, "resourceType", str(field.default))
27
31
 
28
32
  def __iter__(self) -> Iterator[Tuple[str, Any]]: # type: ignore[override]
@@ -1,5 +1,6 @@
1
1
  from typing import Any, Union, Optional, Iterator, Tuple, Dict
2
2
  from pydantic import BaseModel, Field
3
+ from pydantic_core import PydanticUndefined
3
4
  from typing import Protocol
4
5
 
5
6
 
@@ -21,7 +22,10 @@ class FhirpyBaseModel(BaseModel):
21
22
  def __pydantic_init_subclass__(cls, **kwargs: Any) -> None:
22
23
  super().__pydantic_init_subclass__(**kwargs)
23
24
  field = cls.model_fields.get("resource_type") or cls.model_fields.get("resourceType")
24
- if field is not None and field.default is not None:
25
+ # Only concrete resources carry a default resourceType. Abstract/family base types
26
+ # (Resource, DomainResource) leave it unset, so we skip them to avoid registering a
27
+ # class attribute that concrete subclasses would shadow.
28
+ if field is not None and field.default is not None and field.default is not PydanticUndefined:
25
29
  type.__setattr__(cls, "resourceType", str(field.default))
26
30
 
27
31
  def __iter__(self) -> Iterator[Tuple[str, Any]]: # type: ignore[override]
@@ -26,6 +26,8 @@ from __future__ import annotations
26
26
  import copy
27
27
  from typing import Any, Iterable, Mapping, MutableMapping, MutableSequence, Sequence, TypeVar
28
28
 
29
+ from typing_extensions import TypeGuard
30
+
29
31
  T = TypeVar("T")
30
32
 
31
33
  # ---------------------------------------------------------------------------
@@ -33,9 +35,9 @@ T = TypeVar("T")
33
35
  # ---------------------------------------------------------------------------
34
36
 
35
37
 
36
- def is_record(value: Any) -> bool:
38
+ def is_record(value: object) -> TypeGuard[MutableMapping[str, Any]]:
37
39
  """True when ``value`` is a non-None mapping (dict-like, not a list)."""
38
- return isinstance(value, Mapping)
40
+ return isinstance(value, MutableMapping)
39
41
 
40
42
 
41
43
  def ensure_path(root: MutableMapping[str, Any], path: Sequence[str]) -> MutableMapping[str, Any]:
@@ -85,14 +87,14 @@ def apply_slice_match(input_obj: Mapping[str, Any], match: Mapping[str, Any]) ->
85
87
  return result
86
88
 
87
89
 
88
- def _get_key(obj: Any, key: str) -> Any:
90
+ def _get_key(obj: object, key: str) -> Any:
89
91
  """Retrieve ``key`` from a dict-like or Pydantic-model-like object."""
90
92
  if is_record(obj):
91
93
  return obj.get(key)
92
94
  return getattr(obj, key, None)
93
95
 
94
96
 
95
- def _model_get(value: Any, key: str) -> Any:
97
+ def _model_get(value: object, key: str) -> Any:
96
98
  """Get an attribute from a Pydantic model by Python name or field alias.
97
99
 
98
100
  Pydantic stores fields as snake_case attributes but slice match dicts use
@@ -110,7 +112,7 @@ def _model_get(value: Any, key: str) -> Any:
110
112
  return None
111
113
 
112
114
 
113
- def matches_value(value: Any, match: Any) -> bool:
115
+ def matches_value(value: object, match: object) -> bool:
114
116
  """Recursively test whether ``value`` structurally contains everything in
115
117
  ``match``. Lists use "every match item has a corresponding value item"
116
118
  semantics; mappings are matched key-by-key; primitives use ``==``.
@@ -149,7 +151,7 @@ def matches_value(value: Any, match: Any) -> bool:
149
151
  return bool(value == match)
150
152
 
151
153
 
152
- def is_extension(value: Any, url: str | None = None) -> bool:
154
+ def is_extension(value: object, url: str | None = None) -> bool:
153
155
  """True when ``value`` looks like a raw FHIR Extension (has a ``url``).
154
156
  When ``url`` is given, also checks the URL matches.
155
157
  Works with both plain dicts and Pydantic model instances."""
@@ -159,7 +161,7 @@ def is_extension(value: Any, url: str | None = None) -> bool:
159
161
  return url is None or bool(ext_url == url)
160
162
 
161
163
 
162
- def get_extension_value(ext: Any | None, field: str) -> Any:
164
+ def get_extension_value(ext: object | None, field: str) -> Any:
163
165
  """Read a single typed value field from an Extension dict or Pydantic model,
164
166
  returning ``None`` when the extension itself is absent or the field is not set."""
165
167
  if ext is None:
@@ -192,7 +194,7 @@ def push_extension(target: Any, ext: Any) -> None:
192
194
 
193
195
 
194
196
  def extract_complex_extension(
195
- extension: Any | None,
197
+ extension: object | None,
196
198
  config: Sequence[Mapping[str, Any]],
197
199
  ) -> dict[str, Any] | None:
198
200
  """Read a complex (nested) FHIR extension into a plain key/value dict.
@@ -325,7 +327,7 @@ def ensure_profile(resource: Any, canonical_url: str) -> None:
325
327
  profiles.append(canonical_url)
326
328
 
327
329
 
328
- def set_array_slice(lst: MutableSequence[Any], match: Mapping[str, Any], value: Any) -> None:
330
+ def set_array_slice(lst: MutableSequence[Any], match: Mapping[str, Any], value: object) -> None:
329
331
  """Find or insert a slice element. If an element matching ``match``
330
332
  already exists it is replaced in place; otherwise ``value`` is appended."""
331
333
  for i, item in enumerate(lst):
@@ -355,7 +357,7 @@ def get_array_slices(lst: Sequence[Any] | None, match: Mapping[str, Any]) -> lis
355
357
  def set_array_slices(
356
358
  lst: MutableSequence[Any],
357
359
  match: Mapping[str, Any],
358
- values: Sequence[Any],
360
+ values: Sequence[object],
359
361
  ) -> None:
360
362
  """Remove all elements matching ``match``, then append ``values``."""
361
363
  indices = [i for i, item in enumerate(lst) if matches_value(item, match)]
@@ -372,13 +374,13 @@ def set_array_slices(
372
374
  # ---------------------------------------------------------------------------
373
375
 
374
376
 
375
- def _get_field(res: Any, field: str) -> Any:
377
+ def _get_field(res: object, field: str) -> Any:
376
378
  if isinstance(res, Mapping):
377
379
  return res.get(field)
378
380
  return getattr(res, field, None)
379
381
 
380
382
 
381
- def validate_required(res: Any, profile_name: str, field: str) -> list[str]:
383
+ def validate_required(res: object, profile_name: str, field: str) -> list[str]:
382
384
  """Checks that ``field`` is present (not ``None``)."""
383
385
  return (
384
386
  [f"{profile_name}: required field '{field}' is missing"]
@@ -387,7 +389,7 @@ def validate_required(res: Any, profile_name: str, field: str) -> list[str]:
387
389
  )
388
390
 
389
391
 
390
- def validate_must_support(res: Any, profile_name: str, field: str) -> list[str]:
392
+ def validate_must_support(res: object, profile_name: str, field: str) -> list[str]:
391
393
  """Checks that a must-support field is populated (warning, not error)."""
392
394
  return (
393
395
  [f"{profile_name}: must-support field '{field}' is not populated"]
@@ -396,7 +398,7 @@ def validate_must_support(res: Any, profile_name: str, field: str) -> list[str]:
396
398
  )
397
399
 
398
400
 
399
- def validate_excluded(res: Any, profile_name: str, field: str) -> list[str]:
401
+ def validate_excluded(res: object, profile_name: str, field: str) -> list[str]:
400
402
  """Checks that ``field`` is absent."""
401
403
  return (
402
404
  [f"{profile_name}: field '{field}' must not be present"]
@@ -405,7 +407,7 @@ def validate_excluded(res: Any, profile_name: str, field: str) -> list[str]:
405
407
  )
406
408
 
407
409
 
408
- def validate_fixed_value(res: Any, profile_name: str, field: str, expected: Any) -> list[str]:
410
+ def validate_fixed_value(res: object, profile_name: str, field: str, expected: object) -> list[str]:
409
411
  """Checks that ``field`` structurally contains the expected fixed value."""
410
412
  actual = _get_field(res, field)
411
413
  return (
@@ -416,7 +418,7 @@ def validate_fixed_value(res: Any, profile_name: str, field: str, expected: Any)
416
418
 
417
419
 
418
420
  def validate_slice_cardinality(
419
- res: Any,
421
+ res: object,
420
422
  profile_name: str,
421
423
  field: str,
422
424
  match: Mapping[str, Any],
@@ -442,14 +444,48 @@ def validate_slice_cardinality(
442
444
  return errors
443
445
 
444
446
 
445
- def validate_choice_required(res: Any, profile_name: str, choices: Sequence[str]) -> list[str]:
447
+ def validate_slice_fields(
448
+ res: object,
449
+ profile_name: str,
450
+ field: str,
451
+ match: Mapping[str, Any],
452
+ slice_name: str,
453
+ required_fields: Sequence[str],
454
+ ) -> list[str]:
455
+ """Validates required fields within matched slice elements. For each array
456
+ item matching the discriminator, checks that the listed fields are present."""
457
+ items = _get_field(res, field) or []
458
+ if not isinstance(items, Iterable):
459
+ items = []
460
+ errors: list[str] = []
461
+ for item in items:
462
+ if not matches_value(item, match):
463
+ continue
464
+ for rf in required_fields:
465
+ if _get_field(item, rf) is None:
466
+ errors.append(f"{profile_name}.{field}[{slice_name}].{rf} is required")
467
+ return errors
468
+
469
+
470
+ def validate_choice_required(res: object, profile_name: str, choices: Sequence[str]) -> list[str]:
446
471
  """Checks that at least one of the listed choice-type variants is present."""
447
472
  if any(_get_field(res, c) is not None for c in choices):
448
473
  return []
449
474
  return [f"{profile_name}: at least one of {', '.join(choices)} is required"]
450
475
 
451
476
 
452
- def validate_enum(res: Any, profile_name: str, field: str, allowed: Sequence[str]) -> list[str]:
477
+ def validate_choice_prohibited(res: object, profile_name: str, prohibited: Sequence[str]) -> list[str]:
478
+ """Checks that none of the listed prohibited choice-type variants is present.
479
+ E.g. a profile narrowing ``value[x]`` to ``value_quantity`` prohibits every
480
+ other variant."""
481
+ return [
482
+ f"{profile_name}: field '{c}' must not be present"
483
+ for c in prohibited
484
+ if _get_field(res, c) is not None
485
+ ]
486
+
487
+
488
+ def validate_enum(res: object, profile_name: str, field: str, allowed: Sequence[str]) -> list[str]:
453
489
  """Checks that the value of ``field`` has a code within ``allowed``.
454
490
  Handles plain strings, Coding, and CodeableConcept."""
455
491
  value = _get_field(res, field)
@@ -481,7 +517,7 @@ def validate_enum(res: Any, profile_name: str, field: str, allowed: Sequence[str
481
517
  return []
482
518
 
483
519
 
484
- def validate_reference(res: Any, profile_name: str, field: str, allowed: Sequence[str]) -> list[str]:
520
+ def validate_reference(res: object, profile_name: str, field: str, allowed: Sequence[str]) -> list[str]:
485
521
  """Checks that a Reference field points to one of the ``allowed`` resource
486
522
  types. Extracts the type from the ``reference`` string (the part before
487
523
  the first ``/``)."""
@@ -437,6 +437,17 @@ export const validateChoiceRequired = (res: object, profileName: string, choices
437
437
  : [`${profileName}: at least one of ${choices.join(", ")} is required`];
438
438
  };
439
439
 
440
+ /**
441
+ * Checks that none of the listed prohibited choice-type variants is present.
442
+ * E.g. a profile narrowing `value[x]` to `valueAddress` prohibits every other variant.
443
+ */
444
+ export const validateChoiceProhibited = (res: object, profileName: string, prohibited: string[]): string[] => {
445
+ const rec = res as Record<string, unknown>;
446
+ return prohibited
447
+ .filter((c) => rec[c] !== undefined)
448
+ .map((c) => `${profileName}: field '${c}' must not be present`);
449
+ };
450
+
440
451
  /**
441
452
  * Checks that the value of `field` has a code within `allowed`.
442
453
  * Handles plain strings, Coding objects, and CodeableConcept objects.
package/dist/cli/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import T from'picocolors';import Dn from'yargs';import {hideBin}from'yargs/helpers';import {mkdir,writeFile}from'fs/promises';import {dirname}from'path';import Pe from'assert';import {createHash}from'crypto';import {CanonicalManager}from'@atomic-ehr/fhir-canonical-manager';import*as he from'@atomic-ehr/fhirschema';import {isStructureDefinition}from'@atomic-ehr/fhirschema';var ie=e=>{console.log(),console.log(T.cyan(T.bold(`\u2501\u2501\u2501 ${e} \u2501\u2501\u2501`)));},re=(e,n,i)=>{let t=e;if(n&&(t+=` ${T.gray(`(${n}ms)`)}`),console.log(`${T.green("")} ${t}`),i)for(let[r,o]of Object.entries(i))console.log(T.gray(` ${r}: ${o}`));},F=(e,n="\u2022")=>{for(let i of e)console.log(T.gray(` ${n} ${i}`));};var oe={DEBUG:0,INFO:1,WARN:2,ERROR:3,SILENT:4};function k(e={}){let n=e.prefix??"",i=new Set(e.suppressTags??[]),t={},r=[],o=new Set,a=e.level??"INFO",s=p=>oe[p]>=oe[a],c={DEBUG:p=>p,INFO:p=>p,WARN:T.yellow,ERROR:T.red,SILENT:p=>p},l=(p,m,f,y)=>{let h=n?`${n}: `:"",S=y?` ${T.dim(`(${y})`)}`:"";return c[p](`${m} ${h}${f}`)+S},d=(p,m,f,y=false)=>{r.push({level:p,tag:f,message:m,suppressed:y,prefix:n,timestamp:Date.now()});},u=(p,m,f,y=false)=>(...h)=>{let S=h.length===2?h[0]:void 0,x=h.length===2?h[1]:h[0];S&&(t[S]=(t[S]??0)+1);let C=S!==void 0&&i.has(S);if(d(p,x,S,C),!C&&s(p)){if(y){let N=`${p}::${S??""}::${x}`;if(o.has(N))return;o.add(N);}f(l(p,m,x,S));}},g={warn:u("WARN","!",console.warn),dryWarn:u("WARN","!",console.warn,true),info:u("INFO","i",console.log),error:u("ERROR","X",console.error),debug:u("DEBUG","D",console.log),fork(p,m){let f=n?`${n}/${p}`:p,y=[...i,...m?.suppressTags??[]];return k({prefix:f,suppressTags:y,level:m?.level??a})},as(){return g},tagCounts(){return t},printTagSummary(){let p=Object.entries(t);if(p.length===0)return;let m=n?`${n}: `:"",f=p.filter(([h])=>!i.has(h)),y=p.filter(([h])=>i.has(h));if(f.length>0){let h=f.reduce((x,[,C])=>x+C,0),S=f.map(([x,C])=>`${x}: ${C}`).join(", ");console.warn(T.yellow(`! ${m}${h} warnings (${S})`));}if(y.length>0){let h=y.reduce((x,[,C])=>x+C,0),S=y.map(([x,C])=>`${x}: ${C}`).join(", ");console.log(T.dim(`i ${m}${h} suppressed (${S})`));}},buffer(){return r},bufferClear(){r.length=0;}};return g}var b="Use CodeableReference which is not provided by FHIR R4.",Oe="Use Availability which is not provided by FHIR R4.",A={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-manipulation":b,"http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-processing":b,"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":Oe,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":b,"http://hl7.org/fhir/StructureDefinition/specimen-additive":b,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":b,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":b,"http://hl7.org/fhir/StructureDefinition/workflow-reason":b},"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 v(e,n){let i=`${e.name}#${e.version}`,t=A[i]?.[n];if(t)return {shouldSkip:true,reason:t};let r=A[e.name]?.[n];return r?{shouldSkip:true,reason:r}:{shouldSkip:false}}var R=e=>`${e.name}#${e.version}`,ae=e=>`${e.name}@${e.version}`,se=e=>{let n=JSON.stringify(e);return createHash("sha256").update(n).digest("hex").slice(0,16)},ce=(e,n)=>{let i=e.derivation==="constraint"?"constraint":"specialization";return {...e,derivation:i,kind:e.kind,package_meta:e.package_meta||n,name:e.name,url:e.url,base:e.base}};var G=e=>e?.kind==="nested";var E=(...e)=>{let n=e.filter(t=>t!==void 0).flatMap(t=>t.map(r=>[r.url,r]));return n.length===0?void 0:Object.values(Object.fromEntries(n)).sort((t,r)=>t.url.localeCompare(r.url))};var le=e=>[...e.valueFieldTypes??[],...e.profile?[e.profile]:[],...e.subExtensions?.flatMap(n=>n.valueFieldType?[n.valueFieldType]:[])??[]];var pe=(e,n)=>{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||n,name:e.name,url:e.url}};function z(e){let n=e.split("|")[0];return n||e}function Be(e){return e.split("|")[1]}var Me=e=>({package:e.package_meta.name,version:e.package_meta.version,name:e.name,url:e.url});function I(e){let n=Me(e);return e.derivation==="constraint"?{kind:"profile",...n}:e.kind==="primitive-type"?{kind:"primitive-type",...n}:e.kind==="complex-type"?{kind:"complex-type",...n}:e.kind==="resource"?{kind:"resource",...n}:e.kind==="logical"?{kind:"logical",...n}:{kind:"resource",...n}}var je=/[-_]/,_e=/^[a-zA-Z0-9_-]{20,}$/,Ae=e=>{let n=e.split("/"),i=n[n.length-1];return i&&i.length>0?i.split(je).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join(""):e};function L(e,n,i){let t=z(i),r=Ae(t),o={package_meta:{name:"missing_valuesets",version:Be(t)||"0.0.0"},id:i},a=e.resolveVs(n,t)||o,s=a?.id&&!_e.test(a.id)?a.id:r;return {kind:"value-set",package:a.package_meta.name,version:a.package_meta.version,name:s,url:t}}function H(e,n,i){let t=i.binding?.bindingName,r=n.join("."),[o,a,s]=t?[{name:"shared",version:"1.0.0"},t,`urn:fhir:binding:${t}`]:[e.package_meta,`${e.name}.${r}_binding`,`${e.url}#${r}_binding`];return {kind:"binding",package:o.name,version:o.version,name:a,url:s}}function q(e,n,i,t){let r=z(i)||i,o=e.resolveVs(n,r);if(o)return ze(e,o)}function ze(e,n,i){if(n.expansion?.contains)return n.expansion.contains.filter(r=>r.code!==void 0).map(r=>(Pe(r.code),{code:r.code,display:r.display,system:r.system}));let t=[];if(n.compose?.include){for(let r of n.compose.include)if(r.concept)for(let o of r.concept)t.push({system:r.system,code:o.code,display:o.display});else if(r.system&&!r.filter)try{let o=e.resolveAny(r.system);if(o?.concept){let a=(s,c)=>{for(let l of s)t.push({system:c,code:l.code,display:l.display}),l.concept&&a(l.concept,c);};a(o.concept,r.system);}}catch{}}return t.length>0?t:void 0}var de=100,qe=new Set(["UNK"]),W=new Set(["code","Coding","CodeableConcept","CodeableReference","Quantity","string","uri","Duration"]);function K(e,n,i,t){if(!i.binding)return;let r=i.binding.strength,o=i.binding.valueSet;if(!o)return;if(!W.has(i.type??"")){t?.dryWarn("#binding",`eld-11: Binding on non-bindable type '${i.type}' (valueSet: ${o})`);return}if(!(r==="required"||r==="extensible"||r==="preferred"))return;let s=q(e,n.package_meta,o);if(!s||s.length===0)return;let c=s.map(d=>d.code).filter(d=>d&&typeof d=="string"&&d.trim().length>0),l=c.length===1?c[0]:void 0;if(l&&qe.has(l)){t?.dryWarn("#placeholderValueSet",`Value set ${o} only expands to placeholder code '${l}'; skipping enum generation.`);return}if(c.length>de){t?.dryWarn("#largeValueSet",`Value set ${o} has ${c.length} which is more than ${de} codes, which may cause issues with code generation.`);return}if(c.length!==0)return {isOpen:r!=="required",values:c}}function We(e,n,i,t,r){if(!t.binding?.valueSet)return;let o=H(n,i,t),a=L(e,n.package_meta,t.binding.valueSet),s=K(e,n,t,r);return {identifier:o,valueset:a,strength:t.binding.strength,enum:s,dependencies:[a]}}function me(e,n,i){let t=new Set;if(!n.elements)return [];let r=[];function o(c,l){for(let[d,u]of Object.entries(c)){let g=[...l,d],p=g.join("."),m=e.resolveElementSnapshot(n,g);if(!t.has(p)){if(t.add(p),m.binding){let f=We(e,n,g,m,i);f&&r.push(f);}u.elements&&o(u.elements,g);}}}o(n.elements,[]),r.sort((c,l)=>c.identifier.name.localeCompare(l.identifier.name));let a=[],s=new Set;for(let c of r)s.has(c.identifier.url)||(s.add(c.identifier.url),a.push(c));return a}var Ke=/(?<=[a-z])(?=[A-Z])|[-_.\s]/,Ye=e=>e.split(Ke).filter(Boolean);var Je=e=>{if(e.length===0)throw new Error("Empty string");return e[0]?.toUpperCase()+e.substring(1).toLowerCase()},ue=e=>{if(e.length===0)throw new Error("Empty string");let[n,...i]=Ye(e);return [n?.toLowerCase(),...i.map(Je)].join("")};var Y=e=>!e||e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1);var Ze=e=>{let n=e.replace(/\[x\]/g,"").replace(/[- :.]/g,"_");return n?Y(n):""},w=e=>{let n=e.replace(/\[x\]/g,"").replace(/:/g,"_");return n?Y(ue(n)):""},Qe=(e,n)=>{let i=w(e)||"Extension",t=n.split(".").filter(a=>a&&a!=="extension").join("_"),o=`${t?w(t):""}${i}`;return [i,o,`${o}Extension`]},Xe=(e,n)=>{let i=Ze(n)||"Slice",r=`${w(e)||"Field"}${i}`;return [i,r,`${r}Slice`]},en=(e,n,i)=>e.reduce((t,r)=>{let o=r.candidates[n]??"";return t[o]=(t[o]??0)+1,i.has(o)&&(t[o]=(t[o]??0)+1),t},{}),nn=(e,n)=>{let i=e[0]?.candidates.length??0,t=(r,o)=>{if(r.length===0||o>=i)return {};let a=en(r,o,n),s=o>=i-1,[c,l]=r.reduce(([d,u],g)=>{let p=g.candidates[o]??"";return (a[p]??0)>1&&!s?[d,[...u,g]]:[{...d,[g.key]:p},u]},[{},[]]);return {...c,...t(l,o+1)}};return t(e,0)},fe=e=>({candidates:Qe(e.name,e.path),recommended:""}),ge=(e,n)=>({candidates:Xe(e,n),recommended:""}),ye=e=>{let n=(e.extensions??[]).filter(a=>a.url).map(a=>({key:`ext:${a.url}:${a.path}`,candidates:a.nameCandidates.candidates})),i=Object.entries(e.fields??{}).flatMap(([a,s])=>!("slicing"in s)||!s.slicing?.slices?[]:Object.entries(s.slicing.slices).map(([c,l])=>({key:`slice:${a}:${c}`,candidates:l.nameCandidates.candidates}))),t=new Set(Object.keys(e.fields??{}).map(w)),r=[...n,...i];if(r.length===0)return;let o=nn(r,t);for(let a of e.extensions??[]){if(!a.url)continue;let s=`ext:${a.url}:${a.path}`;o[s]&&(a.nameCandidates.recommended=o[s]);}for(let[a,s]of Object.entries(e.fields??{}))if(!(!("slicing"in s)||!s.slicing?.slices))for(let[c,l]of Object.entries(s.slicing.slices)){let d=`slice:${a}:${c}`;o[d]&&(l.nameCandidates.recommended=o[d]);}};var J=e=>e!==null&&typeof e=="object"&&e.resourceType==="CodeSystem";var U=e=>e!==null&&typeof e=="object"&&e.resourceType==="ValueSet";var rn=/^[a-zA-Z0-9]+$/,on=async(e,n)=>{let i=await e.packageJson(n.name);if(!i)return [];let t=i.dependencies;return t!==void 0?Object.entries(t).map(([r,o])=>({name:r,version:o})):[]},Se=e=>({pkg:e,canonicalResolution:{},fhirSchemas:{},valueSets:{}}),Re=async(e,n,i,t,r)=>{let o=R(n);if(r?.info(`${" ".repeat(i*2)}+ ${o}`),t[o])return t[o];let a=Se(n);t[o]=a;for(let c of await e.search({package:n})){let l=c.url;if(!l||!(isStructureDefinition(c)||U(c)||J(c)))continue;let d=l;a.canonicalResolution[d]&&r?.dryWarn("#duplicateCanonical",`Duplicate canonical URL: ${d} at ${o}.`),a.canonicalResolution[d]=[{deep:i,pkg:n,pkgId:o,resource:c}];}let s=await on(e,n);for(let c of s){let{canonicalResolution:l}=await Re(e,c,i+1,t,r);for(let[d,u]of Object.entries(l)){let g=d;a.canonicalResolution[g]=[...a.canonicalResolution[g]||[],...u];}}for(let c of Object.values(a.canonicalResolution))c.sort((l,d)=>l.deep-d.deep);return a},an=(e,n)=>{for(let{pkg:i,canonicalResolution:t}of Object.values(e)){let r=R(i);if(!e[r])throw new Error(`Package ${r} not found`);let o=0;n?.info(`FHIR Schema conversion for '${R(i)}' begins...`);for(let[a,s]of Object.entries(t)){let c=s[0];if(!c)throw new Error("Resource not found");let l=c.resource,d=c.pkg;if(isStructureDefinition(l)){let u=he.translate(l),g=ce(u,d);o++,e[r].fhirSchemas[g.url]=g;}if(U(l)){let u=pe(l,d);e[r].valueSets[u.url]=u;}}n?.info(`FHIR Schema conversion for '${R(i)}' completed: ${o} successful`);}},sn=(e,n,i)=>{let t=Object.values(e).flatMap(r=>r.canonicalResolution[n]);if(!t)throw new Error(`No canonical resolution found for ${n} in any package`);return t[0]?.resource},cn=async(e,{logger:n,focusedPackages:i})=>{let t=i??await e.packages(),r={};for(let p of t)await Re(e,p,0,r,n);an(r,n);let o=(p,m)=>{let f=r[R(p)];if(f){let y=f.canonicalResolution[m]?.[0];if(y)return r[y.pkgId]?.fhirSchemas[m]}for(let y of Object.values(r)){let h=y.fhirSchemas[m];if(h&&h.package_meta.name===p.name)return h}for(let y of Object.values(r)){let h=y.fhirSchemas[m];if(h)return h}},a=(p,m)=>{let f=r[R(p)];if(f){let y=f.canonicalResolution[m]?.[0];if(y)return r[y.pkgId]?.valueSets[m]}for(let y of Object.values(r)){let h=y.valueSets[m];if(h&&h.package_meta.name===p.name)return h}for(let y of Object.values(r)){let h=y.valueSets[m];if(h)return h}},s=p=>(p.includes("|")&&(p=p.split("|")[0]),rn.test(p)?`http://hl7.org/fhir/StructureDefinition/${p}`:p),c=(p,m)=>{let f=o(p,m);if(f===void 0)throw new Error(`Failed to resolve FHIR Schema: '${m}'`);let y=[f];for(;f?.base;){let h=f.package_meta,S=s(f.base);if(f=o(h,S),f===void 0)throw new Error(`Failed to resolve FHIR Schema base for '${m}'. Problem: '${S}' from '${R(h)}'`);y.push(f);}return y},l=(p,m)=>c(p,m).filter(f=>f.derivation==="specialization"),d=(p,m)=>{let f=c(p.package_meta,p.url),y=O(f,m);return Z(y)},u=p=>{let m=new Set;for(let[f,y]of Object.entries(p)){m.add(f);for(let h of y?.choices||[])p[h]||m.add(h);}return Array.from(m)},g;return {testAppendFs(p){let m=R(p.package_meta);r[m]||(r[m]=Se(p.package_meta)),r[m].fhirSchemas[p.url]=p,g=void 0;},resolveFs:o,resolveFsGenealogy:c,resolveFsSpecializations:l,ensureSpecializationCanonicalUrl:s,resolveSd:(p,m)=>{let f=r[R(p)]?.canonicalResolution[m]?.[0]?.resource;if(isStructureDefinition(f))return f},allSd:()=>Object.values(r).flatMap(p=>Object.values(p.canonicalResolution).flatMap(m=>m.map(f=>{let y=f.resource;return y.package_name?y:{...y,package_name:p.pkg.name,package_version:p.pkg.version}}))).filter(p=>isStructureDefinition(p)).sort((p,m)=>p.url.localeCompare(m.url)),allFs:()=>Object.values(r).flatMap(p=>Object.values(p.fhirSchemas)),allVs:()=>Object.values(r).flatMap(p=>Object.values(p.valueSets)),resolveVs:a,resolveAny:p=>sn(r,p),resolveElementSnapshot:d,getAllElementKeys:u,resolver:r,resolutionTree:()=>{if(g)return g;let p={};for(let[m,f]of Object.entries(r)){let y=f.pkg.name;p[y]={};for(let[h,S]of Object.entries(f.canonicalResolution)){let x=h;p[y][x]=[];for(let C of S)p[y][x].push({deep:C.deep,pkg:C.pkg});}}return g=p,p}}},xe=async(e,n)=>{let i=e.map(ae);n?.logger?.info(`Loading FHIR packages: ${i.join(", ")}`);let t=CanonicalManager({packages:i,workingDir:".codegen-cache/canonical-manager-cache",registry:n.registry||void 0});return await t.init(),await cn(t,{...n,focusedPackages:e})},O=(e,n)=>{let[i,...t]=n;return i===void 0?[]:e.map(r=>{if(!r.elements)return;let o=r.elements?.[i];for(let a of t)o=o?.elements?.[a];return o}).filter(r=>r!==void 0)};function Z(e){let n=e.reverse(),i=Object.assign({},...n);return i.elements=void 0,i}var Ce=(e,n,i)=>{let t=e.resolveFsSpecializations(n.package_meta,n.url),r=O(t,i),o=Z(r).type,a;if(o){let s=e.ensureSpecializationCanonicalUrl(o),l=e.resolveFsGenealogy(n.package_meta,s).flatMap(d=>Object.keys(d.elements??{}));l.length>0&&(a=new Set(l));}for(let s of r)if(!(!s.elements||Object.keys(s.elements).length===0)&&!(a&&!Object.keys(s.elements).some(c=>!a.has(c))))return true;return false},Q=(e,n,i,t,r)=>t.type==="BackboneElement"?true:!r?.elements||r.choiceOf!==void 0?false:Ce(e,n,i),ln=e=>e.elements?new Set(X(e,[],e.elements).filter(([n,i])=>i.elements&&Object.keys(i.elements).length>0).map(([n])=>n.join("."))):new Set;function V(e,n,i){let t={},r=n.derivation==="constraint"?e.resolveFsSpecializations(n.package_meta,n.url):e.resolveFsGenealogy(n.package_meta,n.url);for(let d of [...r].reverse()){let u=ln(d);for(let g of u)t[g]=`${d.url}#${g}`;}let o=i.join("."),a=t[o]??`${n.url}#${o}`,s=a.split("#")[0],l=e.resolveFs(n.package_meta,s)?.package_meta??n.package_meta;return {kind:"nested",package:l.name,version:l.version,name:o,url:a}}function X(e,n,i){let t=[];for(let[r,o]of Object.entries(i)){let a=[...n,r];o.elements&&o.choiceOf===void 0&&t.push([a,o]),o.elements&&t.push(...X(e,a,o.elements));}return t}function pn(e,n,i,t,r){let o={},a=e.resolveFsGenealogy(n.package_meta,n.url),s=O(a,i),c=new Set;for(let l of s)if(l.elements)for(let d of Object.keys(l.elements))c.add(d);for(let l of c){let d=[...i,l],u=e.resolveElementSnapshot(n,d);Q(e,n,d,u,t[l])?o[l]=M(e,n,d,u):o[l]=B(e,n,d,u,r);}return o}function ke(e,n,i){if(!n.elements)return;let t=X(n,[],n.elements).filter(([o,a])=>!a.elements||Object.keys(a.elements).length===0?false:a.type!=="BackboneElement"?Ce(e,n,o):true),r=[];for(let[o,a]of t){let s=V(e,n,o),c;a.type==="BackboneElement"||!a.type?c="BackboneElement":c=a.type;let l=e.ensureSpecializationCanonicalUrl(c),d=e.resolveFs(n.package_meta,l);if(!d)throw new Error(`Could not resolve base type ${c}`);let u={kind:"complex-type",package:d.package_meta.name,version:d.package_meta.version,name:c,url:l},g=pn(e,n,o,a.elements??{},i),p={identifier:s,base:u,fields:g};r.push(p);}return r.sort((o,a)=>o.identifier.url.localeCompare(a.identifier.url)),r.length===0?void 0:r}function Ie(e){let n=[];for(let i of e){i.base&&n.push(i.base);for(let t of Object.values(i.fields||{}))"type"in t&&t.type&&n.push(t.type),"binding"in t&&t.binding&&n.push(t.binding);}return n}var dn=new Set(["Availability","CodeableReference","ExtendedContactDetail","MonetaryComponent","RatioRange","VirtualServiceDetail"]),mn=(e,n)=>{let i=e.resolver[R(n)];if(!i)return false;for(let t of Object.values(i.canonicalResolution))for(let r of t)if(r.pkg.name==="hl7.fhir.r4.core")return true;return false},un=(e,n,i)=>!dn.has(i)||!mn(e,n)?"":`
2
+ import F from'picocolors';import $n from'yargs';import {hideBin}from'yargs/helpers';import {mkdir,writeFile}from'fs/promises';import {dirname}from'path';import we from'assert';import {createHash}from'crypto';import {CanonicalManager}from'@atomic-ehr/fhir-canonical-manager';import*as Ie from'@atomic-ehr/fhirschema';import {isStructureDefinition}from'@atomic-ehr/fhirschema';var se=e=>{console.log(),console.log(F.cyan(F.bold(`\u2501\u2501\u2501 ${e} \u2501\u2501\u2501`)));},ae=(e,n,i)=>{let t=e;if(n&&(t+=` ${F.gray(`(${n}ms)`)}`),console.log(`${F.green("")} ${t}`),i)for(let[r,o]of Object.entries(i))console.log(F.gray(` ${r}: ${o}`));},T=(e,n="\u2022")=>{for(let i of e)console.log(F.gray(` ${n} ${i}`));};var ce={DEBUG:0,INFO:1,WARN:2,ERROR:3,SILENT:4};function I(e={}){let n=e.prefix??"",i=new Set(e.suppressTags??[]),t={},r=[],o=new Set,s=e.level??"INFO",a=d=>ce[d]>=ce[s],c={DEBUG:d=>d,INFO:d=>d,WARN:F.yellow,ERROR:F.red,SILENT:d=>d},l=(d,u,f,y)=>{let h=n?`${n}: `:"",S=y?` ${F.dim(`(${y})`)}`:"";return c[d](`${u} ${h}${f}`)+S},p=(d,u,f,y=false)=>{r.push({level:d,tag:f,message:u,suppressed:y,prefix:n,timestamp:Date.now()});},m=(d,u,f,y=false)=>(...h)=>{let S=h.length===2?h[0]:void 0,x=h.length===2?h[1]:h[0];S&&(t[S]=(t[S]??0)+1);let C=S!==void 0&&i.has(S);if(p(d,x,S,C),!C&&a(d)){if(y){let N=`${d}::${S??""}::${x}`;if(o.has(N))return;o.add(N);}f(l(d,u,x,S));}},g={warn:m("WARN","!",console.warn),dryWarn:m("WARN","!",console.warn,true),info:m("INFO","i",console.log),error:m("ERROR","X",console.error),debug:m("DEBUG","D",console.log),fork(d,u){let f=n?`${n}/${d}`:d,y=[...i,...u?.suppressTags??[]];return I({prefix:f,suppressTags:y,level:u?.level??s})},as(){return g},tagCounts(){return t},printTagSummary(){let d=Object.entries(t);if(d.length===0)return;let u=n?`${n}: `:"",f=d.filter(([h])=>!i.has(h)),y=d.filter(([h])=>i.has(h));if(f.length>0){let h=f.reduce((x,[,C])=>x+C,0),S=f.map(([x,C])=>`${x}: ${C}`).join(", ");console.warn(F.yellow(`! ${u}${h} warnings (${S})`));}if(y.length>0){let h=y.reduce((x,[,C])=>x+C,0),S=y.map(([x,C])=>`${x}: ${C}`).join(", ");console.log(F.dim(`i ${u}${h} suppressed (${S})`));}},buffer(){return r},bufferClear(){r.length=0;}};return g}var L=(e,n)=>e<n?-1:e>n?1:0,z=(e,n)=>L(e.sourcePackage,n.sourcePackage)||L(e.sourceCanonical,n.sourceCanonical),le=e=>JSON.stringify([...e].sort(z).map(({sourcePackage:n,sourceCanonical:i})=>[n,i])),pe=(e,n)=>n.sources.length-e.sources.length||L(le(e.sources),le(n.sources))||L(e.schemaHash,n.schemaHash);var b="Use CodeableReference which is not provided by FHIR R4.",_e="Use Availability which is not provided by FHIR R4.",q={"hl7.fhir.uv.extensions.r4":{"http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-manipulation":b,"http://hl7.org/fhir/StructureDefinition/biologicallyderivedproduct-processing":b,"http://hl7.org/fhir/StructureDefinition/extended-contact-availability":_e,"http://hl7.org/fhir/StructureDefinition/immunization-procedure":b,"http://hl7.org/fhir/StructureDefinition/specimen-additive":b,"http://hl7.org/fhir/StructureDefinition/workflow-barrier":b,"http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor":b,"http://hl7.org/fhir/StructureDefinition/workflow-reason":b},"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 v(e,n){let i=`${e.name}#${e.version}`,t=q[i]?.[n];if(t)return {shouldSkip:true,reason:t};let r=q[e.name]?.[n];return r?{shouldSkip:true,reason:r}:{shouldSkip:false}}var R=e=>`${e.name}#${e.version}`,de=e=>`${e.name}@${e.version}`,me=e=>{let n=JSON.stringify(e);return createHash("sha256").update(n).digest("hex").slice(0,16)},ue=(e,n)=>{let i=e.derivation==="constraint"?"constraint":"specialization";return {...e,derivation:i,kind:e.kind,package_meta:e.package_meta||n,name:e.name,url:e.url,base:e.base}};var W=e=>e?.kind==="nested",fe=e=>e?.kind==="profile";var E=(...e)=>{let n=e.filter(t=>t!==void 0).flatMap(t=>t.map(r=>[r.url,r]));return n.length===0?void 0:Object.values(Object.fromEntries(n)).sort((t,r)=>t.url.localeCompare(r.url))};var ge=e=>[...e.valueFieldTypes??[],...e.profile?[e.profile]:[],...e.subExtensions?.flatMap(n=>n.valueFieldType?[n.valueFieldType]:[])??[]];var ye=(e,n)=>{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||n,name:e.name,url:e.url}};function K(e){let n=e.split("|")[0];return n||e}function Ge(e){return e.split("|")[1]}var ze=e=>({package:e.package_meta.name,version:e.package_meta.version,name:e.name,url:e.url});function k(e){let n=ze(e);return e.derivation==="constraint"?{kind:"profile",...n}:e.kind==="primitive-type"?{kind:"primitive-type",...n}:e.kind==="complex-type"?{kind:"complex-type",...n}:e.kind==="resource"?{kind:"resource",...n}:e.kind==="logical"?{kind:"logical",...n}:{kind:"resource",...n}}var qe=/[-_]/,We=/^[a-zA-Z0-9_-]{20,}$/,Ke=e=>{let n=e.split("/"),i=n[n.length-1];return i&&i.length>0?i.split(qe).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join(""):e};function H(e,n,i){let t=K(i),r=Ke(t),o={package_meta:{name:"missing_valuesets",version:Ge(t)||"0.0.0"},id:i},s=e.resolveVs(n,t)||o,a=s?.id&&!We.test(s.id)?s.id:r;return {kind:"value-set",package:s.package_meta.name,version:s.package_meta.version,name:a,url:t}}function w(e,n,i){let t=i.binding?.bindingName,r=n.join("."),[o,s,a]=t?[{name:"shared",version:"1.0.0"},t,`urn:fhir:binding:${t}`]:[e.package_meta,`${e.name}.${r}_binding`,`${e.url}#${r}_binding`];return {kind:"binding",package:o.name,version:o.version,name:s,url:a}}function Y(e,n,i,t){let r=K(i)||i,o=e.resolveVs(n,r);if(o)return Je(e,o)}function Je(e,n,i){if(n.expansion?.contains)return n.expansion.contains.filter(r=>r.code!==void 0).map(r=>(we(r.code),{code:r.code,display:r.display,system:r.system}));let t=[];if(n.compose?.include){for(let r of n.compose.include)if(r.concept)for(let o of r.concept)t.push({system:r.system,code:o.code,display:o.display});else if(r.system&&!r.filter)try{let o=e.resolveAny(r.system);if(o?.concept){let s=(a,c)=>{for(let l of a)t.push({system:c,code:l.code,display:l.display}),l.concept&&s(l.concept,c);};s(o.concept,r.system);}}catch{}}return t.length>0?t:void 0}var he=100,Ze=new Set(["UNK"]),J=new Set(["code","Coding","CodeableConcept","CodeableReference","Quantity","string","uri","Duration"]);function Z(e,n,i,t){if(!i.binding)return;let r=i.binding.strength,o=i.binding.valueSet;if(!o)return;if(!J.has(i.type??"")){t?.dryWarn("#binding",`eld-11: Binding on non-bindable type '${i.type}' (valueSet: ${o})`);return}if(!(r==="required"||r==="extensible"||r==="preferred"))return;let a=Y(e,n.package_meta,o);if(!a||a.length===0)return;let c=a.map(p=>p.code).filter(p=>p&&typeof p=="string"&&p.trim().length>0),l=c.length===1?c[0]:void 0;if(l&&Ze.has(l)){t?.dryWarn("#placeholderValueSet",`Value set ${o} only expands to placeholder code '${l}'; skipping enum generation.`);return}if(c.length>he){t?.dryWarn("#largeValueSet",`Value set ${o} has ${c.length} which is more than ${he} codes, which may cause issues with code generation.`);return}if(c.length!==0)return {isOpen:r!=="required",values:c}}function Qe(e,n,i,t,r){if(!t.binding?.valueSet)return;let o=w(n,i,t),s=H(e,n.package_meta,t.binding.valueSet),a=Z(e,n,t,r);return {identifier:o,valueset:s,strength:t.binding.strength,enum:a,dependencies:[s]}}function Se(e,n,i){let t=new Set;if(!n.elements)return [];let r=[];function o(c,l){for(let[p,m]of Object.entries(c)){let g=[...l,p],d=g.join("."),u=e.resolveElementSnapshot(n,g);if(!t.has(d)){if(t.add(d),u.binding){let f=Qe(e,n,g,u,i);f&&r.push(f);}m.elements&&o(m.elements,g);}}}o(n.elements,[]),r.sort((c,l)=>c.identifier.name.localeCompare(l.identifier.name));let s=[],a=new Set;for(let c of r)a.has(c.identifier.url)||(a.add(c.identifier.url),s.push(c));return s}var Xe=/(?<=[a-z])(?=[A-Z])|[-_.\s]/,en=e=>e.split(Xe).filter(Boolean);var nn=e=>{if(e.length===0)throw new Error("Empty string");return e[0]?.toUpperCase()+e.substring(1).toLowerCase()},Re=e=>{if(e.length===0)throw new Error("Empty string");let[n,...i]=en(e);return [n?.toLowerCase(),...i.map(nn)].join("")};var Q=e=>!e||e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1);var tn=e=>{let n=e.replace(/\[x\]/g,"").replace(/[- :.]/g,"_");return n?Q(n):""},U=e=>{let n=e.replace(/\[x\]/g,"").replace(/:/g,"_");return n?Q(Re(n)):""},rn=(e,n)=>{let i=U(e)||"Extension",t=n.split(".").filter(s=>s&&s!=="extension").join("_"),o=`${t?U(t):""}${i}`;return [i,o,`${o}Extension`]},on=(e,n)=>{let i=tn(n)||"Slice",r=`${U(e)||"Field"}${i}`;return [i,r,`${r}Slice`]},sn=(e,n,i)=>e.reduce((t,r)=>{let o=r.candidates[n]??"";return t[o]=(t[o]??0)+1,i.has(o)&&(t[o]=(t[o]??0)+1),t},{}),an=(e,n)=>{let i=e[0]?.candidates.length??0,t=(r,o)=>{if(r.length===0||o>=i)return {};let s=sn(r,o,n),a=o>=i-1,[c,l]=r.reduce(([p,m],g)=>{let d=g.candidates[o]??"";return (s[d]??0)>1&&!a?[p,[...m,g]]:[{...p,[g.key]:d},m]},[{},[]]);return {...c,...t(l,o+1)}};return t(e,0)},xe=e=>({candidates:rn(e.name,e.path),recommended:""}),Ce=(e,n)=>({candidates:on(e,n),recommended:""}),ke=e=>{let n=(e.extensions??[]).filter(s=>s.url).map(s=>({key:`ext:${s.url}:${s.path}`,candidates:s.nameCandidates.candidates})),i=Object.entries(e.slicing??{}).flatMap(([s,a])=>a.slices?Object.entries(a.slices).map(([c,l])=>({key:`slice:${s}:${c}`,candidates:l.nameCandidates.candidates})):[]),t=new Set(Object.keys(e.fields??{}).map(U)),r=[...n,...i];if(r.length===0)return;let o=an(r,t);for(let s of e.extensions??[]){if(!s.url)continue;let a=`ext:${s.url}:${s.path}`;o[a]&&(s.nameCandidates.recommended=o[a]);}for(let[s,a]of Object.entries(e.slicing??{}))if(a.slices)for(let[c,l]of Object.entries(a.slices)){let p=`slice:${s}:${c}`;o[p]&&(l.nameCandidates.recommended=o[p]);}};var X=e=>e!==null&&typeof e=="object"&&e.resourceType==="CodeSystem";var $=e=>e!==null&&typeof e=="object"&&e.resourceType==="ValueSet";var ln=/^[a-zA-Z0-9]+$/,pn=async(e,n)=>{let i=await e.packageJson(n.name);if(!i)return [];let t=i.dependencies;return t!==void 0?Object.entries(t).map(([r,o])=>({name:r,version:o})):[]},be=e=>({pkg:e,canonicalResolution:{},fhirSchemas:{},valueSets:{}}),Fe=async(e,n,i,t,r)=>{let o=R(n);if(r?.info(`${" ".repeat(i*2)}+ ${o}`),t[o])return t[o];let s=be(n);t[o]=s;for(let c of await e.search({package:n})){let l=c.url;if(!l||!(isStructureDefinition(c)||$(c)||X(c)))continue;let p=l;s.canonicalResolution[p]&&r?.dryWarn("#duplicateCanonical",`Duplicate canonical URL: ${p} at ${o}.`),s.canonicalResolution[p]=[{deep:i,pkg:n,pkgId:o,resource:c}];}let a=await pn(e,n);for(let c of a){let{canonicalResolution:l}=await Fe(e,c,i+1,t,r);for(let[p,m]of Object.entries(l)){let g=p;s.canonicalResolution[g]=[...s.canonicalResolution[g]||[],...m];}}for(let c of Object.values(s.canonicalResolution))c.sort((l,p)=>l.deep-p.deep);return s},dn=(e,n)=>{for(let{pkg:i,canonicalResolution:t}of Object.values(e)){let r=R(i);if(!e[r])throw new Error(`Package ${r} not found`);let o=0;n?.info(`FHIR Schema conversion for '${R(i)}' begins...`);for(let[s,a]of Object.entries(t)){let c=a[0];if(!c)throw new Error("Resource not found");let l=c.resource,p=c.pkg;if(isStructureDefinition(l)){let m=Ie.translate(l),g=ue(m,p);o++,e[r].fhirSchemas[g.url]=g;}if($(l)){let m=ye(l,p);e[r].valueSets[m.url]=m;}}n?.info(`FHIR Schema conversion for '${R(i)}' completed: ${o} successful`);}},mn=(e,n,i)=>{let t=Object.values(e).flatMap(r=>r.canonicalResolution[n]);if(!t)throw new Error(`No canonical resolution found for ${n} in any package`);return t[0]?.resource},un=async(e,{logger:n,focusedPackages:i})=>{let t=i??await e.packages(),r={};for(let d of t)await Fe(e,d,0,r,n);dn(r,n);let o=(d,u)=>{let f=r[R(d)];if(f){let y=f.canonicalResolution[u]?.[0];if(y)return r[y.pkgId]?.fhirSchemas[u]}for(let y of Object.values(r)){let h=y.fhirSchemas[u];if(h&&h.package_meta.name===d.name)return h}for(let y of Object.values(r)){let h=y.fhirSchemas[u];if(h)return h}},s=(d,u)=>{let f=r[R(d)];if(f){let y=f.canonicalResolution[u]?.[0];if(y)return r[y.pkgId]?.valueSets[u]}for(let y of Object.values(r)){let h=y.valueSets[u];if(h&&h.package_meta.name===d.name)return h}for(let y of Object.values(r)){let h=y.valueSets[u];if(h)return h}},a=d=>(d.includes("|")&&(d=d.split("|")[0]),ln.test(d)?`http://hl7.org/fhir/StructureDefinition/${d}`:d),c=(d,u)=>{let f=o(d,u);if(f===void 0)throw new Error(`Failed to resolve FHIR Schema: '${u}'`);let y=[f];for(;f?.base;){let h=f.package_meta,S=a(f.base);if(f=o(h,S),f===void 0)throw new Error(`Failed to resolve FHIR Schema base for '${u}'. Problem: '${S}' from '${R(h)}'`);y.push(f);}return y},l=(d,u)=>c(d,u).filter(f=>f.derivation==="specialization"),p=(d,u)=>{let f=c(d.package_meta,d.url),y=O(f,u);return ee(y)},m=d=>{let u=new Set;for(let[f,y]of Object.entries(d)){u.add(f);for(let h of y?.choices||[])d[h]||u.add(h);}return Array.from(u)},g;return {testAppendFs(d){let u=R(d.package_meta);r[u]||(r[u]=be(d.package_meta)),r[u].fhirSchemas[d.url]=d,g=void 0;},resolveFs:o,resolveFsGenealogy:c,resolveFsSpecializations:l,ensureSpecializationCanonicalUrl:a,resolveSd:(d,u)=>{let f=r[R(d)]?.canonicalResolution[u]?.[0]?.resource;if(isStructureDefinition(f))return f},allSd:()=>Object.values(r).flatMap(d=>Object.values(d.canonicalResolution).flatMap(u=>u.map(f=>{let y=f.resource;return y.package_name?y:{...y,package_name:f.pkg.name,package_version:f.pkg.version}}))).filter(d=>isStructureDefinition(d)).sort((d,u)=>d.url.localeCompare(u.url)),allFs:()=>Object.values(r).flatMap(d=>Object.values(d.fhirSchemas)),allVs:()=>Object.values(r).flatMap(d=>Object.values(d.valueSets)),resolveVs:s,resolveAny:d=>mn(r,d),resolveElementSnapshot:p,getAllElementKeys:m,resolver:r,resolutionTree:()=>{if(g)return g;let d={};for(let[u,f]of Object.entries(r)){let y=f.pkg.name;d[y]={};for(let[h,S]of Object.entries(f.canonicalResolution)){let x=h;d[y][x]=[];for(let C of S)d[y][x].push({deep:C.deep,pkg:C.pkg});}}return g=d,d}}},Te=async(e,n)=>{let i=e.map(de);n?.logger?.info(`Loading FHIR packages: ${i.join(", ")}`);let t=CanonicalManager({packages:i,workingDir:".codegen-cache/canonical-manager-cache",registry:n.registry||void 0});return await t.init(),await un(t,{...n,focusedPackages:e})},O=(e,n)=>{let[i,...t]=n;return i===void 0?[]:e.map(r=>{if(!r.elements)return;let o=r.elements?.[i];for(let s of t)o=o?.elements?.[s];return o}).filter(r=>r!==void 0)};function ee(e){let n=e.reverse(),i=Object.assign({},...n);return i.elements=void 0,i}var ve=(e,n,i)=>{let t=e.resolveFsSpecializations(n.package_meta,n.url),r=O(t,i),o=ee(r).type,s;if(o){let a=e.ensureSpecializationCanonicalUrl(o),l=e.resolveFsGenealogy(n.package_meta,a).flatMap(p=>Object.keys(p.elements??{}));l.length>0&&(s=new Set(l));}for(let a of r)if(!(!a.elements||Object.keys(a.elements).length===0)&&!(s&&!Object.keys(a.elements).some(c=>!s.has(c))))return true;return false},ne=(e,n,i,t,r)=>t.type==="BackboneElement"?true:!r?.elements||r.choiceOf!==void 0?false:ve(e,n,i),fn=e=>e.elements?new Set(te(e,[],e.elements).filter(([n,i])=>i.elements&&Object.keys(i.elements).length>0).map(([n])=>n.join("."))):new Set;function B(e,n,i){let t={},r=n.derivation==="constraint"?e.resolveFsSpecializations(n.package_meta,n.url):e.resolveFsGenealogy(n.package_meta,n.url);for(let p of [...r].reverse()){let m=fn(p);for(let g of m)t[g]=`${p.url}#${g}`;}let o=i.join("."),s=t[o]??`${n.url}#${o}`,a=s.split("#")[0],l=e.resolveFs(n.package_meta,a)?.package_meta??n.package_meta;return {kind:"nested",package:l.name,version:l.version,name:o,url:s}}function te(e,n,i){let t=[];for(let[r,o]of Object.entries(i)){let s=[...n,r];o.elements&&o.choiceOf===void 0&&t.push([s,o]),o.elements&&t.push(...te(e,s,o.elements));}return t}function gn(e,n,i,t,r){let o={},s={},a=e.resolveFsGenealogy(n.package_meta,n.url),c=O(a,i),l=new Set;for(let p of c)if(p.elements)for(let m of Object.keys(p.elements))l.add(m);for(let p of l){let m=[...i,p],g=e.resolveElementSnapshot(n,m);ne(e,n,m,g,t[p])?o[p]=_(e,n,m,g):o[p]=j(e,n,m,g,r);let d=M(p,g);d&&(s[p]=d);}return {fields:o,slicing:Object.keys(s).length>0?s:void 0}}function Ee(e,n,i){if(!n.elements)return;let t=te(n,[],n.elements).filter(([o,s])=>!s.elements||Object.keys(s.elements).length===0?false:s.type!=="BackboneElement"?ve(e,n,o):true),r=[];for(let[o,s]of t){let a=B(e,n,o),c;s.type==="BackboneElement"||!s.type?c="BackboneElement":c=s.type;let l=e.ensureSpecializationCanonicalUrl(c),p=e.resolveFs(n.package_meta,l);if(!p)throw new Error(`Could not resolve base type ${c}`);let m={kind:"complex-type",package:p.package_meta.name,version:p.package_meta.version,name:c,url:l},{fields:g,slicing:d}=gn(e,n,o,s.elements??{},i),u={identifier:a,base:m,fields:g,slicing:d};r.push(u);}return r.sort((o,s)=>o.identifier.url.localeCompare(s.identifier.url)),r.length===0?void 0:r}function Pe(e){let n=[];for(let i of e){i.base&&n.push(i.base);for(let t of Object.values(i.fields||{}))"type"in t&&t.type&&n.push(t.type),"binding"in t&&t.binding&&n.push(t.binding);}return n}var yn=new Set(["Availability","CodeableReference","ExtendedContactDetail","MonetaryComponent","RatioRange","VirtualServiceDetail"]),hn=(e,n)=>{let i=e.resolver[R(n)];if(!i)return false;for(let t of Object.values(i.canonicalResolution))for(let r of t)if(r.pkg.name==="hl7.fhir.r4.core")return true;return false},Sn=(e,n,i)=>!yn.has(i)||!hn(e,n)?"":`
3
3
  hint: '${i}' is an R5+ type and is not available when generating against R4.
4
- Either skip this canonical via skip-hack.ts, or upgrade the target to R5.`;function be(e,n,i){let t=i[i.length-1];if(!t)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let r=i.slice(0,-1),o=e.resolveFsGenealogy(n.package_meta,n.url).flatMap(a=>{if(r.length===0)return a.required||[];if(!a.elements)return [];let s=a;for(let c of r)s=s?.elements?.[c];return s?.required||[]});return new Set(o).has(t)}function Te(e,n,i){let t=i[i.length-1];if(!t)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let r=i.slice(0,-1),o=e.resolveFsGenealogy(n.package_meta,n.url).flatMap(a=>{if(r.length===0)return a.excluded||[];if(!a.elements)return [];let s=a;for(let c of r)s=s?.elements?.[c];return s?.excluded||[]});return new Set(o).has(t)}var fn=(e,n,i)=>{if(i.refers)return i.refers.map(t=>{let r=e.ensureSpecializationCanonicalUrl(t),o=e.resolveFs(n.package_meta,r);if(!o)throw new Error(`Failed to resolve fs for ${r}`);return I(o)})},gn=e=>{let n=new Set,i=new Set;if(e.required)for(let r of e.required)n.add(r);if(e.excluded)for(let r of e.excluded)i.add(r);if(e.elements)for(let[r,o]of Object.entries(e.elements))o.min!==void 0&&o.min>0&&n.add(r);let t=e.elements?Object.keys(e.elements):void 0;return {required:n.size>0?Array.from(n):void 0,excluded:i.size>0?Array.from(i):void 0,elements:t&&t.length>0?t:void 0}},yn=e=>!e||typeof e=="object"&&Object.keys(e).length===0,j=(e,n,i)=>{let t=e;for(let o=0;o<n.length-1;o++){let a=n[o];(!t[a]||typeof t[a]!="object")&&(t[a]={}),t=t[a];}let r=n[n.length-1];t[r]=i;},hn=(e,n)=>{let i=e;for(let t of n)if(i&&typeof i=="object"&&!Array.isArray(i))i=i[t];else return;return i},Fe=(e,n,i,t,r)=>{if(i>=n.length||!e.elements)return;let o=n[i],a=e.elements[o];if(a){if(i===n.length-1&&a.fixed?.value!==void 0){j(t,n,a.fixed.value);return}if(a.slicing?.slices){r.add(n.slice(0,i+1).join("."));let s=n.slice(i+1);for(let c of Object.values(a.slicing.slices)){if(!c.min||c.min<1||!c.match||typeof c.match!="object")continue;let l=c.match;if(Object.keys(l).length!==0)if(s.length>0){let d=hn(l,s);d!==void 0&&j(t,n,d);}else j(t,n.slice(0,i+1),l);}return}Fe(a,n,i+1,t,r);}},Sn=(e,n,i)=>{if(e==="$this")return;let t=e.split("."),r=n;for(let a of t)if(r=r?.elements?.[a],!r)return;let o=r.type;!o||o.includes("/")||j(i,t,{resourceType:o});},Rn=(e,n)=>{if(!n||!e||e.length===0)return;let i={},t=new Set;for(let r of e)if(r.type==="type")Sn(r.path,n,i);else {if(!n.elements)continue;let o=r.path.split(".");Fe(n,o,0,i,t);}if(Object.keys(i).length!==0){for(let r of t){let o=r.split("."),a=i;for(let c=0;c<o.length-1;c++){let l=a[o[c]];if(!l||typeof l!="object"||Array.isArray(l))break;a=l;}let s=o[o.length-1];a[s]&&typeof a[s]=="object"&&!Array.isArray(a[s])&&(a[s]=[a[s]]);}return i}},ve=(e,n)=>{let i=n.slicing;if(!i)return;let t={};for(let[r,o]of Object.entries(i.slices??{})){if(!o)continue;let{required:a,excluded:s,elements:c}=o.schema?gn(o.schema):{};t[r]={min:o.min,max:o.max,match:yn(o.match)?Rn(i.discriminator??[],o.schema):o.match,required:a,excluded:s,elements:c,nameCandidates:ge(e,r)};}return {discriminator:i.discriminator??[],rules:i.rules,ordered:i.ordered,slices:Object.keys(t).length>0?t:void 0}};function P(e,n,i,t,r){if(t.elementReference){let o=t.elementReference.slice(1).filter((a,s)=>s%2===1);return V(e,n,o)}if(t.type){let o=e.ensureSpecializationCanonicalUrl(t.type),a=e.resolveFs(n.package_meta,o);if(!a){let s=R(n.package_meta),c=i.join("."),l=un(e,n.package_meta,t.type);throw new Error(`Could not resolve field type:
5
- package: ${s}
4
+ Either skip this canonical via skip-hack.ts, or upgrade the target to R5.`;function Ne(e,n,i){let t=i[i.length-1];if(!t)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let r=i.slice(0,-1),o=e.resolveFsGenealogy(n.package_meta,n.url).flatMap(s=>{if(r.length===0)return s.required||[];if(!s.elements)return [];let a=s;for(let c of r)a=a?.elements?.[c];return a?.required||[]});return new Set(o).has(t)}function De(e,n,i){let t=i[i.length-1];if(!t)throw new Error(`Internal error: fieldName is missing for path ${i.join("/")}`);let r=i.slice(0,-1),o=e.resolveFsGenealogy(n.package_meta,n.url).flatMap(s=>{if(r.length===0)return s.excluded||[];if(!s.elements)return [];let a=s;for(let c of r)a=a?.elements?.[c];return a?.excluded||[]});return new Set(o).has(t)}var Rn=(e,n,i)=>{if(!i.refers)return;let t=[],r=[],o=new Set;for(let s of i.refers){let a=e.ensureSpecializationCanonicalUrl(s),c=e.resolveFs(n.package_meta,a);if(!c)throw new Error(`Failed to resolve fs for ${a}`);let l=k(c),p=l;if(fe(l)){r.push(l);let m=e.resolveFsSpecializations(c.package_meta,c.url)[0];if(!m)throw new Error(`Failed to resolve base specialization for ${a}`);p=k(m);}o.has(p.url)||(o.add(p.url),t.push(p));}return {resource:t,profiles:r.length>0?r:void 0}},xn=e=>{let n=new Set,i=new Set;if(e.required)for(let r of e.required)n.add(r);if(e.excluded)for(let r of e.excluded)i.add(r);if(e.elements)for(let[r,o]of Object.entries(e.elements))o.min!==void 0&&o.min>0&&n.add(r);let t=e.elements?Object.keys(e.elements):void 0;return {required:n.size>0?Array.from(n):void 0,excluded:i.size>0?Array.from(i):void 0,elements:t&&t.length>0?t:void 0}},Cn=e=>!e||typeof e=="object"&&Object.keys(e).length===0,A=(e,n,i)=>{let t=e;for(let o=0;o<n.length-1;o++){let s=n[o];(!t[s]||typeof t[s]!="object")&&(t[s]={}),t=t[s];}let r=n[n.length-1];t[r]=i;},kn=(e,n)=>{let i=e;for(let t of n)if(i&&typeof i=="object"&&!Array.isArray(i))i=i[t];else return;return i},Le=(e,n,i,t,r)=>{if(i>=n.length||!e.elements)return;let o=n[i],s=e.elements[o];if(s){if(i===n.length-1&&s.fixed?.value!==void 0){A(t,n,s.fixed.value);return}if(s.slicing?.slices){r.add(n.slice(0,i+1).join("."));let a=n.slice(i+1);for(let c of Object.values(s.slicing.slices)){if(!c.min||c.min<1||!c.match||typeof c.match!="object")continue;let l=c.match;if(Object.keys(l).length!==0)if(a.length>0){let p=kn(l,a);p!==void 0&&A(t,n,p);}else A(t,n.slice(0,i+1),l);}return}Le(s,n,i+1,t,r);}},In=(e,n,i)=>{if(e==="$this")return;let t=e.split("."),r=n;for(let s of t)if(r=r?.elements?.[s],!r)return;let o=r.type;!o||o.includes("/")||A(i,t,{resourceType:o});},bn=(e,n)=>{if(!n||!e||e.length===0)return;let i={},t=new Set;for(let r of e)if(r.type==="type")In(r.path,n,i);else {if(!n.elements)continue;let o=r.path.split(".");Le(n,o,0,i,t);}if(Object.keys(i).length!==0){for(let r of t){let o=r.split("."),s=i;for(let c=0;c<o.length-1;c++){let l=s[o[c]];if(!l||typeof l!="object"||Array.isArray(l))break;s=l;}let a=o[o.length-1];s[a]&&typeof s[a]=="object"&&!Array.isArray(s[a])&&(s[a]=[s[a]]);}return i}},M=(e,n)=>{let i=n.slicing;if(!i)return;let t={};for(let[r,o]of Object.entries(i.slices??{})){if(!o)continue;let{required:s,excluded:a,elements:c}=o.schema?xn(o.schema):{};t[r]={min:o.min,max:o.max,match:Cn(o.match)?bn(i.discriminator??[],o.schema):o.match,required:s,excluded:a,elements:c,nameCandidates:Ce(e,r)};}return {discriminator:i.discriminator??[],rules:i.rules,ordered:i.ordered,slices:Object.keys(t).length>0?t:void 0}};function P(e,n,i,t,r){if(t.elementReference){let o=t.elementReference.slice(1).filter((s,a)=>a%2===1);return B(e,n,o)}if(t.type){let o=e.ensureSpecializationCanonicalUrl(t.type),s=e.resolveFs(n.package_meta,o);if(!s){let a=R(n.package_meta),c=i.join("."),l=Sn(e,n.package_meta,t.type);throw new Error(`Could not resolve field type:
5
+ package: ${a}
6
6
  schema: ${n.url}
7
7
  field: ${c}
8
- type: ${t.type}${l}`)}return I(a)}t.choices||n.derivation!=="constraint"&&r?.dryWarn("#fieldTypeNotFound",`Can't recognize element type: <${n.url}>.${i.join(".")} (pkg: '${R(n.package_meta)}'): missing type info`);}var B=(e,n,i,t,r,o)=>{let a,s;t.binding&&(a=H(n,i,t),W.has(t.type??"")&&(s=K(e,n,t,r)));let c=P(e,n,i,t,r);c||r?.dryWarn("#fieldTypeNotFound",`Field type not found for '${n.url}#${i.join(".")}' (${n.derivation})`);let l;t.pattern?l={kind:"pattern",type:t.pattern.type,value:t.pattern.value}:t.fixed&&(l={kind:"fixed",type:t.fixed.type,value:t.fixed.value});let d=o??t;if(!l&&d.elements?.coding?.slicing?.slices){let u=d.elements.coding.slicing.slices,g=Object.values(u);g.length>0&&g.every(m=>m.min!==void 0&&m.min>=1&&m.match&&typeof m.match=="object"&&Object.keys(m.match).length>0)&&(l={kind:"fixed",type:"CodeableConcept",value:{coding:g.flatMap(f=>f.match?[f.match]:[])}});}return {type:c,required:be(e,n,i),excluded:Te(e,n,i),reference:fn(e,n,t),array:t.array||false,min:t.min,max:t.max,slicing:ve(i[i.length-1]??"",t),choices:t.choices,choiceOf:t.choiceOf,binding:a,enum:s,valueConstraint:l,mustSupport:t.mustSupport}};function M(e,n,i,t){return {type:V(e,n,i),array:t.array||false,required:be(e,n,i),excluded:Te(e,n,i),slicing:ve(i[i.length-1]??"",t)}}var xn=(e,n,i,t)=>{let r=e.resolveFs(n.package_meta,i);if(!r?.elements)return;let o=[];for(let[a,s]of Object.entries(r.elements)){if(s.choiceOf!=="value"&&!a.startsWith("value"))continue;let c=P(e,r,[a],s,t);c&&o.push(c);}return E(o)},Cn=(e,n,i)=>{let t=[];if(!n.elements)return t;for(let[r,o]of Object.entries(n.elements)){if(!r.startsWith("extension:"))continue;let a=r.split(":")[1];if(!a)continue;let s;for(let[c,l]of Object.entries(o.elements??{}))if(!(l.choiceOf!=="value"&&!c.startsWith("value"))&&(s=P(e,n,[r,c],l,i),s))break;t.push({name:a,url:o.url??a,valueFieldType:s,min:o.min,max:o.max!==void 0?String(o.max):void 0});}return t},kn=(e,n,i)=>{let t=[],o=n.elements?.extension?.slicing?.slices;if(!o||typeof o!="object")return t;for(let[a,s]of Object.entries(o)){let c=s,l=c.schema;if(!l)continue;let d;for(let[u,g]of Object.entries(l.elements??{})){let p=g;if(!(p.choiceOf!=="value"&&!u.startsWith("value"))&&(d=P(e,n,[u],p,i),d))break}t.push({name:a,url:c.match?.url??a,valueFieldType:d,min:l._required?1:l.min??0,max:l.max!==void 0?String(l.max):l.array?"*":"1"});}return t},In=(e,n,i,t)=>{let r=e.resolveFs(n.package_meta,i);if(!r?.elements)return;let o=Cn(e,r,t),a=kn(e,r,t),s=[...o,...a];return s.length>0?s:void 0},Ee=(e,n,i)=>{let t=[],r=(c,l,d)=>{let u=d.url,g=u?xn(e,n,u,i):void 0,p=u?In(e,n,u,i):void 0;if(!u){let S=n.elements?.extension?.slicing?.slices?.[l]?.schema;if(S){u=S.elements?.url?.fixed?.value??l;for(let[x,C]of Object.entries(S.elements??{})){let N=C;if(N.choiceOf==="value"||x.startsWith("value")){let te=P(e,n,[x],N,i);if(te){g=[te];break}}}}}let m=p&&p.length>0,f=u?e.resolveFs(n.package_meta,u):void 0,y=f?I(f):void 0,h=[...c,"extension"].join(".");t.push({name:l,path:h,url:u,profile:y,min:d.min,max:d.max!==void 0?String(d.max):void 0,mustSupport:d.mustSupport,valueFieldTypes:g,subExtensions:p,isComplex:m,nameCandidates:fe({name:l,path:h})});},o=(c,l)=>{if(l.extensions)for(let[d,u]of Object.entries(l.extensions))r(c,d,u);if(l.elements)for(let[d,u]of Object.entries(l.elements))o([...c,d],u);};o([],n);let a=new Set,s=t.filter(c=>{let l=`${c.url}:${c.path}`;return a.has(l)?false:(a.add(l),true)});return s.length===0?void 0:s};function bn(e,n,i,t,r){if(!t)return;let o={};for(let a of e.getAllElementKeys(t)){let s=[...i,a],c=e.resolveElementSnapshot(n,s),l=c.type?e.ensureSpecializationCanonicalUrl(c.type):void 0;if(l&&v(n.package_meta,l).shouldSkip){r?.warn("#skipCanonical",`Skipping field ${s} for ${l} due to skip hack ${v(n.package_meta,l).reason}`);continue}Q(e,n,s,c,t[a])?o[a]=M(e,n,s,c):o[a]=B(e,n,s,c,r,t[a]);}return o}function Tn(e){let n=[];for(let i of Object.values(e))"type"in i&&i.type&&n.push(i.type),"binding"in i&&i.binding&&n.push(i.binding);return n}async function De(e,n,i){if(!n.url)throw new Error("ValueSet URL is required");let t=L(e,n.package_meta,n.url),r=q(e,n.package_meta,n.url);return {identifier:t,description:n.description,concept:r,compose:r?void 0:n.compose}}var Le=(e,n,i)=>{let t=[];return e&&t.push(e),n&&t.push(...Tn(n)),i&&t.push(...Ie(i)),t},Ne=(e,n,i,t)=>{let o=Le(n,i,t).filter(a=>!(a.url===e.url||G(a)));return E(o)},Fn=(e,n,i,t)=>{let o=Le(n,i,t).filter(a=>a.url!==e.url);return E(o)};function He(e,n,i){let t;if(n.base){let l=e.resolveFs(n.package_meta,e.ensureSpecializationCanonicalUrl(n.base));if(!l)throw new Error(`Base resource not found '${n.base}' for <${n.url}> from ${R(n.package_meta)}`);let d=I(l);Pe(!G(d),`Unexpected nested base for ${n.url}`),t=d;}let r=bn(e,n,[],n.elements,i),o=ke(e,n,i),a=me(e,n,i);if(n.derivation==="constraint"){let l=I(n);if(!t)throw new Error(`Profile ${n.url} must have a base type`);let d=Ee(e,n,i),u=d?.flatMap(le),g=Fn(l,t,r,o),p={identifier:l,base:t,fields:r,nested:o,description:n.description,dependencies:E(g,u),extensions:d};return ye(p),[p,...a]}if(n.kind==="primitive-type"){let l=I(n);return Pe(t,`Primitive type ${n.url} must have a base type`),[{identifier:l,description:n.description,base:t,dependencies:Ne(l,t,r,o)},...a]}let s=I(n);return [{identifier:s,base:t,fields:r,nested:o,description:n.description,dependencies:Ne(s,t,r,o),typeFamily:void 0},...a]}var vn=(e,n,i)=>{let t={};for(let a of e){let s=`${a.schema.identifier.url}|${a.schema.identifier.package}`,c=se(a.schema);t[s]??={},t[s][c]??={typeSchema:a.schema,sources:[]},t[s][c].sources.push(a);}let r=[],o={};for(let a of Object.values(t)){let s=Object.values(a).sort((l,d)=>d.sources.length-l.sources.length),c=s[0];if(c)if(s.length>1){let l=c.typeSchema.identifier.url,d=c.typeSchema.identifier.package;i?.dryWarn("#duplicateSchema",`'${l}' from '${d}' has ${s.length} versions`),r.push(c.typeSchema);o[d]??={},o[d][l]=s.flatMap(g=>g.sources.map(p=>({typeSchema:g.typeSchema,sourcePackage:p.sourcePackage,sourceCanonical:p.sourceCanonical})));}else r.push(c.typeSchema);}return {schemas:r,collisions:o}},we=async(e,n,i)=>{let t=[];for(let r of e.allFs()){let o=R(r.package_meta),a=v(r.package_meta,r.url);if(a.shouldSkip){i?.dryWarn("#skipCanonical",`Skip ${r.url} from ${o}. Reason: ${a.reason}`);continue}for(let s of He(e,r,i))t.push({schema:s,sourcePackage:o,sourceCanonical:r.url});}for(let r of e.allVs())t.push({schema:await De(e,r),sourcePackage:R(r.package_meta),sourceCanonical:r.url});return vn(t,n,i)};var Ue={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 n=k({prefix:"TypeSchema"});try{n.info("Generating TypeSchema from FHIR packages"),n.info(`Packages: ${e.packages.join(", ")}`),n.info(`Output: ${e.output}`);let i=e.singleFile?"ndjson":e.format;n.debug(`Format: ${i}${e.singleFile&&e.format==="json"?" (forced from json due to singleFile)":""}`),e.treeshake&&e.treeshake.length>0&&n.info(`Treeshaking enabled for ResourceTypes: ${e.treeshake.join(", ")}`),e.singleFile&&n.info("Single file output enabled (NDJSON format)"),e.registry&&n.info(`Using custom registry: ${e.registry}`);let t=Date.now(),r=e.packages.map(d=>{if(d.includes("@")){let u=d.lastIndexOf("@");return {name:d.slice(0,u),version:d.slice(u+1)||"latest"}}return {name:d,version:"latest"}});n.info(`Processing packages: ${r.map(d=>`${d.name}@${d.version}`).join(", ")}`);let o=await xe(r,{logger:n,registry:e.registry,focusedPackages:r}),{schemas:a}=await we(o,void 0,n);if(a.length===0)throw new Error("No schemas were generated from the specified packages");let s=e.output;if(!s)throw new Error("Output format not specified");await mkdir(dirname(s),{recursive:!0});let c;i==="json"?c=JSON.stringify(a,null,2):c=a.map(d=>JSON.stringify(d)).join(`
9
- `),await writeFile(s,c,"utf-8");let l=Date.now()-t;if(re(`Generated ${a.length} TypeSchema definitions`,l,{schemas:a.length}),n.info(`Output: ${s}`),e.verbose){n.debug("Generated schemas:");let d=a.map(u=>`${u.identifier?.name||"Unknown"} (${u.identifier?.kind||"unknown"})`);F(d);}}catch(i){n.error(`Failed to generate TypeSchema: ${i instanceof Error?i.message:String(i)}`),process.exit(1);}}};var ee=k({prefix:"typeschema"}),$e={command:"typeschema [subcommand]",describe:"TypeSchema operations - generate, validate and merge schemas",builder:e=>e.command(Ue).help().example("$0 typeschema generate hl7.fhir.r4.core@4.0.1","Generate TypeSchema from FHIR R4 core package"),handler:e=>{if(!e.subcommand&&e._.length===1){ee.info("Available typeschema subcommands:"),F(["generate Generate TypeSchema files from FHIR packages"]),console.log(`
8
+ type: ${t.type}${l}`)}return k(s)}t.choices||n.derivation!=="constraint"&&r?.dryWarn("#fieldTypeNotFound",`Can't recognize element type: <${n.url}>.${i.join(".")} (pkg: '${R(n.package_meta)}'): missing type info`);}var j=(e,n,i,t,r,o)=>{let s,a;t.binding&&(s=w(n,i,t),J.has(t.type??"")&&(a=Z(e,n,t,r)));let c=P(e,n,i,t,r);c||r?.dryWarn("#fieldTypeNotFound",`Field type not found for '${n.url}#${i.join(".")}' (${n.derivation})`);let l;t.pattern?l={kind:"pattern",type:t.pattern.type,value:t.pattern.value}:t.fixed&&(l={kind:"fixed",type:t.fixed.type,value:t.fixed.value});let p=o??t;if(!l&&p.elements?.coding?.slicing?.slices){let m=p.elements.coding.slicing.slices,g=Object.values(m);g.length>0&&g.every(u=>u.min!==void 0&&u.min>=1&&u.match&&typeof u.match=="object"&&Object.keys(u.match).length>0)&&(l={kind:"fixed",type:"CodeableConcept",value:{coding:g.flatMap(f=>f.match?[f.match]:[])}});}return {type:c,required:Ne(e,n,i),excluded:De(e,n,i),reference:Rn(e,n,t),array:t.array||false,min:t.min,max:t.max,choices:t.choices,choiceOf:t.choiceOf,binding:s,enum:a,valueConstraint:l,mustSupport:t.mustSupport}};function _(e,n,i,t){return {type:B(e,n,i),array:t.array||false,required:Ne(e,n,i),excluded:De(e,n,i)}}var Fn=(e,n,i,t)=>{let r=e.resolveFs(n.package_meta,i);if(!r?.elements)return;let o=[];for(let[s,a]of Object.entries(r.elements)){if(a.choiceOf!=="value"&&!s.startsWith("value"))continue;let c=P(e,r,[s],a,t);c&&o.push(c);}return E(o)},Tn=(e,n,i)=>{let t=[];if(!n.elements)return t;for(let[r,o]of Object.entries(n.elements)){if(!r.startsWith("extension:"))continue;let s=r.split(":")[1];if(!s)continue;let a;for(let[c,l]of Object.entries(o.elements??{}))if(!(l.choiceOf!=="value"&&!c.startsWith("value"))&&(a=P(e,n,[r,c],l,i),a))break;t.push({name:s,url:o.url??s,valueFieldType:a,min:o.min,max:o.max!==void 0?String(o.max):void 0});}return t},vn=(e,n,i)=>{let t=[],o=n.elements?.extension?.slicing?.slices;if(!o||typeof o!="object")return t;for(let[s,a]of Object.entries(o)){let c=a,l=c.schema;if(!l)continue;let p;for(let[m,g]of Object.entries(l.elements??{})){let d=g;if(!(d.choiceOf!=="value"&&!m.startsWith("value"))&&(p=P(e,n,[m],d,i),p))break}t.push({name:s,url:c.match?.url??s,valueFieldType:p,min:l._required?1:l.min??0,max:l.max!==void 0?String(l.max):l.array?"*":"1"});}return t},En=(e,n,i,t)=>{let r=e.resolveFs(n.package_meta,i);if(!r?.elements)return;let o=Tn(e,r,t),s=vn(e,r,t),a=[...o,...s];return a.length>0?a:void 0},He=(e,n,i)=>{let t=[],r=(c,l,p)=>{let m=p.url,g=m?Fn(e,n,m,i):void 0,d=m?En(e,n,m,i):void 0;if(!m){let S=n.elements?.extension?.slicing?.slices?.[l]?.schema;if(S){m=S.elements?.url?.fixed?.value??l;for(let[x,C]of Object.entries(S.elements??{})){let N=C;if(N.choiceOf==="value"||x.startsWith("value")){let oe=P(e,n,[x],N,i);if(oe){g=[oe];break}}}}}let u=d&&d.length>0,f=m?e.resolveFs(n.package_meta,m):void 0,y=f?k(f):void 0,h=[...c,"extension"].join(".");t.push({name:l,path:h,url:m,profile:y,min:p.min,max:p.max!==void 0?String(p.max):void 0,mustSupport:p.mustSupport,valueFieldTypes:g,subExtensions:d,isComplex:u,nameCandidates:xe({name:l,path:h})});},o=(c,l)=>{if(l.extensions)for(let[p,m]of Object.entries(l.extensions))r(c,p,m);if(l.elements)for(let[p,m]of Object.entries(l.elements))o([...c,p],m);};o([],n);let s=new Set,a=t.filter(c=>{let l=`${c.url}:${c.path}`;return s.has(l)?false:(s.add(l),true)});return a.length===0?void 0:a};function Pn(e,n,i,t,r){if(!t)return {};let o={},s={};for(let a of e.getAllElementKeys(t)){let c=[...i,a],l=e.resolveElementSnapshot(n,c),p=l.type?e.ensureSpecializationCanonicalUrl(l.type):void 0;if(p&&v(n.package_meta,p).shouldSkip){r?.warn("#skipCanonical",`Skipping field ${c} for ${p} due to skip hack ${v(n.package_meta,p).reason}`);continue}ne(e,n,c,l,t[a])?o[a]=_(e,n,c,l):o[a]=j(e,n,c,l,r,t[a]);let m=M(a,l);m&&(s[a]=m);}return {fields:o,slicing:Object.keys(s).length>0?s:void 0}}function Nn(e){let n=[];for(let i of Object.values(e))"type"in i&&i.type&&n.push(i.type),"binding"in i&&i.binding&&n.push(i.binding);return n}async function $e(e,n,i){if(!n.url)throw new Error("ValueSet URL is required");let t=H(e,n.package_meta,n.url),r=Y(e,n.package_meta,n.url);return {identifier:t,description:n.description,concept:r,compose:r?void 0:n.compose}}var Ve=(e,n,i)=>{let t=[];return e&&t.push(e),n&&t.push(...Nn(n)),i&&t.push(...Pe(i)),t},Ue=(e,n,i,t)=>{let o=Ve(n,i,t).filter(s=>!(s.url===e.url||W(s)));return E(o)},Dn=(e,n,i,t)=>{let o=Ve(n,i,t).filter(s=>s.url!==e.url);return E(o)};function Oe(e,n,i){let t;if(n.base){let p=e.resolveFs(n.package_meta,e.ensureSpecializationCanonicalUrl(n.base));if(!p)throw new Error(`Base resource not found '${n.base}' for <${n.url}> from ${R(n.package_meta)}`);let m=k(p);we(!W(m),`Unexpected nested base for ${n.url}`),t=m;}let{fields:r,slicing:o}=Pn(e,n,[],n.elements,i),s=Ee(e,n,i),a=Se(e,n,i);if(n.derivation==="constraint"){let p=k(n);if(!t)throw new Error(`Profile ${n.url} must have a base type`);let m=He(e,n,i),g=m?.flatMap(ge),d=Dn(p,t,r,s),u={identifier:p,base:t,fields:r,slicing:o,nested:s,description:n.description,dependencies:E(d,g),extensions:m};return ke(u),[u,...a]}if(n.kind==="primitive-type"){let p=k(n);return we(t,`Primitive type ${n.url} must have a base type`),[{identifier:p,description:n.description,base:t,dependencies:Ue(p,t,r,s)},...a]}let c=k(n);return [{identifier:c,base:t,fields:r,slicing:o,nested:s,description:n.description,dependencies:Ue(c,t,r,s),typeFamily:void 0},...a]}var Ln=(e,n,i)=>{let t={};for(let s of e){let a=`${s.schema.identifier.url}|${s.schema.identifier.package}`,c=me(s.schema);t[a]??={},t[a][c]??={typeSchema:s.schema,sources:[]},t[a][c].sources.push(s);}let r=[],o={};for(let s of Object.values(t)){let a=Object.entries(s).map(([l,p])=>({...p,schemaHash:l,sources:[...p.sources].sort(z)})).sort(pe),c=a[0];if(c)if(a.length>1){let l=c.typeSchema.identifier.url,p=c.typeSchema.identifier.package;i?.dryWarn("#duplicateSchema",`'${l}' from '${p}' has ${a.length} versions`),r.push(c.typeSchema);o[p]??={},o[p][l]=a.flatMap(g=>g.sources.map(d=>({typeSchema:g.typeSchema,sourcePackage:d.sourcePackage,sourceCanonical:d.sourceCanonical})));}else r.push(c.typeSchema);}return {schemas:r,collisions:o}},Be=async(e,n,i)=>{let t=[];for(let r of e.allFs()){let o=R(r.package_meta),s=v(r.package_meta,r.url);if(s.shouldSkip){i?.dryWarn("#skipCanonical",`Skip ${r.url} from ${o}. Reason: ${s.reason}`);continue}for(let a of Oe(e,r,i))t.push({schema:a,sourcePackage:o,sourceCanonical:r.url});}for(let r of e.allVs())t.push({schema:await $e(e,r),sourcePackage:R(r.package_meta),sourceCanonical:r.url});return Ln(t,n,i)};var Me={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 n=I({prefix:"TypeSchema"});try{n.info("Generating TypeSchema from FHIR packages"),n.info(`Packages: ${e.packages.join(", ")}`),n.info(`Output: ${e.output}`);let i=e.singleFile?"ndjson":e.format;n.debug(`Format: ${i}${e.singleFile&&e.format==="json"?" (forced from json due to singleFile)":""}`),e.treeshake&&e.treeshake.length>0&&n.info(`Treeshaking enabled for ResourceTypes: ${e.treeshake.join(", ")}`),e.singleFile&&n.info("Single file output enabled (NDJSON format)"),e.registry&&n.info(`Using custom registry: ${e.registry}`);let t=Date.now(),r=e.packages.map(p=>{if(p.includes("@")){let m=p.lastIndexOf("@");return {name:p.slice(0,m),version:p.slice(m+1)||"latest"}}return {name:p,version:"latest"}});n.info(`Processing packages: ${r.map(p=>`${p.name}@${p.version}`).join(", ")}`);let o=await Te(r,{logger:n,registry:e.registry,focusedPackages:r}),{schemas:s}=await Be(o,void 0,n);if(s.length===0)throw new Error("No schemas were generated from the specified packages");let a=e.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(p=>JSON.stringify(p)).join(`
9
+ `),await writeFile(a,c,"utf-8");let l=Date.now()-t;if(ae(`Generated ${s.length} TypeSchema definitions`,l,{schemas:s.length}),n.info(`Output: ${a}`),e.verbose){n.debug("Generated schemas:");let p=s.map(m=>`${m.identifier?.name||"Unknown"} (${m.identifier?.kind||"unknown"})`);T(p);}}catch(i){n.error(`Failed to generate TypeSchema: ${i instanceof Error?i.message:String(i)}`),process.exit(1);}}};var ie=I({prefix:"typeschema"}),je={command:"typeschema [subcommand]",describe:"TypeSchema operations - generate, validate and merge schemas",builder:e=>e.command(Me).help().example("$0 typeschema generate hl7.fhir.r4.core@4.0.1","Generate TypeSchema from FHIR R4 core package"),handler:e=>{if(!e.subcommand&&e._.length===1){ie.info("Available typeschema subcommands:"),T(["generate Generate TypeSchema files from FHIR packages"]),console.log(`
10
10
  Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),console.log(`
11
- Examples:`),F(["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}e.subcommand&&!["generate","validate","merge"].includes(e.subcommand)&&(ee.error(`Unknown typeschema subcommand: ${e.subcommand}`),ee.info("Available typeschema subcommands:"),F(["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(`
12
- Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};var _=k({prefix:"cli"});async function Hn(e){let n=e.logLevel??(e.debug||e.verbose?"DEBUG":"INFO");_=k({prefix:"cli",level:n});}function wn(){return Dn(hideBin(process.argv)).scriptName("atomic-codegen").usage("$0 <command> [options]").middleware(Hn).command($e).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(e=>{e._.length===0&&(ie("Welcome to Atomic Codegen!"),console.log("Available commands:"),console.log(" typeschema Generate, validate and merge TypeSchema files"),console.log(`
11
+ Examples:`),T(["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}e.subcommand&&!["generate","validate","merge"].includes(e.subcommand)&&(ie.error(`Unknown typeschema subcommand: ${e.subcommand}`),ie.info("Available typeschema subcommands:"),T(["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(`
12
+ Use 'atomic-codegen typeschema <subcommand> --help' for more information about a subcommand.`),process.exit(1));}};var G=I({prefix:"cli"});async function On(e){let n=e.logLevel??(e.debug||e.verbose?"DEBUG":"INFO");G=I({prefix:"cli",level:n});}function Bn(){return $n(hideBin(process.argv)).scriptName("atomic-codegen").usage("$0 <command> [options]").middleware(On).command(je).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(e=>{e._.length===0&&(se("Welcome to Atomic Codegen!"),console.log("Available commands:"),console.log(" typeschema Generate, validate and merge TypeSchema files"),console.log(`
13
13
  Use 'atomic-codegen <command> --help' for more information about a command.`),console.log(`
14
14
  Quick examples:`),console.log(" atomic-codegen typeschema generate hl7.fhir.r4.core@4.0.1 -o schemas.ndjson"),console.log(`
15
- 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,n,i)=>{_.error(n?n.message:e),_.error("Use --help for usage information"),process.exit(1);}).wrap(Math.min(120,process.stdout.columns||80))}async function ne(){await wn().parseAsync();}import.meta.main&&ne().catch(e=>{_.error(String(e)),process.exit(1);});ne().catch(e=>{console.error("CLI Error:",e instanceof Error?e.message:e),process.exit(1);});
15
+ 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,n,i)=>{G.error(n?n.message:e),G.error("Use --help for usage information"),process.exit(1);}).wrap(Math.min(120,process.stdout.columns||80))}async function re(){await Bn().parseAsync();}import.meta.main&&re().catch(e=>{G.error(String(e)),process.exit(1);});re().catch(e=>{console.error("CLI Error:",e instanceof Error?e.message:e),process.exit(1);});
package/dist/index.d.ts CHANGED
@@ -871,15 +871,22 @@ type CollisionResolution = {
871
871
  type ResolveCollisionsConf = Record<string, CollisionResolution>;
872
872
  type IrConf = {
873
873
  treeShake?: TreeShakeConf;
874
+ /** Rule defaults applied to every treeShake root; a rule's own value wins. */
875
+ treeShakeDefaults?: TreeShakeDefaults;
874
876
  promoteLogical?: LogicalPromotionConf;
875
877
  resolveCollisions?: ResolveCollisionsConf;
876
878
  };
879
+ type TreeShakeDefaults = Pick<TreeShakeRule, "followReferences">;
877
880
  type LogicalPromotionConf = Record<PkgName$1, CanonicalUrl[]>;
878
881
  type TreeShakeConf = Record<string, Record<string, TreeShakeRule>>;
879
882
  type TreeShakeRule = {
880
883
  ignoreFields?: string[];
881
884
  selectFields?: string[];
882
885
  ignoreExtensions?: string[];
886
+ /** Also generate types for the schema's reference targets (base resources
887
+ * and target profiles). Non-transitive: followed types keep their own
888
+ * reference targets as plain string literals. Default: false. */
889
+ followReferences?: boolean;
883
890
  };
884
891
 
885
892
  type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR" | "SILENT";
@@ -913,7 +920,7 @@ type LoggerOptions<T extends string> = {
913
920
  level?: LogLevel;
914
921
  };
915
922
 
916
- type CodegenTag = "#binding" | "#largeValueSet" | "#placeholderValueSet" | "#fieldTypeNotFound" | "#skipCanonical" | "#duplicateSchema" | "#duplicateCanonical" | "#resolveBase" | "#resolveCollisionMiss";
923
+ type CodegenTag = "#binding" | "#largeValueSet" | "#placeholderValueSet" | "#fieldTypeNotFound" | "#skipCanonical" | "#duplicateSchema" | "#duplicateCanonical" | "#resolveBase" | "#resolveCollisionMiss" | "#nonMonotonicChoice";
917
924
  type CodegenLog = Log<CodegenTag>;
918
925
  type CodegenLogManager = LogManager<CodegenTag>;
919
926
  declare const mkCodegenLogger: (opts?: LoggerOptions<CodegenTag>) => LogManager<CodegenTag>;
@@ -1006,7 +1013,12 @@ interface PythonGeneratorOptions extends WriterOptions {
1006
1013
  }
1007
1014
 
1008
1015
  interface IntrospectionWriterOptions extends FileSystemWriterOptions {
1009
- typeSchemas?: string /** if .ndjson -- put in one file, else -- split into separated files*/;
1016
+ /** if target is .ndjson -- put in one file, else -- split into separated files;
1017
+ * profileSnapshots additionally exports flattened profile snapshots next to profiles as <name>.snapshot.json */
1018
+ typeSchemas?: string | {
1019
+ target: string;
1020
+ profileSnapshots?: boolean;
1021
+ };
1010
1022
  typeTree?: string /** .json or .yaml file */;
1011
1023
  fhirSchemas?: string /** if .ndjson -- put in one file, else -- split into separated files*/;
1012
1024
  structureDefinitions?: string /** if .ndjson -- put in one file, else -- split into separated files*/;