babelfhir-ts 1.6.2 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -113
- package/out/src/generator/emitters/class/classGenerator.js +2 -2
- package/out/src/generator/emitters/class/classGeneratorHelpers.js +8 -13
- package/out/src/generator/emitters/class/classTemplate.js +8 -5
- package/out/src/generator/index.js +0 -18
- package/out/src/generator/sdProcessor.js +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
<a href="https://www.npmjs.com/package/@babelfhir-ts/dicomweb"><img src="https://img.shields.io/npm/v/@babelfhir-ts/dicomweb.svg?label=%40babelfhir-ts%2Fdicomweb" alt="dicomweb"></a>
|
|
37
37
|
</p>
|
|
38
38
|
|
|
39
|
-
**BabelFHIR-TS** transforms FHIR® StructureDefinitions into production-ready TypeScript code with full type safety and built-in validation.
|
|
39
|
+
**BabelFHIR-TS** transforms FHIR® StructureDefinitions into production-ready TypeScript code with full type safety and built-in validation. BabelFHIR-TS generates **profile-aware** interfaces that understand your Implementation Guide's constraints, extensions, and slicing rules.
|
|
40
40
|
|
|
41
41
|
### What you get
|
|
42
42
|
|
|
@@ -48,118 +48,7 @@
|
|
|
48
48
|
- **Zero manual mapping**—consume any FHIR package or Implementation Guide directly from registries
|
|
49
49
|
- **Fast and lightweight**—the CLI pulls no FHIRPath engine of its own; generated packages declare `fhirpath` as a *peer* dependency (`>=4.9.1 <6`), so the host app owns the version
|
|
50
50
|
- **Type-safe FHIR client** — generated client extends [`@babelfhir-ts/client-r4`](https://www.npmjs.com/package/@babelfhir-ts/client-r4) / [`client-r4b`](https://www.npmjs.com/package/@babelfhir-ts/client-r4b) / [`client-r5`](https://www.npmjs.com/package/@babelfhir-ts/client-r5) with profile-specific methods (e.g., `.uSCorePatientProfile()`, `.pASClaim()`) on top of base resource accessors
|
|
51
|
-
- **Install any FHIR profile as a node module**—use `babelfhir-ts install` to add Implementation Guides directly to your project
|
|
52
|
-
|
|
53
|
-
<!-- PARITY-BADGES:START - Do not remove or modify this section -->
|
|
54
|
-
## Continuous Validation
|
|
55
|
-
|
|
56
|
-
Every push to `develop` and `main` runs the parity pipeline, which validates generated code against real-world FHIR Implementation Guides. (Pull requests run the faster `CI` workflow: typecheck, unit tests, and generated-artifact drift checks.) For each IG, the pipeline:
|
|
57
|
-
|
|
58
|
-
1. Downloads the FHIR package from a registry
|
|
59
|
-
2. Generates TypeScript interfaces, validators, and classes
|
|
60
|
-
3. Compiles the output with `tsc` (zero errors required)
|
|
61
|
-
4. Generates `empty()` and `random()` test resources for every profile
|
|
62
|
-
5. Validates those resources against two independent external FHIR validators
|
|
63
|
-
|
|
64
|
-
### Validated Implementation Guides (31)
|
|
65
|
-
|
|
66
|
-
Every parity run validates **31 real-world IGs** (29 R4, 2 R5). The list is not duplicated here — it is generated from the parity suite's own source of truth into [`parity-matrix.json`](./parity-matrix.json).
|
|
67
|
-
|
|
68
|
-
Each validated IG is also published as a ready-to-install package — `@max-health-inc/fhir-<name>` — so you do not have to generate it yourself:
|
|
69
|
-
|
|
70
|
-
**[→ Browse the FHIR IG registry](https://github.com/orgs/Max-Health-Inc/packages?ecosystem=npm&q=fhir-)**
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
# GitHub Packages needs the scope mapped, and a token with read:packages
|
|
74
|
-
echo "@max-health-inc:registry=https://npm.pkg.github.com" >> .npmrc
|
|
75
|
-
npm install @max-health-inc/fhir-us-core
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Published by [Max-Health-Inc/fhir-igs](https://github.com/Max-Health-Inc/fhir-igs), which pins a babelfhir-ts version and republishes an IG only when the IG version, the pinned generator, or the generation flags actually change.
|
|
79
|
-
|
|
80
|
-
### Validation with the Firely SDK Validator
|
|
81
|
-
|
|
82
|
-
The `firely` job validates generated resources using the [Firely SDK Validator](https://docs.fire.ly/projects/Firely-NET-SDK/validation.html) (`Firely.Fhir.Validation`, v3.x) running on the Firely .NET SDK (`Hl7.Fhir`, v6.x) — two separately versioned packages. Results are published as live badges:
|
|
83
|
-
|
|
84
|
-
<details><summary>Per-IG results</summary>
|
|
85
|
-
|
|
86
|
-

|
|
87
|
-

|
|
88
|
-

|
|
89
|
-

|
|
90
|
-

|
|
91
|
-

|
|
92
|
-

|
|
93
|
-

|
|
94
|
-

|
|
95
|
-

|
|
96
|
-

|
|
97
|
-

|
|
98
|
-

|
|
99
|
-

|
|
100
|
-

|
|
101
|
-

|
|
102
|
-

|
|
103
|
-

|
|
104
|
-

|
|
105
|
-

|
|
106
|
-

|
|
107
|
-

|
|
108
|
-

|
|
109
|
-

|
|
110
|
-

|
|
111
|
-

|
|
112
|
-

|
|
113
|
-

|
|
114
|
-

|
|
115
|
-
|
|
116
|
-
</details>
|
|
117
|
-
|
|
118
|
-
### Validation with HL7 Java Validator
|
|
119
|
-
|
|
120
|
-
The `hl7` job validates the same artifacts using the [official HL7 FHIR Validator](https://confluence.hl7.org/display/FHIR/Using+the+FHIR+Validator), the reference implementation for FHIR conformance checking:
|
|
121
|
-
|
|
122
|
-
<details><summary>Per-IG results</summary>
|
|
123
|
-
|
|
124
|
-

|
|
125
|
-

|
|
126
|
-

|
|
127
|
-

|
|
128
|
-

|
|
129
|
-

|
|
130
|
-

|
|
131
|
-

|
|
132
|
-

|
|
133
|
-

|
|
134
|
-

|
|
135
|
-

|
|
136
|
-

|
|
137
|
-

|
|
138
|
-

|
|
139
|
-

|
|
140
|
-

|
|
141
|
-

|
|
142
|
-

|
|
143
|
-

|
|
144
|
-

|
|
145
|
-

|
|
146
|
-

|
|
147
|
-

|
|
148
|
-

|
|
149
|
-

|
|
150
|
-

|
|
151
|
-

|
|
152
|
-

|
|
153
|
-
|
|
154
|
-
</details>
|
|
155
|
-
|
|
156
|
-
> External-validator badges cover the 29 R4/R4B IGs. R5 packages are generated and typechecked, but neither external validator publishes R5 badges yet.
|
|
157
|
-
|
|
158
|
-
> Terminology validation requires a tx server. The pipeline uses `--tx-server https://tx.fhir.org/{r4|r5}` (matching the package's FHIR version) during generation to expand ValueSets and produce valid codes.
|
|
159
|
-
|
|
160
|
-
📊 **[Full Report](https://max-health-inc.github.io/BabelFHIR-TS/)**
|
|
161
|
-
<!-- HL7-PARITY-BADGES:END -->
|
|
162
|
-
<!-- PARITY-BADGES:END -->
|
|
51
|
+
- **Install any FHIR profile as a node module**—use `babelfhir-ts install` to add Implementation Guides (FHIR Packages) directly to your project
|
|
163
52
|
|
|
164
53
|
## Installation
|
|
165
54
|
|
|
@@ -274,6 +163,117 @@ Full documentation is available at **[max-health-inc.github.io/BabelFHIR-TS/docs
|
|
|
274
163
|
- [Limitations](https://max-health-inc.github.io/BabelFHIR-TS/docs/limitations) — edge cases, random() caveats
|
|
275
164
|
- [Contributing](https://max-health-inc.github.io/BabelFHIR-TS/docs/contributing) — dev setup, scripts, project structure
|
|
276
165
|
|
|
166
|
+
<!-- PARITY-BADGES:START - Do not remove or modify this section -->
|
|
167
|
+
## Continuous Validation
|
|
168
|
+
|
|
169
|
+
Every push to `develop` and `main` runs the parity pipeline, which validates generated code against real-world FHIR Implementation Guides. (Pull requests run the faster `CI` workflow: typecheck, unit tests, and generated-artifact drift checks.) For each IG, the pipeline:
|
|
170
|
+
|
|
171
|
+
1. Downloads the FHIR package from a registry
|
|
172
|
+
2. Generates TypeScript interfaces, validators, and classes
|
|
173
|
+
3. Compiles the output with `tsc` (zero errors required)
|
|
174
|
+
4. Generates `empty()` and `random()` test resources for every profile
|
|
175
|
+
5. Validates those resources against two independent external FHIR validators
|
|
176
|
+
|
|
177
|
+
### Validated Implementation Guides (31)
|
|
178
|
+
|
|
179
|
+
Every parity run validates **31 real-world IGs** (29 R4, 2 R5). The list is not duplicated here — it is generated from the parity suite's own source of truth into [`parity-matrix.json`](./parity-matrix.json).
|
|
180
|
+
|
|
181
|
+
Each validated IG is also published as a ready-to-install package — `@max-health-inc/fhir-<name>` — so you do not have to generate it yourself:
|
|
182
|
+
|
|
183
|
+
**[→ Browse the FHIR IG registry](https://github.com/orgs/Max-Health-Inc/packages?ecosystem=npm&q=fhir-)**
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# GitHub Packages needs the scope mapped, and a token with read:packages
|
|
187
|
+
echo "@max-health-inc:registry=https://npm.pkg.github.com" >> .npmrc
|
|
188
|
+
npm install @max-health-inc/fhir-us-core
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Published by [Max-Health-Inc/fhir-igs](https://github.com/Max-Health-Inc/fhir-igs), which pins a babelfhir-ts version and republishes an IG only when the IG version, the pinned generator, or the generation flags actually change.
|
|
192
|
+
|
|
193
|
+
### Validation with the Firely SDK Validator
|
|
194
|
+
|
|
195
|
+
The `firely` job validates generated resources using the [Firely SDK Validator](https://docs.fire.ly/projects/Firely-NET-SDK/validation.html) (`Firely.Fhir.Validation`, v3.x) running on the Firely .NET SDK (`Hl7.Fhir`, v6.x) — two separately versioned packages. Results are published as live badges:
|
|
196
|
+
|
|
197
|
+
<details><summary>Per-IG results</summary>
|
|
198
|
+
|
|
199
|
+

|
|
200
|
+

|
|
201
|
+

|
|
202
|
+

|
|
203
|
+

|
|
204
|
+

|
|
205
|
+

|
|
206
|
+

|
|
207
|
+

|
|
208
|
+

|
|
209
|
+

|
|
210
|
+

|
|
211
|
+

|
|
212
|
+

|
|
213
|
+

|
|
214
|
+

|
|
215
|
+

|
|
216
|
+

|
|
217
|
+

|
|
218
|
+

|
|
219
|
+

|
|
220
|
+

|
|
221
|
+

|
|
222
|
+

|
|
223
|
+

|
|
224
|
+

|
|
225
|
+

|
|
226
|
+

|
|
227
|
+

|
|
228
|
+
|
|
229
|
+
</details>
|
|
230
|
+
|
|
231
|
+
### Validation with HL7 Java Validator
|
|
232
|
+
|
|
233
|
+
The `hl7` job validates the same artifacts using the [official HL7 FHIR Validator](https://confluence.hl7.org/display/FHIR/Using+the+FHIR+Validator), the reference implementation for FHIR conformance checking:
|
|
234
|
+
|
|
235
|
+
<details><summary>Per-IG results</summary>
|
|
236
|
+
|
|
237
|
+

|
|
238
|
+

|
|
239
|
+

|
|
240
|
+

|
|
241
|
+

|
|
242
|
+

|
|
243
|
+

|
|
244
|
+

|
|
245
|
+

|
|
246
|
+

|
|
247
|
+

|
|
248
|
+

|
|
249
|
+

|
|
250
|
+

|
|
251
|
+

|
|
252
|
+

|
|
253
|
+

|
|
254
|
+

|
|
255
|
+

|
|
256
|
+

|
|
257
|
+

|
|
258
|
+

|
|
259
|
+

|
|
260
|
+

|
|
261
|
+

|
|
262
|
+

|
|
263
|
+

|
|
264
|
+

|
|
265
|
+

|
|
266
|
+
|
|
267
|
+
</details>
|
|
268
|
+
|
|
269
|
+
> External-validator badges cover the 29 R4/R4B IGs. R5 packages are generated and typechecked, but neither external validator publishes R5 badges yet.
|
|
270
|
+
|
|
271
|
+
> Terminology validation requires a tx server. The pipeline uses `--tx-server https://tx.fhir.org/{r4|r5}` (matching the package's FHIR version) during generation to expand ValueSets and produce valid codes.
|
|
272
|
+
|
|
273
|
+
📊 **[Full Report](https://max-health-inc.github.io/BabelFHIR-TS/)**
|
|
274
|
+
<!-- HL7-PARITY-BADGES:END -->
|
|
275
|
+
<!-- PARITY-BADGES:END -->
|
|
276
|
+
|
|
277
277
|
## License
|
|
278
278
|
|
|
279
279
|
ISC © Maximilian Nussbaumer
|
|
@@ -5,7 +5,7 @@ import { primitivePlaceholder, generateCodeDefault, makeCodeableConcept, chooseC
|
|
|
5
5
|
import { generateSliceElement, buildNestedRequirementsObject } from './sliceElementGenerator.js';
|
|
6
6
|
import { COMPLEX_SKELETON_MAP, propKey, buildValueExpression, buildCrossReferencedEntryArray, } from './classGeneratorHelpers.js';
|
|
7
7
|
import { renderClassTemplate } from './classTemplate.js';
|
|
8
|
-
export function generateClass(className, interfaceName, baseResource, requiredFields = [], profileUrl, fieldPatterns = [], forbiddenFields = [], valueSetBindings = {}, fieldOrder = [], codeableConceptBindings = []) {
|
|
8
|
+
export function generateClass(className, interfaceName, baseResource, requiredFields = [], profileUrl, fieldPatterns = [], forbiddenFields = [], valueSetBindings = {}, fieldOrder = [], codeableConceptBindings = [], hasValueSetRegistry = false) {
|
|
9
9
|
// Decide whether to emit resourceType. If baseResource points at a known resource or ends with 'Resource'.
|
|
10
10
|
const CORE_RESOURCE_BASES = ctx().coreResourceBases;
|
|
11
11
|
const addResourceType = !!baseResource && CORE_RESOURCE_BASES.has(baseResource);
|
|
@@ -578,6 +578,6 @@ export function generateClass(className, interfaceName, baseResource, requiredFi
|
|
|
578
578
|
profileUrl, constructorMetaProfile, setterMetaProfile,
|
|
579
579
|
randomMetaProfileInit, resourceTypeLine, baseResource,
|
|
580
580
|
fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder,
|
|
581
|
-
codeableConceptBindings,
|
|
581
|
+
codeableConceptBindings, hasValueSetRegistry,
|
|
582
582
|
});
|
|
583
583
|
}
|
|
@@ -93,12 +93,13 @@ export function buildCrossReferencedEntryArray(sliceElements) {
|
|
|
93
93
|
return `(() => { ${decls.join(' ')} return [${rewritten.join(', ')}]; })()`;
|
|
94
94
|
}
|
|
95
95
|
/** Generate the static pattern/forbidden/order/binding metadata properties for a class. */
|
|
96
|
-
export function generatePatternMetadata(fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder = [], codeableConceptBindings = []
|
|
96
|
+
export function generatePatternMetadata(fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder = [], codeableConceptBindings = [],
|
|
97
|
+
/** Whether the class file imports `getRandomConceptByUrl` — see renderClassTemplate. */
|
|
98
|
+
emitCodeResolver = false) {
|
|
97
99
|
const patternMap = {};
|
|
98
100
|
for (const fp of fieldPatterns) {
|
|
99
101
|
patternMap[fp.fieldName] = fp.pattern;
|
|
100
102
|
}
|
|
101
|
-
const hasBindings = Object.keys(valueSetBindings).length > 0;
|
|
102
103
|
return `
|
|
103
104
|
/**
|
|
104
105
|
* Pattern constraints this profile fixes on its fields, keyed by field path
|
|
@@ -127,16 +128,10 @@ export function generatePatternMetadata(fieldPatterns, forbiddenFields, valueSet
|
|
|
127
128
|
*/
|
|
128
129
|
protected static readonly _codeableConceptBindings: string[] = ${JSON.stringify(codeableConceptBindings)};
|
|
129
130
|
|
|
130
|
-
/**
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (registry && typeof registry.getRandomConceptByUrl === 'function') {
|
|
136
|
-
return registry.getRandomConceptByUrl as (url: string) => { code: string; system: string; display?: string } | undefined;
|
|
137
|
-
}
|
|
138
|
-
} catch { /* ValueSetRegistry not available */ }
|
|
139
|
-
return undefined;
|
|
140
|
-
})()` : 'undefined'};
|
|
131
|
+
/**
|
|
132
|
+
* Random-example code resolver for ValueSet bindings. \`undefined\` when this package emitted no
|
|
133
|
+
* ValueSet registry; enrichResource and resolveSliceCode both fall back to a placeholder.
|
|
134
|
+
*/
|
|
135
|
+
protected static readonly _codeResolver: ((url: string) => { code: string; system: string; display?: string } | undefined) | undefined = ${emitCodeResolver ? 'getRandomConceptByUrl' : 'undefined'};
|
|
141
136
|
`;
|
|
142
137
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { COMPLEX_SKELETON_MAP, generatePatternMetadata } from './classGeneratorHelpers.js';
|
|
2
2
|
/** Render the final class file content from pre-computed template parameters. */
|
|
3
3
|
export function renderClassTemplate(params) {
|
|
4
|
-
const { interfaceName, className, requiredInitBlock, enableMetaProfile, profileUrl, constructorMetaProfile, setterMetaProfile, randomMetaProfileInit, resourceTypeLine, baseResource, fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings, } = params;
|
|
4
|
+
const { interfaceName, className, requiredInitBlock, enableMetaProfile, profileUrl, constructorMetaProfile, setterMetaProfile, randomMetaProfileInit, resourceTypeLine, baseResource, fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings, hasValueSetRegistry, } = params;
|
|
5
5
|
// Determine which skeleton helpers are actually used in requiredInitBlock
|
|
6
6
|
const usedSkeletons = new Set();
|
|
7
7
|
for (const helper of Object.values(COMPLEX_SKELETON_MAP)) {
|
|
@@ -24,14 +24,17 @@ export function renderClassTemplate(params) {
|
|
|
24
24
|
helperImports.add(helper);
|
|
25
25
|
}
|
|
26
26
|
const helperImportList = Array.from(helperImports).join(', ');
|
|
27
|
-
|
|
27
|
+
// Both halves needed: bindings can all point at ValueSets this package does not emit, and a
|
|
28
|
+
// registry with no bindings is dead weight.
|
|
29
|
+
const emitCodeResolver = Object.keys(valueSetBindings).length > 0 && hasValueSetRegistry;
|
|
28
30
|
return `
|
|
29
31
|
import { validate${interfaceName}, type ${interfaceName} } from "./${interfaceName}.js";
|
|
30
32
|
import type { ValidatorOptions } from "./ValidatorOptions.js";
|
|
31
33
|
// Only import helpers actually referenced below (dynamic based on required fields)
|
|
32
34
|
import { ${helperImportList} } from "./random/index.js";
|
|
33
|
-
${
|
|
34
|
-
|
|
35
|
+
${emitCodeResolver ? `// Static on purpose: a Node-only runtime require here dies at module init under any bundler
|
|
36
|
+
// that strips module metadata, which kept this package off Workers and Deno.
|
|
37
|
+
import { getRandomConceptByUrl } from "./valuesets/index.js";` : ''}
|
|
35
38
|
|
|
36
39
|
// Helper emitted only when meta.profile enforcement is applicable (resource profiles)
|
|
37
40
|
${enableMetaProfile ? `type WithMeta = { meta?: { profile?: string[] } };
|
|
@@ -54,7 +57,7 @@ function safeClone<T>(value: T): T {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
export class ${className} {
|
|
57
|
-
${generatePatternMetadata(fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings)}
|
|
60
|
+
${generatePatternMetadata(fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings, emitCodeResolver)}
|
|
58
61
|
private resource: ${interfaceName};
|
|
59
62
|
|
|
60
63
|
// Declared and assigned rather than written as a parameter property, which
|
|
@@ -611,11 +611,6 @@ export async function generateIntoPackage(packageArchivePath, outArchivePath, fl
|
|
|
611
611
|
// Install fhirpath type stub so tsc can resolve validator imports
|
|
612
612
|
const { installFhirpathStub, removeFhirpathStub } = await import('./emitters/validator/fhirpathStubInstaller.js');
|
|
613
613
|
installFhirpathStub(outputDir);
|
|
614
|
-
// Install minimal @types/node stub so tsc can resolve `import { createRequire } from 'module'`
|
|
615
|
-
const nodeTypesDir = path.join(outputDir, 'node_modules', '@types', 'node');
|
|
616
|
-
fs.mkdirSync(nodeTypesDir, { recursive: true });
|
|
617
|
-
fs.writeFileSync(path.join(nodeTypesDir, 'index.d.ts'), `declare module 'module' {\n export function createRequire(filename: string | URL): NodeRequire;\n}\n`);
|
|
618
|
-
fs.writeFileSync(path.join(nodeTypesDir, 'package.json'), JSON.stringify({ name: '@types/node', version: '0.0.0-stub', types: 'index.d.ts' }));
|
|
619
614
|
// Compile TypeScript to JavaScript
|
|
620
615
|
endPhase = startPhase('compile');
|
|
621
616
|
logger.log('Compiling TypeScript to JavaScript...');
|
|
@@ -623,11 +618,6 @@ export async function generateIntoPackage(packageArchivePath, outArchivePath, fl
|
|
|
623
618
|
endPhase(); // compile
|
|
624
619
|
// Remove fhirpath stub — the real package is a peer dependency
|
|
625
620
|
removeFhirpathStub(outputDir);
|
|
626
|
-
// Remove @types/node stub — only needed for compilation
|
|
627
|
-
try {
|
|
628
|
-
fs.rmSync(path.join(outputDir, 'node_modules', '@types'), { recursive: true, force: true });
|
|
629
|
-
}
|
|
630
|
-
catch { /* ignore */ }
|
|
631
621
|
// Remove base client type stubs — they were only needed for tsc to resolve
|
|
632
622
|
// @babelfhir-ts/client-<version> imports during compilation. The real package is
|
|
633
623
|
// installed by the consumer via npm.
|
|
@@ -843,19 +833,11 @@ export async function generateIntoPackageDirect(packageArchivePath, flags) {
|
|
|
843
833
|
}
|
|
844
834
|
const { installFhirpathStub, removeFhirpathStub } = await import('./emitters/validator/fhirpathStubInstaller.js');
|
|
845
835
|
installFhirpathStub(outputDir);
|
|
846
|
-
const nodeTypesDir = path.join(outputDir, 'node_modules', '@types', 'node');
|
|
847
|
-
fs.mkdirSync(nodeTypesDir, { recursive: true });
|
|
848
|
-
fs.writeFileSync(path.join(nodeTypesDir, 'index.d.ts'), `declare module 'module' {\n export function createRequire(filename: string | URL): NodeRequire;\n}\n`);
|
|
849
|
-
fs.writeFileSync(path.join(nodeTypesDir, 'package.json'), JSON.stringify({ name: '@types/node', version: '0.0.0-stub', types: 'index.d.ts' }));
|
|
850
836
|
endPhase = startPhase('compile');
|
|
851
837
|
logger.log('Compiling TypeScript to JavaScript...');
|
|
852
838
|
await compileTypeScriptToJS(outputDir);
|
|
853
839
|
endPhase(); // compile
|
|
854
840
|
removeFhirpathStub(outputDir);
|
|
855
|
-
try {
|
|
856
|
-
fs.rmSync(path.join(outputDir, 'node_modules', '@types'), { recursive: true, force: true });
|
|
857
|
-
}
|
|
858
|
-
catch { /* ignore */ }
|
|
859
841
|
const babelfhirDir = path.join(outputDir, 'node_modules', '@babelfhir-ts');
|
|
860
842
|
if (fs.existsSync(babelfhirDir)) {
|
|
861
843
|
for (const entry of fs.readdirSync(babelfhirDir)) {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Helpers and types live in sdProcessorHelpers.ts.
|
|
7
7
|
* Required-field dedup lives in sdProcessorRequiredFields.ts.
|
|
8
8
|
*/
|
|
9
|
+
import fs from 'fs';
|
|
9
10
|
import path from 'path';
|
|
10
11
|
import { generateClass } from './emitters/class/classGenerator.js';
|
|
11
12
|
import { generateInterfaces } from './emitters/interface/interfaceGenerator.js';
|
|
@@ -733,7 +734,10 @@ export async function processStructureDefinition(sd, ctx) {
|
|
|
733
734
|
}
|
|
734
735
|
// ── Emit artifacts ───────────────────────────────────────────────
|
|
735
736
|
const { fieldPatterns, forbiddenFields, valueSetBindings, codeableConceptBindings, fieldOrder } = await extractFieldPatternsAndMetadata([parsed.newFields || [], aligned.alignedNewFields || [], parsed.oldFields || []], baseResource, sd, requiredFields, candidateRequiredFields, nestedRequirementsMap, resolvedProfilePatterns);
|
|
736
|
-
|
|
737
|
+
// Read off disk, not threaded through ctx: emitValueSetFiles has already run by now, and ten
|
|
738
|
+
// call sites would otherwise carry a flag most of them always pass false.
|
|
739
|
+
const hasValueSetRegistry = fs.existsSync(path.join(outputDir, 'valuesets', 'index.ts'));
|
|
740
|
+
const classContent = generateClass(`${interfaceName}Class`, interfaceName, baseResource, requiredFields, sd.url, fieldPatterns, forbiddenFields, valueSetBindings, fieldOrder, codeableConceptBindings, hasValueSetRegistry);
|
|
737
741
|
ensureRandomSupportFile(outputDir);
|
|
738
742
|
ensureValidatorOptionsFile(outputDir);
|
|
739
743
|
writeInterfaceAndValidatorToFile(outputDir, interfaceName, finalInterfaceContent, validateFn);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "babelfhir-ts",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
4
4
|
"description": "BabelFHIR-TS: generate TypeScript interfaces, validators, and helper classes from FHIR R4/R4B/R5 StructureDefinitions (profiles) directly inside package archives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "out/src/main.js",
|