babelfhir-ts 1.1.4 → 1.2.0

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.
Files changed (84) hide show
  1. package/README.md +91 -25
  2. package/out/fhir-r4.d.ts +4 -0
  3. package/out/fhir-r4b.d.ts +4 -0
  4. package/out/src/generator/core/constants.js +77 -2
  5. package/out/src/generator/core/sdDiagnostics.js +108 -0
  6. package/out/src/generator/core/utils.js +22 -2
  7. package/out/src/generator/emitters/class/classGenerator.js +120 -258
  8. package/out/src/generator/emitters/class/classGeneratorHelpers.js +122 -0
  9. package/out/src/generator/emitters/class/classGeneratorTypes.js +4 -0
  10. package/out/src/generator/emitters/class/classHeuristics.js +19 -0
  11. package/out/src/generator/emitters/class/classTemplate.js +121 -0
  12. package/out/src/generator/emitters/class/enrichResourceBundleHandler.js +256 -0
  13. package/out/src/generator/emitters/class/enrichResourceFixers.js +184 -0
  14. package/out/src/generator/emitters/class/enrichResourceHandlers.js +84 -151
  15. package/out/src/generator/emitters/class/enrichResourceObservationHandler.js +254 -0
  16. package/out/src/generator/emitters/class/enrichResourceTemplate.js +110 -327
  17. package/out/src/generator/emitters/class/fieldPatternExtractor.js +103 -18
  18. package/out/src/generator/emitters/class/randomSupportGenerator.js +2 -1
  19. package/out/src/generator/emitters/class/randomUtilitiesTemplate.js +22 -1
  20. package/out/src/generator/emitters/class/sliceElementDefaults.js +467 -0
  21. package/out/src/generator/emitters/class/sliceElementGenerator.js +131 -367
  22. package/out/src/generator/emitters/interface/importManager.js +3 -0
  23. package/out/src/generator/emitters/interface/interfaceFieldProcessor.js +6 -77
  24. package/out/src/generator/emitters/interface/interfaceFieldUtils.js +52 -0
  25. package/out/src/generator/emitters/interface/interfaceGenerator.js +41 -3
  26. package/out/src/generator/emitters/interface/postProcessExtensions.js +16 -10
  27. package/out/src/generator/emitters/interface/processNestedField.js +19 -3
  28. package/out/src/generator/emitters/validator/sliceBackboneValidation.js +370 -0
  29. package/out/src/generator/emitters/validator/sliceExtensionValidation.js +244 -0
  30. package/out/src/generator/emitters/validator/sliceValidatorGenerator.js +197 -194
  31. package/out/src/generator/emitters/validator/sliceValidatorUtils.js +95 -0
  32. package/out/src/generator/emitters/validator/validatorBindingBuilder.js +304 -0
  33. package/out/src/generator/emitters/validator/validatorBindingLeafEmitters.js +303 -0
  34. package/out/src/generator/emitters/validator/validatorConstraintBuilders.js +374 -0
  35. package/out/src/generator/emitters/validator/validatorFieldBuilders.js +265 -0
  36. package/out/src/generator/emitters/validator/validatorGenerator.js +90 -382
  37. package/out/src/generator/emitters/validator/validatorTemplates.js +106 -0
  38. package/out/src/generator/emitters/validator/validatorTypes.js +1 -0
  39. package/out/src/generator/emitters/zod/zodRefinementBuilder.js +151 -0
  40. package/out/src/generator/emitters/zod/zodSchemaGenerator.js +133 -182
  41. package/out/src/generator/fhir/corePackageResolver.js +288 -0
  42. package/out/src/generator/fhir/corePackageResolver.ts +371 -0
  43. package/out/src/generator/fhir/createRules.js +158 -0
  44. package/out/src/generator/fhir/createRules.ts +188 -0
  45. package/out/src/generator/fhir/fallback/r4.json +15468 -0
  46. package/out/src/generator/fhir/fallback/r4b.json +15287 -0
  47. package/out/src/generator/fhir/r4/base/well-known-system-codes.json +46 -1
  48. package/out/src/generator/fhir/types.js +55 -12
  49. package/out/src/generator/fhir/types.ts +71 -16
  50. package/out/src/generator/fhir/versionRegistry.js +28 -0
  51. package/out/src/generator/fhir/versionRegistry.ts +45 -0
  52. package/out/src/generator/generationHelpers.js +202 -0
  53. package/out/src/generator/index.js +74 -277
  54. package/out/src/generator/parser/packageParser.js +218 -0
  55. package/out/src/generator/parser/sdFetcher.js +39 -1
  56. package/out/src/generator/parser/sdParser.js +65 -6
  57. package/out/src/generator/parser/sliceAggregator.js +203 -161
  58. package/out/src/generator/parser/sliceAggregatorComposition.js +194 -0
  59. package/out/src/generator/parser/vsParser.js +8 -2
  60. package/out/src/generator/sdProcessor.js +104 -302
  61. package/out/src/generator/sdProcessorHelpers.js +98 -0
  62. package/out/src/generator/sdProcessorRequiredFields.js +129 -0
  63. package/out/src/main.js +37 -246
  64. package/package.json +3 -3
  65. package/out/src/generator/fhir/r4/base/Bundle.json +0 -2154
  66. package/out/src/generator/fhir/r4/base/Composition.json +0 -3346
  67. package/out/src/generator/fhir/r4/base/Endpoint.json +0 -1051
  68. package/out/src/generator/fhir/r4/base/README.md +0 -28
  69. package/out/src/generator/fhir/r4/base/Subscription.json +0 -1072
  70. package/out/src/generator/fhir/r4/base/ValueSet.json +0 -4021
  71. package/out/src/generator/fhir/r4/context.js +0 -21
  72. package/out/src/generator/fhir/r4/context.ts +0 -24
  73. package/out/src/generator/fhir/r4/dataTypes.json +0 -858
  74. package/out/src/generator/fhir/r4/interfaces.json +0 -664
  75. package/out/src/generator/fhir/r4/resources.json +0 -150
  76. package/out/src/generator/fhir/r4/rules.js +0 -207
  77. package/out/src/generator/fhir/r4/rules.ts +0 -226
  78. package/out/src/generator/fhir/r4b/context.js +0 -21
  79. package/out/src/generator/fhir/r4b/context.ts +0 -24
  80. package/out/src/generator/fhir/r4b/dataTypes.json +0 -860
  81. package/out/src/generator/fhir/r4b/interfaces.json +0 -684
  82. package/out/src/generator/fhir/r4b/resources.json +0 -145
  83. package/out/src/generator/fhir/r4b/rules.js +0 -171
  84. package/out/src/generator/fhir/r4b/rules.ts +0 -190
