babelfhir-ts 1.5.3 → 1.5.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.
|
@@ -30,7 +30,7 @@ export function generateBackboneSliceTypes(ctx) {
|
|
|
30
30
|
const { interfaceName, baseResource, newFields, baseFields, interfaces, importManager, inferBackboneType } = ctx;
|
|
31
31
|
const rules = getRules();
|
|
32
32
|
// 1. Find all sliced backbone element arrays
|
|
33
|
-
const sliceGroups = collectSliceGroups(newFields, baseResource);
|
|
33
|
+
const sliceGroups = collectSliceGroups(newFields, baseFields, baseResource);
|
|
34
34
|
if (sliceGroups.length === 0)
|
|
35
35
|
return;
|
|
36
36
|
for (const group of sliceGroups) {
|
|
@@ -109,10 +109,18 @@ export function generateBackboneSliceTypes(ctx) {
|
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
111
|
* Collect sliced backbone element groups from the fields.
|
|
112
|
+
*
|
|
113
|
+
* Handles two scenarios:
|
|
114
|
+
* 1. The differential includes the unsliced parent field (e.g. Observation.component) —
|
|
115
|
+
* the parent field carries slicing metadata and baseTypeCode.
|
|
116
|
+
* 2. The differential only contains slice entries (e.g. Observation.component:confidence)
|
|
117
|
+
* without redeclaring the parent — common in downstream profiles. In this case the
|
|
118
|
+
* parent field is looked up from baseFields.
|
|
112
119
|
*/
|
|
113
|
-
function collectSliceGroups(fields, baseResource) {
|
|
120
|
+
function collectSliceGroups(fields, baseFields, baseResource) {
|
|
114
121
|
const groups = [];
|
|
115
122
|
const seenPaths = new Set();
|
|
123
|
+
// Pass 1: parent field present in newFields
|
|
116
124
|
for (const field of fields) {
|
|
117
125
|
if (field.sliceName)
|
|
118
126
|
continue; // Skip slice entries themselves
|
|
@@ -121,48 +129,71 @@ function collectSliceGroups(fields, baseResource) {
|
|
|
121
129
|
const path = field.name;
|
|
122
130
|
if (seenPaths.has(path))
|
|
123
131
|
continue;
|
|
124
|
-
// Check if there are named slices at this path
|
|
125
132
|
const sliceFields = fields.filter(f => f.name === path && f.sliceName);
|
|
126
133
|
if (sliceFields.length === 0)
|
|
127
134
|
continue;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
if (!isEligibleBackbonePath(field.baseTypeCode || field.type || '', path, baseResource))
|
|
136
|
+
continue;
|
|
137
|
+
const childFields = gatherChildFields(fields, path);
|
|
138
|
+
const slicingRules = field.slicingRules || 'open';
|
|
139
|
+
seenPaths.add(path);
|
|
140
|
+
groups.push({ parentField: field, sliceFields, childFields, slicingRules });
|
|
141
|
+
}
|
|
142
|
+
// Pass 2: orphaned slice entries whose parent path wasn't found in newFields.
|
|
143
|
+
// The differential may only contain slice entries (e.g. Observation.component:confidence)
|
|
144
|
+
// without the unsliced parent. Resolve the parent from baseFields.
|
|
145
|
+
for (const field of fields) {
|
|
146
|
+
if (!field.sliceName)
|
|
147
|
+
continue;
|
|
148
|
+
const path = field.name;
|
|
149
|
+
if (seenPaths.has(path))
|
|
134
150
|
continue;
|
|
135
|
-
//
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
151
|
+
// Find the parent field in baseFields
|
|
152
|
+
const parentField = baseFields.find(f => f.name === path && !f.sliceName);
|
|
153
|
+
if (!parentField)
|
|
138
154
|
continue;
|
|
139
|
-
|
|
140
|
-
// type references that are handled by the external profile resolution system
|
|
141
|
-
if (fieldName === 'entry')
|
|
155
|
+
if (!parentField.isArray)
|
|
142
156
|
continue;
|
|
143
|
-
|
|
144
|
-
const parts = path.split('.');
|
|
145
|
-
if (parts.length !== 2)
|
|
157
|
+
if (!isEligibleBackbonePath(parentField.baseTypeCode || parentField.type || '', path, baseResource))
|
|
146
158
|
continue;
|
|
147
|
-
|
|
159
|
+
const sliceFields = fields.filter(f => f.name === path && f.sliceName);
|
|
160
|
+
if (sliceFields.length === 0)
|
|
148
161
|
continue;
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
if (f.name === path)
|
|
152
|
-
return false; // Skip the parent itself
|
|
153
|
-
const childId = f.elementId || f.name;
|
|
154
|
-
// Match children that belong to ANY slice of this element
|
|
155
|
-
return childId.startsWith(`${path}:`) || (f.name.startsWith(`${path}.`) && f.name !== path);
|
|
156
|
-
});
|
|
157
|
-
// Determine slicing rules from the parent field's metadata
|
|
158
|
-
// The slicing rules come from the SD's element.slicing.rules
|
|
159
|
-
// We default to 'open' since that's the FHIR default
|
|
160
|
-
const slicingRules = field.slicingRules || 'open';
|
|
162
|
+
const childFields = gatherChildFields(fields, path);
|
|
163
|
+
const slicingRules = parentField.slicingRules || 'open';
|
|
161
164
|
seenPaths.add(path);
|
|
162
|
-
groups.push({ parentField
|
|
165
|
+
groups.push({ parentField, sliceFields, childFields, slicingRules });
|
|
163
166
|
}
|
|
164
167
|
return groups;
|
|
165
168
|
}
|
|
169
|
+
/** Check whether a field path is eligible for backbone slice typing. */
|
|
170
|
+
function isEligibleBackbonePath(baseType, path, baseResource) {
|
|
171
|
+
if (baseType !== 'BackboneElement' && baseType !== 'Element')
|
|
172
|
+
return false;
|
|
173
|
+
const fieldName = path.split('.').pop() || '';
|
|
174
|
+
// Skip extension slices — handled separately by postProcessExtensions
|
|
175
|
+
if (fieldName === 'extension' || fieldName === 'modifierExtension')
|
|
176
|
+
return false;
|
|
177
|
+
// Skip Bundle.entry and similar resource-container slices
|
|
178
|
+
if (fieldName === 'entry')
|
|
179
|
+
return false;
|
|
180
|
+
// Must be a root-level field (direct child of the base resource)
|
|
181
|
+
const parts = path.split('.');
|
|
182
|
+
if (parts.length !== 2)
|
|
183
|
+
return false;
|
|
184
|
+
if (baseResource && parts[0] !== baseResource)
|
|
185
|
+
return false;
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
/** Gather all child fields for any slice of the given parent path. */
|
|
189
|
+
function gatherChildFields(fields, path) {
|
|
190
|
+
return fields.filter(f => {
|
|
191
|
+
if (f.name === path)
|
|
192
|
+
return false;
|
|
193
|
+
const childId = f.elementId || f.name;
|
|
194
|
+
return childId.startsWith(`${path}:`) || (f.name.startsWith(`${path}.`) && f.name !== path);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
166
197
|
/**
|
|
167
198
|
* Build the body lines for a slice-specific interface.
|
|
168
199
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "babelfhir-ts",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.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",
|