babelfhir-ts 1.5.15 → 1.5.16
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.
|
@@ -456,9 +456,9 @@ function generatePatternCodingValidation(slice, relPath, errorPath, sliceLabel,
|
|
|
456
456
|
if (isNestedInOptionalSlice) {
|
|
457
457
|
out.push(`
|
|
458
458
|
// Required slice validation for ${relPath}:${sliceLabel} (nested in array: ${arrayParentPath}, parent slice is optional)
|
|
459
|
-
if (
|
|
459
|
+
if (resource.${arrayParentPath} && Array.isArray(resource.${arrayParentPath}) && resource.${arrayParentPath}.length > 0) {
|
|
460
460
|
const ${varName}Elements: Array<{ system?: string; code?: string }> = [];
|
|
461
|
-
for (const item of
|
|
461
|
+
for (const item of resource.${arrayParentPath}) {
|
|
462
462
|
const nestedArray = item.${optionalPath};
|
|
463
463
|
if (nestedArray && Array.isArray(nestedArray)) {
|
|
464
464
|
for (const coding of nestedArray) { if (${matchExpr.replace(/item\./g, 'coding.')}) ${varName}Elements.push(coding); }
|
|
@@ -473,9 +473,9 @@ function generatePatternCodingValidation(slice, relPath, errorPath, sliceLabel,
|
|
|
473
473
|
out.push(`
|
|
474
474
|
// Required slice validation for ${relPath}:${sliceLabel} (nested in array: ${arrayParentPath})
|
|
475
475
|
// Only check when parent array exists — parent absence is reported by separate required-field checks
|
|
476
|
-
if (
|
|
476
|
+
if (resource.${arrayParentPath} && Array.isArray(resource.${arrayParentPath})) {
|
|
477
477
|
const ${varName}Elements: Array<{ system?: string; code?: string }> = [];
|
|
478
|
-
for (const item of
|
|
478
|
+
for (const item of resource.${arrayParentPath}) {
|
|
479
479
|
const nestedArray = item.${optionalPath};
|
|
480
480
|
if (nestedArray && Array.isArray(nestedArray)) {
|
|
481
481
|
for (const coding of nestedArray) { if (${matchExpr.replace(/item\./g, 'coding.')}) ${varName}Elements.push(coding); }
|
|
@@ -496,9 +496,9 @@ function generatePatternCodingValidation(slice, relPath, errorPath, sliceLabel,
|
|
|
496
496
|
out.push(`
|
|
497
497
|
// Required slice validation for ${relPath}:${sliceLabel}
|
|
498
498
|
// Only check nested slice if parent field exists (parent absence is already reported separately)
|
|
499
|
-
if (
|
|
500
|
-
if (
|
|
501
|
-
const ${varName}Elements = (
|
|
499
|
+
if (resource.${parentPath}) {
|
|
500
|
+
if (resource.${optionalPath} && Array.isArray(resource.${optionalPath})) {
|
|
501
|
+
const ${varName}Elements = (resource.${optionalPath} as Array<{ system?: string; code?: string }>).filter((item) =>
|
|
502
502
|
${matchExpr}
|
|
503
503
|
);
|
|
504
504
|
if (${varName}Elements.length < ${min}) {
|
|
@@ -512,8 +512,8 @@ function generatePatternCodingValidation(slice, relPath, errorPath, sliceLabel,
|
|
|
512
512
|
else {
|
|
513
513
|
out.push(`
|
|
514
514
|
// Required slice validation for ${relPath}:${sliceLabel}
|
|
515
|
-
if (
|
|
516
|
-
const ${varName}Elements = (
|
|
515
|
+
if (resource.${optionalPath} && Array.isArray(resource.${optionalPath})) {
|
|
516
|
+
const ${varName}Elements = (resource.${optionalPath} as Array<{ system?: string; code?: string }>).filter((item) =>
|
|
517
517
|
${matchExpr}
|
|
518
518
|
);
|
|
519
519
|
if (${varName}Elements.length < ${min}) {
|
|
@@ -627,8 +627,8 @@ function generateProfiledChildDelegation(slice, relPath, childFieldsWithFixedVal
|
|
|
627
627
|
out.push(`
|
|
628
628
|
// Profiled sub-resource delegation for ${relPath}:${sliceLabel}.${childRelPath} → ${delegateName}
|
|
629
629
|
{
|
|
630
|
-
if (
|
|
631
|
-
for (const _parentItem of
|
|
630
|
+
if (resource.${arrayParentPath} && Array.isArray(resource.${arrayParentPath})) {
|
|
631
|
+
for (const _parentItem of resource.${arrayParentPath}) {
|
|
632
632
|
const _pi: any = _parentItem;
|
|
633
633
|
const _nestedArr = _pi?.${remainingPath};
|
|
634
634
|
if (_nestedArr && Array.isArray(_nestedArr)) {
|
|
@@ -775,9 +775,9 @@ function generateProfileDiscriminatorValidation(slice, relPath, errorPath, slice
|
|
|
775
775
|
const { resourceType, profileUrls } = match;
|
|
776
776
|
const max = typeof slice.max === 'number' && slice.max !== Infinity ? slice.max : undefined;
|
|
777
777
|
const parentPath = relPath.includes('.') ? relPath.split('.').slice(0, -1).join('.') : '';
|
|
778
|
-
const accessor = parentPath ? `(resource as any)?.${parentPath.replace(/\./g, '?.')}` : `
|
|
778
|
+
const accessor = parentPath ? `(resource as any)?.${parentPath.replace(/\./g, '?.')}` : `resource.${relPath}`;
|
|
779
779
|
// For top-level entry slices, access resource.entry directly
|
|
780
|
-
const arrayAccessor = relPath === 'entry' || !relPath.includes('.') ? `
|
|
780
|
+
const arrayAccessor = relPath === 'entry' || !relPath.includes('.') ? `resource.${relPath}` : accessor;
|
|
781
781
|
// Resolve profiled validator for delegation
|
|
782
782
|
let delegateInterfaceName;
|
|
783
783
|
if (ctx.profileUrlToName && ctx.validatorImports) {
|
|
@@ -102,12 +102,39 @@ function copyFhirAmbientDeclaration(outputDir) {
|
|
|
102
102
|
log.warn(`Warning: ${dtsFileName} not found. Run: npm run generate:fhir-module`);
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Locate the `@types` directory that ships with babelfhir-ts itself (the one
|
|
107
|
+
* containing `@types/fhir`). The generated output imports base FHIR types via the
|
|
108
|
+
* ambient `fhir/r4` module, which aliases `fhir4.*` from `@types/fhir`. Under
|
|
109
|
+
* `--skip-install` the generated package's own dependencies (including
|
|
110
|
+
* `@types/fhir`) are never installed into its `node_modules`, so the output
|
|
111
|
+
* typecheck would resolve `fhir4.Observation` to an empty type and any validator
|
|
112
|
+
* accessing a base-inherited field not restated locally (e.g. `Observation.code`
|
|
113
|
+
* on a profile that only slices `code.coding`) would fail TS2339. Pointing
|
|
114
|
+
* `typeRoots` at babelfhir's own always-present `@types` makes the typecheck
|
|
115
|
+
* robust regardless of the output's install state.
|
|
116
|
+
*/
|
|
117
|
+
function resolveGeneratorTypeRoots() {
|
|
118
|
+
let dir = __generatorDir;
|
|
119
|
+
for (let i = 0; i < 6; i++) {
|
|
120
|
+
const atTypes = path.join(dir, 'node_modules', '@types');
|
|
121
|
+
if (fs.existsSync(path.join(atTypes, 'fhir')))
|
|
122
|
+
return [atTypes];
|
|
123
|
+
const parent = path.dirname(dir);
|
|
124
|
+
if (parent === dir)
|
|
125
|
+
break;
|
|
126
|
+
dir = parent;
|
|
127
|
+
}
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
105
130
|
/** Compile TypeScript files to JavaScript with declaration files */
|
|
106
131
|
async function compileTypeScriptToJS(dir) {
|
|
107
132
|
return new Promise((resolve, reject) => {
|
|
108
133
|
const tscCmd = process.platform === 'win32' ? 'tsc.cmd' : 'tsc';
|
|
109
134
|
// Create a temporary tsconfig.json for compilation
|
|
110
|
-
// Paths are relative to tsconfig location (which is `dir` itself)
|
|
135
|
+
// Paths are relative to tsconfig location (which is `dir` itself); the
|
|
136
|
+
// generator's own @types (absolute) is appended so `@types/fhir` resolves
|
|
137
|
+
// even when the output's deps were skipped (see resolveGeneratorTypeRoots).
|
|
111
138
|
const tsconfig = {
|
|
112
139
|
compilerOptions: {
|
|
113
140
|
target: 'ES2020',
|
|
@@ -121,7 +148,7 @@ async function compileTypeScriptToJS(dir) {
|
|
|
121
148
|
allowSyntheticDefaultImports: true,
|
|
122
149
|
strict: true,
|
|
123
150
|
resolveJsonModule: true,
|
|
124
|
-
typeRoots: ['./node_modules/@types'],
|
|
151
|
+
typeRoots: ['./node_modules/@types', ...resolveGeneratorTypeRoots()],
|
|
125
152
|
types: ['node']
|
|
126
153
|
},
|
|
127
154
|
include: ['./**/*.ts'],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "babelfhir-ts",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.16",
|
|
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",
|