package/README.md CHANGED
@@ -35,38 +35,104 @@ Every pull request runs two independent CI pipelines that validate generated cod
35
35
  4. Generates `empty()` and `random()` test resources for every profile
36
36
  5. Validates those resources against two external FHIR validators
37
37
 
38
- ### Tested Implementation Guides
38
+ ### Tested Implementation Guides (28 packages)
39
39
 
40
- | Implementation Guide | Package | Profiles |
40
+ | Category | Implementation Guide | Package |
41
41
  |---|---|---|
42
- | US Core | `hl7.fhir.us.core@8.0.0` | Patient, Condition, Observation, Encounter, … |
43
- | ISiK Basis (Germany) | `de.gematik.isik-basismodul@4.0.3` | ISiKPatient, ISiKDiagnose, … |
44
- | IPS (International Patient Summary) | `hl7.fhir.uv.ips@2.0.0` | Composition, MedicationStatement, … |
45
- | SMART App Launch | `hl7.fhir.uv.smart-app-launch@2.2.0` | WellKnown endpoints |
46
- | CH Core (Switzerland) | `ch.fhir.ig.ch-core@5.0.0` | CHCorePatient, CHCoreEncounter, … |
47
- | DaVinci PAS | `hl7.fhir.us.davinci-pas@2.0.1` | PASClaim, PASClaimResponse, … |
42
+ | US | US Core | `hl7.fhir.us.core@8.0.0` |
43
+ | US | QI-Core | `hl7.fhir.us.qicore@6.0.0` |
44
+ | US | mCODE | `hl7.fhir.us.mcode@4.0.0` |
45
+ | US | SDOH Clinical Care | `hl7.fhir.us.sdoh-clinicalcare@2.2.0` |
46
+ | US | NDH (National Directory) | `hl7.fhir.us.ndh@1.0.0` |
47
+ | US | CARIN BB | `hl7.fhir.us.carin-bb@2.1.0` |
48
+ | US | CQF Measures | `hl7.fhir.us.cqfmeasures@4.0.0` |
49
+ | US | Physical Activity | `hl7.fhir.us.physical-activity@1.0.0` |
50
+ | DaVinci | PAS | `hl7.fhir.us.davinci-pas@2.0.1` |
51
+ | DaVinci | CDex | `hl7.fhir.us.davinci-cdex@2.1.0` |
52
+ | DaVinci | PDex | `hl7.fhir.us.davinci-pdex@2.1.0` |
53
+ | DaVinci | DTR | `hl7.fhir.us.davinci-dtr@2.1.0` |
54
+ | DaVinci | Alerts | `hl7.fhir.us.davinci-alerts@1.0.0` |
55
+ | DaVinci | DEQM | `hl7.fhir.us.davinci-deqm@4.0.0` |
56
+ | DaVinci | Drug Formulary | `hl7.fhir.us.davinci-drug-formulary@2.1.0` |
57
+ | Universal | IPS | `hl7.fhir.uv.ips@2.0.0` |
58
+ | Universal | SMART App Launch | `hl7.fhir.uv.smart-app-launch@2.2.0` |
59
+ | Universal | SDC (Structured Data Capture) | `hl7.fhir.uv.sdc@3.0.0` |
60
+ | Universal | Genomics Reporting | `hl7.fhir.uv.genomics-reporting@3.0.0` |
61
+ | Universal | CPG (Clinical Practice Guidelines) | `hl7.fhir.uv.cpg@2.0.0` |
62
+ | DE | ISiK Basis | `de.gematik.isik-basismodul@4.0.3` |
63
+ | DE | ISiK Medikation | `de.gematik.isik-medikation@4.0.1` |
64
+ | DE | KBV eRezept | `kbv.ita.erp@1.1.1` |
65
+ | DE | DE Basisprofil | `de.basisprofil.r4@1.5.0` |
66
+ | CH | CH Core (Switzerland) | `ch.fhir.ig.ch-core@5.0.0` |
67
+ | AU | AU Core (Australia) | `hl7.fhir.au.core@1.0.0` |
68
+ | IHE | PIXm | `ihe.iti.pixm@3.0.4` |
69
+ | IHE | MHD | `ihe.iti.mhd@4.2.2` |
48
70
 
49
71
  ### Validation with Firely .NET SDK
50
72
 
51
- The first pipeline validates generated resources using the [Firely .NET SDK validator](https://docs.fire.ly/projects/Firely-NET-SDK/) (v3.1.0). Results are published as live badges:
52
-
53
- ![US Core 8.0.0](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-us-core.json)
54
- ![ISiK Basis 4.0.3](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-isik-basis.json)
55
- ![IPS 2.0.0](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ips.json)
56
- ![SMART 2.2.0](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-smart.json)
57
- ![CH Core 5.0.0](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ch-core.json)
58
- ![DaVinci PAS 2.0.1](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-pas.json)
73
+ The first pipeline validates generated resources using the [Firely .NET SDK validator](https://docs.fire.ly/projects/Firely-NET-SDK/) (Firely.Fhir.Validation.R4 v3.1.1). Results are published as live badges:
74
+
75
+ ![US Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-us-core.json)
76
+ ![QI-Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-qicore.json)
77
+ ![mCODE](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-mcode.json)
78
+ ![SDOH](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-sdoh.json)
79
+ ![NDH](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ndh.json)
80
+ ![CARIN BB](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-carin-bb.json)
81
+ ![CQF Measures](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-cqfmeasures.json)
82
+ ![Physical Activity](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-physical-activity.json)
83
+ ![DaVinci PAS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-pas.json)
84
+ ![DaVinci CDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-cdex.json)
85
+ ![DaVinci PDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-pdex.json)
86
+ ![DaVinci DTR](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-dtr.json)
87
+ ![DaVinci Alerts](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-alerts.json)
88
+ ![DaVinci DEQM](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-deqm.json)
89
+ ![DaVinci Drug Formulary](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-davinci-drug-formulary.json)
90
+ ![IPS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ips.json)
91
+ ![SMART](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-smart.json)
92
+ ![SDC](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-sdc.json)
93
+ ![Genomics Reporting](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-genomics-reporting.json)
94
+ ![CPG](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-cpg.json)
95
+ ![ISiK Basis](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-isik-basis.json)
96
+ ![ISiK Medikation](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-isik-medikation.json)
97
+ ![KBV eRezept](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-kbv-erp.json)
98
+ ![DE Basisprofil](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-de-basisprofil.json)
99
+ ![CH Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-ch-core.json)
100
+ ![AU Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-au-core.json)
101
+ ![PIXm](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-pixm.json)
102
+ ![MHD](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-mhd.json)
59
103
 
60
104
  ### Validation with HL7 Java Validator
61
105
 
62
- The second pipeline validates using the [official HL7 FHIR Validator](https://confluence.hl7.org/display/FHIR/Using+the+FHIR+Validator) (v6.9.1), the reference implementation for FHIR conformance checking:
63
-
64
- ![US Core 8.0.0](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-us-core.json)
65
- ![ISiK Basis 4.0.3](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-isik-basis.json)
66
- ![IPS 2.0.0](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ips.json)
67
- ![SMART 2.2.0](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-smart.json)
68
- ![CH Core 5.0.0](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ch-core.json)
69
- ![DaVinci PAS 2.0.1](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-pas.json)
106
+ The second pipeline validates using the [official HL7 FHIR Validator](https://confluence.hl7.org/display/FHIR/Using+the+FHIR+Validator) (v6.9.4), the reference implementation for FHIR conformance checking:
107
+
108
+ ![US Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-us-core.json)
109
+ ![QI-Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-qicore.json)
110
+ ![mCODE](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-mcode.json)
111
+ ![SDOH](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-sdoh.json)
112
+ ![NDH](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ndh.json)
113
+ ![CARIN BB](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-carin-bb.json)
114
+ ![CQF Measures](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-cqfmeasures.json)
115
+ ![Physical Activity](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-physical-activity.json)
116
+ ![DaVinci PAS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-pas.json)
117
+ ![DaVinci CDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-cdex.json)
118
+ ![DaVinci PDex](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-pdex.json)
119
+ ![DaVinci DTR](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-dtr.json)
120
+ ![DaVinci Alerts](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-alerts.json)
121
+ ![DaVinci DEQM](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-deqm.json)
122
+ ![DaVinci Drug Formulary](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-davinci-drug-formulary.json)
123
+ ![IPS](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ips.json)
124
+ ![SMART](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-smart.json)
125
+ ![SDC](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-sdc.json)
126
+ ![Genomics Reporting](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-genomics-reporting.json)
127
+ ![CPG](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-cpg.json)
128
+ ![ISiK Basis](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-isik-basis.json)
129
+ ![ISiK Medikation](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-isik-medikation.json)
130
+ ![KBV eRezept](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-kbv-erp.json)
131
+ ![DE Basisprofil](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-de-basisprofil.json)
132
+ ![CH Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-ch-core.json)
133
+ ![AU Core](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-au-core.json)
134
+ ![PIXm](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-pixm.json)
135
+ ![MHD](https://img.shields.io/endpoint?url=https://max-health-inc.github.io/BabelFHIR-TS/badges/badge-hl7-mhd.json)
70
136
 
71
137
  > Terminology validation requires a tx server. The pipeline uses `--tx-server https://tx.fhir.org/r4` during generation to expand ValueSets and produce valid codes.
72
138
 
@@ -194,4 +260,4 @@ For security issues, please see [SECURITY.md](SECURITY.md) for our security poli
194
260
  - [GitHub repository](https://github.com/Max-Health-Inc/BabelFHIR-TS)
195
261
  - [Validation report](https://max-health-inc.github.io/BabelFHIR-TS/)
196
262
  - [Issue tracker](https://github.com/Max-Health-Inc/BabelFHIR-TS/issues)
197
- - [Changelog](CHANGELOG.md)
263
+ - [Changelog / Releases](https://github.com/Max-Health-Inc/BabelFHIR-TS/releases)
package/out/fhir-r4.d.ts CHANGED
@@ -673,4 +673,8 @@ declare module 'fhir/r4' {
673
673
  export type VisionPrescription = fhir4.VisionPrescription;
674
674
  export type VisionPrescriptionLensSpecification = fhir4.VisionPrescriptionLensSpecification;
675
675
  export type VisionPrescriptionLensSpecificationPrism = fhir4.VisionPrescriptionLensSpecificationPrism;
676
+ /** Constraint profile on Quantity — missing from @types/fhir */
677
+ export type MoneyQuantity = fhir4.Quantity;
678
+ /** Constraint profile on Quantity — missing from @types/fhir */
679
+ export type SimpleQuantity = fhir4.Quantity;
676
680
  }
package/out/fhir-r4b.d.ts CHANGED
@@ -693,4 +693,8 @@ declare module 'fhir/r4b' {
693
693
  export type VisionPrescription = fhir4b.VisionPrescription;
694
694
  export type VisionPrescriptionLensSpecification = fhir4b.VisionPrescriptionLensSpecification;
695
695
  export type VisionPrescriptionLensSpecificationPrism = fhir4b.VisionPrescriptionLensSpecificationPrism;
696
+ /** Constraint profile on Quantity — missing from @types/fhir */
697
+ export type MoneyQuantity = fhir4b.Quantity;
698
+ /** Constraint profile on Quantity — missing from @types/fhir */
699
+ export type SimpleQuantity = fhir4b.Quantity;
696
700
  }
@@ -81,7 +81,7 @@ export const DEFAULT_COUNTRY = 'XX';
81
81
  export const DEFAULT_BASE64 = 'ZXhhbXBsZQ=='; // "example"
82
82
  export const DEFAULT_BASE64_HELLO = 'SGVsbG8gV29ybGQ='; // "Hello World"
83
83
  export const DEFAULT_CONTENT_TYPE = 'application/pdf';
84
- export const EXAMPLE_ID_SYSTEM = 'https://acme.org/ids';
84
+ export const EXAMPLE_ID_SYSTEM = 'https://babelfhir.dev/ids';
85
85
  // ─── Resource status defaults (data-driven map) ─────────────────────────────
86
86
  // ─── Preferred code values ───────────────────────────────────────────────────
87
87
  //
@@ -150,7 +150,11 @@ export const VALUESET_DEFAULTS = {
150
150
  'http://hl7.org/fhir/uv/ips/ValueSet/results-status-uv-ips': { code: 'final' },
151
151
  'http://hl7.org/fhir/uv/ips/ValueSet/imaging-study-status-uv-ips': { code: 'available' },
152
152
  'http://hl7.org/fhir/us/davinci-hrex/ValueSet/hrex-task-status': { code: 'requested' },
153
+ 'http://hl7.org/fhir/us/physical-activity/ValueSet/pa-task-status': { code: 'requested' },
153
154
  'http://fhir.de/ValueSet/EncounterStatusDe': { code: 'finished' },
155
+ // ── Narrative status ValueSets ─────────────────────────────────────────
156
+ 'http://hl7.org/fhir/ValueSet/narrative-status': { code: 'generated' },
157
+ 'http://hl7.org/fhir/us/core/ValueSet/us-core-narrative-status': { code: 'generated' },
154
158
  // ── CodeableConcept clinical status (required binding) ────────────────────
155
159
  'http://hl7.org/fhir/ValueSet/condition-clinical': { system: TS.CONDITION_CLINICAL, code: 'active' },
156
160
  'http://hl7.org/fhir/ValueSet/condition-ver-status': { system: TS.CONDITION_VER_STATUS, code: 'confirmed' },
@@ -169,6 +173,28 @@ export const VALUESET_DEFAULTS = {
169
173
  'http://hl7.org/fhir/ValueSet/subscriber-relationship': { system: TS.SUBSCRIBER_REL, code: 'self' },
170
174
  'http://hl7.org/fhir/ValueSet/c80-doc-typecodes': { system: TS.LOINC, code: '34133-9', display: 'Summary of episode note' },
171
175
  'http://hl7.org/fhir/ValueSet/document-classcodes': { system: TS.LOINC, code: '34133-9' },
176
+ // ── Additional status ValueSets for specific resource types ───────────────
177
+ 'http://hl7.org/fhir/ValueSet/clinicalimpression-status': { code: 'completed' },
178
+ 'http://hl7.org/fhir/ValueSet/verificationresult-status': { code: 'attested' },
179
+ 'http://hl7.org/fhir/ValueSet/list-status': { code: 'current' },
180
+ 'http://hl7.org/fhir/ValueSet/consent-state-codes': { code: 'active' },
181
+ 'http://hl7.org/fhir/ValueSet/publication-status': { code: 'active' },
182
+ // ── Group type ValueSet (code type, required binding) ───────────────────────
183
+ 'http://hl7.org/fhir/ValueSet/group-type': { code: 'person' },
184
+ // ── Consent ValueSets (code type, required binding) ────────────────────────
185
+ 'http://hl7.org/fhir/ValueSet/consent-provision-type': { code: 'permit' },
186
+ 'http://hl7.org/fhir/ValueSet/consent-data-meaning': { code: 'instance' },
187
+ // ── Code fields for definition resources (PlanDefinition, ActivityDefinition) ─
188
+ 'http://hl7.org/fhir/ValueSet/action-condition-kind': { code: 'applicability' },
189
+ 'http://hl7.org/fhir/ValueSet/action-relationship-type': { code: 'before-start' },
190
+ 'http://hl7.org/fhir/ValueSet/action-participant-type': { code: 'practitioner' },
191
+ 'http://hl7.org/fhir/ValueSet/request-resource-types': { code: 'Task' },
192
+ 'http://hl7.org/fhir/ValueSet/resource-types': { code: 'Patient' },
193
+ 'http://hl7.org/fhir/ValueSet/FHIR-version': { code: '4.0.1' },
194
+ // ── Claim/EoB ValueSets (CARIN BB) ────────────────────────────────────────
195
+ 'http://hl7.org/fhir/ValueSet/claim-type': { system: 'http://terminology.hl7.org/CodeSystem/claim-type', code: 'institutional' },
196
+ 'http://hl7.org/fhir/ValueSet/process-priority': { code: 'normal' },
197
+ 'http://hl7.org/fhir/ValueSet/remittance-outcome': { code: 'complete' },
172
198
  };
173
199
  /**
174
200
  * Look up a safe default for a given ValueSet binding URI.
@@ -255,18 +281,61 @@ const procedure = (mp) => `{ resourceType: 'Procedure', id: randomId()${mp}, sta
255
281
  const device = (mp) => `{ resourceType: 'Device', id: randomId()${mp}, type: { coding: [{ system: '${TS.SNOMED}', code: '49062001', display: 'Device' }] } }`;
256
282
  const claimResponse = (mp) => `{ resourceType: 'ClaimResponse', id: randomId()${mp}, status: 'active', type: { coding: [{ system: '${TS.CLAIM_TYPE}', code: 'professional' }] }, use: 'preauthorization', patient: { reference: 'Patient/' + randomId() }, created: new Date().toISOString().split('T')[0], insurer: { reference: 'Organization/' + randomId() }, outcome: 'complete' }`;
257
283
  const claim = (mp) => `{ resourceType: 'Claim', id: randomId()${mp}, status: 'active', type: { coding: [{ system: '${TS.CLAIM_TYPE}', code: 'professional' }] }, use: 'preauthorization', patient: { reference: 'Patient/' + randomId() }, created: new Date().toISOString().split('T')[0], provider: { reference: 'Practitioner/' + randomId() }, priority: { coding: [{ system: '${TS.PROCESS_PRIORITY}', code: 'normal' }] }, insurance: [{ sequence: 1, focal: true, coverage: { reference: 'Coverage/' + randomId() } }] }`;
284
+ /**
285
+ * Placeholder values for Composition fields that profiles may require (min >= 1)
286
+ * but the base skeleton does not include.
287
+ */
288
+ const COMPOSITION_FIELD_PLACEHOLDERS = {
289
+ identifier: `identifier: { value: 'example-id', system: 'urn:ietf:rfc:3986' }`,
290
+ language: `language: 'en'`,
291
+ confidentiality: `confidentiality: 'N'`,
292
+ category: `category: [{ coding: [{ system: '${TS.LOINC}', code: '11503-0' }] }]`,
293
+ encounter: `encounter: { reference: 'Encounter/' + randomId() }`,
294
+ custodian: `custodian: { reference: 'Organization/' + randomId() }`,
295
+ attester: `attester: [{ mode: 'professional', party: { reference: 'Practitioner/' + randomId() } }]`,
296
+ event: `event: [{ period: { start: '2024-01-01' } }]`,
297
+ relatesTo: `relatesTo: [{ code: 'replaces', targetReference: { reference: 'Composition/' + randomId() } }]`,
298
+ };
258
299
  export function compositionSkeleton(metaProfile, opts = {}) {
259
300
  const loincCode = opts.loincCode ?? '60591-5';
260
301
  const textStatus = opts.textStatus ?? 'generated';
261
302
  const sectionExpr = opts.sections && opts.sections.length > 0
262
303
  ? opts.sections.map(s => `{ title: '${s.title}', code: { coding: [{ system: '${TS.LOINC}', code: '${s.loincCode}' }] }, text: { status: 'generated', div: '<div xmlns="http://www.w3.org/1999/xhtml">${s.title}</div>' }, emptyReason: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/list-empty-reason', code: 'unavailable', display: 'Unavailable' }] } }`).join(', ')
263
304
  : `{ title: 'Section', text: { status: 'generated', div: '<div xmlns="http://www.w3.org/1999/xhtml">Content</div>' } }`;
264
- return `{ resourceType: 'Composition', id: 'comp-' + randomId()${metaProfile}, text: { status: '${textStatus}', div: '<div xmlns="http://www.w3.org/1999/xhtml">Composition Narrative</div>' }, status: 'final', type: { coding: [{ system: '${TS.LOINC}', code: '${loincCode}' }], text: '${loincCode}' }, subject: { reference: 'Patient/' + randomId(), display: 'Example Patient' }, date: new Date().toISOString(), author: [{ reference: 'Practitioner/' + randomId(), display: 'Example Practitioner' }], title: 'Document Title', section: [${sectionExpr}] }`;
305
+ // Build extra fields required by the Composition profile but not in the base skeleton
306
+ const extraFields = (opts.requiredFields ?? [])
307
+ .map(f => COMPOSITION_FIELD_PLACEHOLDERS[f])
308
+ .filter(Boolean)
309
+ .join(', ');
310
+ const extraExpr = extraFields ? `, ${extraFields}` : '';
311
+ // Build primitive extensions (e.g., _confidentiality with required extension)
312
+ const primExtParts = [];
313
+ for (const pe of (opts.primitiveExtensions ?? [])) {
314
+ // Default to valueCodeableConcept with data-absent-reason (always valid, avoids example URL bans)
315
+ const valueExpr = pe.valueType === 'string'
316
+ ? `valueString: 'placeholder'`
317
+ : `valueCodeableConcept: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/data-absent-reason', code: 'unknown' }] }`;
318
+ primExtParts.push(`'_${pe.field}': { extension: [{ url: '${pe.url}', ${valueExpr} }] }`);
319
+ }
320
+ const primExtExpr = primExtParts.length > 0 ? `, ${primExtParts.join(', ')}` : '';
321
+ return `{ resourceType: 'Composition', id: 'comp-' + randomId()${metaProfile}${extraExpr}${primExtExpr}, text: { status: '${textStatus}', div: '<div xmlns="http://www.w3.org/1999/xhtml">Composition Narrative</div>' }, status: 'final', type: { coding: [{ system: '${TS.LOINC}', code: '${loincCode}' }], text: '${loincCode}' }, subject: { reference: 'Patient/' + randomId(), display: 'Example Patient' }, date: new Date().toISOString(), author: [{ reference: 'Practitioner/' + randomId(), display: 'Example Practitioner' }], title: 'Document Title', section: [${sectionExpr}] }`;
265
322
  }
266
323
  /**
267
324
  * Registry of resource skeletons indexed by resource type.
268
325
  * Used for inline resource generation (Bundle entry.resource, slice fallbacks).
269
326
  */
327
+ const group = (mp) => {
328
+ // Profile-specific code: pdex-member-match-group requires code from PDexMultiMemberMatchResultVS
329
+ const code = mp.includes('pdex-member-match-group')
330
+ ? `code: { coding: [{ system: 'http://hl7.org/fhir/us/davinci-pdex/CodeSystem/PdexMultiMemberMatchResultCS', code: 'match' }] }, `
331
+ : '';
332
+ return `{ resourceType: 'Group', id: randomId()${mp}, type: 'person', actual: true, ${code}}`;
333
+ };
334
+ const coverage = (mp) => `{ resourceType: 'Coverage', id: randomId()${mp}, status: 'active', subscriberId: randomId(), beneficiary: { reference: 'Patient/' + randomId() }, relationship: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/subscriber-relationship', code: 'self' }] }, payor: [{ reference: 'Organization/' + randomId() }] }`;
335
+ const consent = (mp) => `{ resourceType: 'Consent', id: randomId()${mp}, status: 'active', scope: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/consentscope', code: 'patient-privacy' }] }, category: [{ coding: [{ system: '${TS.ACT_CODE}', code: 'IDSCL' }] }], patient: { reference: 'Patient/' + randomId() }, performer: [{ reference: 'Organization/' + randomId() }], sourceReference: { reference: 'DocumentReference/' + randomId() }, policy: [{ uri: 'http://example.org/policy' }], provision: { type: 'permit', period: { start: '2024-01-01T00:00:00.000Z', end: '2025-01-01T00:00:00.000Z' }, actor: [{ role: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/provenance-participant-type', code: 'performer' }] }, reference: { reference: 'Organization/' + randomId() } }, { role: { coding: [{ system: 'http://terminology.hl7.org/CodeSystem/v3-ParticipationType', code: 'IRCP' }] }, reference: { reference: 'Organization/' + randomId() } }], action: [{ coding: [{ system: 'http://terminology.hl7.org/CodeSystem/consentaction', code: 'disclose' }] }] } }`;
336
+ const list = (mp) => `{ resourceType: 'List', id: randomId()${mp}, status: 'current', mode: 'working', code: { coding: [{ system: '${TS.LOINC}', code: '57024-2' }] }, subject: { reference: 'Patient/' + randomId() }, date: new Date().toISOString() }`;
337
+ const documentReference = (mp) => `{ resourceType: 'DocumentReference', id: randomId()${mp}, status: 'current', content: [{ attachment: { contentType: 'text/plain', url: 'https://babelfhir.dev/' + randomId() } }] }`;
338
+ const binary = (mp) => `{ resourceType: 'Binary', id: randomId()${mp}, contentType: 'application/pdf', data: '${DEFAULT_BASE64}' }`;
270
339
  export const RESOURCE_SKELETONS = {
271
340
  Patient: patient,
272
341
  Practitioner: practitioner,
@@ -280,6 +349,12 @@ export const RESOURCE_SKELETONS = {
280
349
  Device: device,
281
350
  ClaimResponse: claimResponse,
282
351
  Claim: claim,
352
+ Group: group,
353
+ Coverage: coverage,
354
+ Consent: consent,
355
+ List: list,
356
+ DocumentReference: documentReference,
357
+ Binary: binary,
283
358
  };
284
359
  /**
285
360
  * Build a Bundle entry object expression from a skeleton.
@@ -0,0 +1,108 @@
1
+ /**
2
+ * StructureDefinition Quality Diagnostics
3
+ *
4
+ * Collects structured diagnostics about SD quality issues discovered
5
+ * during code generation. Unlike log messages (which are transient),
6
+ * diagnostics are accumulated and emitted as a machine-readable report.
7
+ *
8
+ * This turns BabelFHIR-TS into a **profile validator** — not just a
9
+ * resource validator. When a profile has a structural flaw (unmatchable
10
+ * discriminator, missing snapshot, unresolvable type), we flag the
11
+ * *profile*, not the resources that happen to be validated against it.
12
+ */
13
+ // ── Collector ────────────────────────────────────────────────────────────────
14
+ const diagnostics = [];
15
+ const knownProfiles = new Set();
16
+ /** Reset all collected diagnostics (call before a new generation run). */
17
+ export function resetDiagnostics() {
18
+ diagnostics.length = 0;
19
+ knownProfiles.clear();
20
+ }
21
+ /** Register a profile as processed (even if no diagnostics are emitted for it). */
22
+ export function registerProfile(profileUrl, profileName) {
23
+ knownProfiles.add(profileUrl || profileName);
24
+ }
25
+ /** Record a diagnostic. */
26
+ export function addDiagnostic(d) {
27
+ diagnostics.push(d);
28
+ knownProfiles.add(d.profileUrl || d.profileName);
29
+ }
30
+ /** Get all collected diagnostics. */
31
+ export function getDiagnostics() {
32
+ return diagnostics;
33
+ }
34
+ /** Build the final quality report. */
35
+ export function buildQualityReport() {
36
+ const profiles = {};
37
+ const affectedUrls = new Set();
38
+ for (const d of diagnostics) {
39
+ const key = d.profileUrl || d.profileName;
40
+ affectedUrls.add(key);
41
+ if (!profiles[key]) {
42
+ profiles[key] = {
43
+ profileUrl: d.profileUrl,
44
+ profileName: d.profileName,
45
+ diagnostics: [],
46
+ };
47
+ }
48
+ profiles[key].diagnostics.push({
49
+ severity: d.severity,
50
+ category: d.category,
51
+ elementPath: d.elementPath,
52
+ message: d.message,
53
+ impact: d.impact,
54
+ });
55
+ }
56
+ return {
57
+ generated: new Date().toISOString(),
58
+ summary: {
59
+ errors: diagnostics.filter(d => d.severity === 'error').length,
60
+ warnings: diagnostics.filter(d => d.severity === 'warning').length,
61
+ info: diagnostics.filter(d => d.severity === 'info').length,
62
+ profilesAffected: affectedUrls.size,
63
+ profilesClean: knownProfiles.size - affectedUrls.size,
64
+ },
65
+ profiles,
66
+ };
67
+ }
68
+ /** Format the report as a human-readable CLI summary. */
69
+ export function formatReportSummary(report) {
70
+ const { summary } = report;
71
+ const total = summary.errors + summary.warnings + summary.info;
72
+ if (total === 0) {
73
+ return `\n✅ SD Quality: ${summary.profilesClean} profiles analyzed, no issues detected.\n`;
74
+ }
75
+ const lines = [];
76
+ lines.push('');
77
+ lines.push(`🔍 SD Quality Report: ${total} issue(s) across ${summary.profilesAffected} profile(s)`);
78
+ if (summary.errors > 0)
79
+ lines.push(` ❌ ${summary.errors} error(s) — structural flaws that will cause validator false positives`);
80
+ if (summary.warnings > 0)
81
+ lines.push(` ⚠️ ${summary.warnings} warning(s) — constraints that cannot be fully evaluated`);
82
+ if (summary.info > 0)
83
+ lines.push(` ℹ️ ${summary.info} info — limitations noted`);
84
+ lines.push(` ✅ ${summary.profilesClean} profile(s) are clean`);
85
+ lines.push('');
86
+ // Group by category for a compact view
87
+ const byCat = new Map();
88
+ for (const d of diagnostics) {
89
+ if (!byCat.has(d.category))
90
+ byCat.set(d.category, []);
91
+ byCat.get(d.category).push(d);
92
+ }
93
+ const catLabels = {
94
+ discriminator: 'Discriminator defects',
95
+ snapshot: 'Missing/incomplete snapshots',
96
+ type: 'Unresolvable element types',
97
+ constraint: 'Unevaluable FHIRPath constraints',
98
+ binding: 'Unresolvable ValueSet bindings',
99
+ 'profile-ref': 'Profile reference failures',
100
+ structure: 'Structural issues',
101
+ };
102
+ for (const [cat, items] of byCat) {
103
+ const profiles = new Set(items.map(d => d.profileName));
104
+ lines.push(` ${catLabels[cat]}: ${items.length} (${profiles.size} profile(s))`);
105
+ }
106
+ lines.push('');
107
+ return lines.join('\n');
108
+ }
@@ -17,7 +17,7 @@ export function stripVersionFromCanonicalUrl(url) {
17
17
  export function writeInterfaceAndValidatorToFile(outputDir, interfaceName, interfaceContent, validateFunctionContent) {
18
18
  const filePath = path.join(outputDir, `${interfaceName}.ts`);
19
19
  const content = `${interfaceContent}\n\n${validateFunctionContent}`;
20
- fs.writeFileSync(filePath, content, "utf-8");
20
+ caseAwareWriteFile(filePath, content);
21
21
  }
22
22
  export function extractFieldsFromInterface(interfaceDecl) {
23
23
  return interfaceDecl.getProperties().map((property) => {
@@ -188,9 +188,29 @@ export function ensureDirectoryExists(dirPath) {
188
188
  }
189
189
  /**
190
190
  * Writes content to a file at the specified path.
191
+ * On case-insensitive filesystems (Windows/macOS), removes any existing file
192
+ * whose name differs only in casing to prevent TS1261 errors.
191
193
  */
192
194
  export function writeToFile(filePath, content) {
193
- fs.writeFileSync(filePath, content, "utf-8");
195
+ caseAwareWriteFile(filePath, content);
196
+ }
197
+ /**
198
+ * Writes a file, first removing any existing file with the same case-insensitive
199
+ * name but different casing. Prevents TS1261/TS1149 on case-insensitive filesystems.
200
+ */
201
+ function caseAwareWriteFile(filePath, content) {
202
+ const dir = path.dirname(filePath);
203
+ const filename = path.basename(filePath);
204
+ if (fs.existsSync(dir)) {
205
+ const filenameLower = filename.toLowerCase();
206
+ for (const entry of fs.readdirSync(dir)) {
207
+ if (entry.toLowerCase() === filenameLower && entry !== filename) {
208
+ fs.unlinkSync(path.join(dir, entry));
209
+ break;
210
+ }
211
+ }
212
+ }
213
+ fs.writeFileSync(filePath, content, 'utf-8');
194
214
  }
195
215
  /**
196
216
  * Extracts the base resource name from a baseDefinition URL.