@atomic-ehr/codegen 0.0.1-canary.20250821160126.c552195 → 0.0.1-canary.20250822150706.c3b8669
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/dist/api/builder.d.ts +3 -3
- package/dist/api/builder.d.ts.map +1 -1
- package/dist/api/builder.js +374 -0
- package/dist/api/generators/base/BaseGenerator.d.ts +4 -4
- package/dist/api/generators/base/BaseGenerator.d.ts.map +1 -1
- package/dist/api/generators/base/BaseGenerator.js +572 -0
- package/dist/api/generators/base/FileManager.d.ts +2 -2
- package/dist/api/generators/base/FileManager.d.ts.map +1 -1
- package/dist/api/generators/base/FileManager.js +204 -0
- package/dist/api/generators/base/PythonTypeMapper.d.ts +2 -2
- package/dist/api/generators/base/PythonTypeMapper.d.ts.map +1 -1
- package/dist/api/generators/base/PythonTypeMapper.js +71 -0
- package/dist/api/generators/base/TemplateEngine.d.ts +1 -1
- package/dist/api/generators/base/TemplateEngine.d.ts.map +1 -1
- package/dist/api/generators/base/TemplateEngine.js +133 -0
- package/dist/api/generators/base/TypeMapper.js +153 -0
- package/dist/api/generators/base/TypeScriptTypeMapper.d.ts +1 -1
- package/dist/api/generators/base/TypeScriptTypeMapper.d.ts.map +1 -1
- package/dist/api/generators/base/TypeScriptTypeMapper.js +232 -0
- package/dist/api/generators/base/builders/DirectoryBuilder.d.ts +4 -4
- package/dist/api/generators/base/builders/DirectoryBuilder.d.ts.map +1 -1
- package/dist/api/generators/base/builders/DirectoryBuilder.js +215 -0
- package/dist/api/generators/base/builders/FileBuilder.d.ts +2 -2
- package/dist/api/generators/base/builders/FileBuilder.d.ts.map +1 -1
- package/dist/api/generators/base/builders/FileBuilder.js +408 -0
- package/dist/api/generators/base/builders/IndexBuilder.d.ts +2 -2
- package/dist/api/generators/base/builders/IndexBuilder.d.ts.map +1 -1
- package/dist/api/generators/base/builders/IndexBuilder.js +290 -0
- package/dist/api/generators/base/enhanced-errors.d.ts +2 -2
- package/dist/api/generators/base/enhanced-errors.d.ts.map +1 -1
- package/dist/api/generators/base/enhanced-errors.js +259 -0
- package/dist/api/generators/base/error-handler.d.ts +1 -1
- package/dist/api/generators/base/error-handler.d.ts.map +1 -1
- package/dist/api/generators/base/error-handler.js +243 -0
- package/dist/api/generators/base/errors.d.ts +2 -2
- package/dist/api/generators/base/errors.d.ts.map +1 -1
- package/dist/api/generators/base/errors.js +694 -0
- package/dist/api/generators/base/index.d.ts +22 -22
- package/dist/api/generators/base/index.d.ts.map +1 -1
- package/dist/api/generators/base/index.js +161 -0
- package/dist/api/generators/base/types.d.ts +2 -2
- package/dist/api/generators/base/types.d.ts.map +1 -1
- package/dist/api/generators/base/types.js +12 -0
- package/dist/api/generators/rest-client.d.ts +2 -2
- package/dist/api/generators/rest-client.d.ts.map +1 -1
- package/dist/api/generators/rest-client.js +847 -0
- package/dist/api/generators/search-parameter-enhancer.d.ts +1 -1
- package/dist/api/generators/search-parameter-enhancer.d.ts.map +1 -1
- package/dist/api/generators/search-parameter-enhancer.js +801 -0
- package/dist/api/generators/types.js +4 -0
- package/dist/api/generators/typescript.d.ts +3 -3
- package/dist/api/generators/typescript.d.ts.map +1 -1
- package/dist/api/generators/typescript.js +537 -0
- package/dist/api/generators/validation-generator.js +632 -0
- package/dist/api/index.d.ts +10 -10
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +51 -0
- package/dist/cli/commands/generate/typescript.d.ts +1 -1
- package/dist/cli/commands/generate/typescript.d.ts.map +1 -1
- package/dist/cli/commands/generate/typescript.js +52 -0
- package/dist/cli/commands/generate.d.ts +5 -12
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +158 -0
- package/dist/cli/commands/index.d.ts +2 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +100 -0
- package/dist/cli/commands/typeschema/generate.js +130 -0
- package/dist/cli/commands/typeschema.js +48 -0
- package/dist/cli/index.js +12 -8664
- package/dist/cli/utils/log.d.ts +2 -2
- package/dist/cli/utils/log.d.ts.map +1 -1
- package/dist/cli/utils/log.js +23 -0
- package/dist/cli/utils/prompts.js +224 -0
- package/dist/cli/utils/spinner.js +270 -0
- package/dist/config.d.ts +22 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +703 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +84 -38
- package/dist/logger.js +290 -0
- package/dist/typeschema/cache.d.ts +2 -2
- package/dist/typeschema/cache.d.ts.map +1 -1
- package/dist/typeschema/cache.js +285 -0
- package/dist/typeschema/core/binding.d.ts +1 -1
- package/dist/typeschema/core/binding.d.ts.map +1 -1
- package/dist/typeschema/core/binding.js +187 -0
- package/dist/typeschema/core/field-builder.d.ts +1 -1
- package/dist/typeschema/core/field-builder.d.ts.map +1 -1
- package/dist/typeschema/core/field-builder.js +259 -0
- package/dist/typeschema/core/identifier.js +117 -0
- package/dist/typeschema/core/nested-types.d.ts +1 -1
- package/dist/typeschema/core/nested-types.d.ts.map +1 -1
- package/dist/typeschema/core/nested-types.js +111 -0
- package/dist/typeschema/core/transformer.d.ts +2 -2
- package/dist/typeschema/core/transformer.d.ts.map +1 -1
- package/dist/typeschema/core/transformer.js +345 -0
- package/dist/typeschema/generator.d.ts +3 -3
- package/dist/typeschema/generator.d.ts.map +1 -1
- package/dist/typeschema/generator.js +352 -0
- package/dist/typeschema/index.d.ts +14 -14
- package/dist/typeschema/index.d.ts.map +1 -1
- package/dist/typeschema/index.js +92 -0
- package/dist/typeschema/parser.d.ts +2 -2
- package/dist/typeschema/parser.d.ts.map +1 -1
- package/dist/typeschema/parser.js +310 -0
- package/dist/typeschema/profile/processor.d.ts +1 -1
- package/dist/typeschema/profile/processor.d.ts.map +1 -1
- package/dist/typeschema/profile/processor.js +268 -0
- package/dist/typeschema/schema.js +456 -0
- package/dist/typeschema/type-schema.types.js +39 -0
- package/dist/typeschema/types.js +4 -0
- package/dist/typeschema/utils.d.ts +1 -1
- package/dist/typeschema/utils.d.ts.map +1 -1
- package/dist/typeschema/utils.js +13 -0
- package/dist/typeschema/value-set/processor.d.ts +1 -1
- package/dist/typeschema/value-set/processor.d.ts.map +1 -1
- package/dist/typeschema/value-set/processor.js +168 -0
- package/dist/utils/codegen-logger.js +204 -0
- package/dist/utils.js +42 -0
- package/package.json +15 -4
- package/dist/index-e7pfye24.js +0 -8532
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { buildEnum } from "./binding.js";
|
|
3
|
+
import { buildBindingIdentifier, buildNestedIdentifier, buildSchemaIdentifier, } from "./identifier.js";
|
|
4
|
+
/**
|
|
5
|
+
* Get the full element hierarchy for a given path
|
|
6
|
+
*/
|
|
7
|
+
export function getElementHierarchy(fhirSchema, path, _manager) {
|
|
8
|
+
const hierarchy = [];
|
|
9
|
+
// Get element at path from current schema
|
|
10
|
+
let element = fhirSchema.elements;
|
|
11
|
+
for (const key of path) {
|
|
12
|
+
element = element?.[key];
|
|
13
|
+
if (!element)
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
if (element) {
|
|
17
|
+
hierarchy.push(element);
|
|
18
|
+
}
|
|
19
|
+
// For now, we only use the current schema's element
|
|
20
|
+
// TODO: Implement base schema traversal when we have proper schema loading
|
|
21
|
+
return hierarchy;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Merge element hierarchy into a snapshot
|
|
25
|
+
*/
|
|
26
|
+
export function mergeElementHierarchy(hierarchy) {
|
|
27
|
+
// Handle empty hierarchy
|
|
28
|
+
if (hierarchy.length === 0) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
// Start with the most specific (first) element
|
|
32
|
+
const snapshot = { ...hierarchy[0] };
|
|
33
|
+
// Merge properties from base elements (reverse order to apply from base to specific)
|
|
34
|
+
for (let i = hierarchy.length - 1; i >= 0; i--) {
|
|
35
|
+
const element = hierarchy[i];
|
|
36
|
+
// Properties that should be taken from the most specific element
|
|
37
|
+
const specificProps = [
|
|
38
|
+
"choices",
|
|
39
|
+
"short",
|
|
40
|
+
"index",
|
|
41
|
+
"elements",
|
|
42
|
+
"required",
|
|
43
|
+
"excluded",
|
|
44
|
+
"binding",
|
|
45
|
+
"refers",
|
|
46
|
+
"elementReference",
|
|
47
|
+
"mustSupport",
|
|
48
|
+
"slices",
|
|
49
|
+
"slicing",
|
|
50
|
+
"url",
|
|
51
|
+
"extensions",
|
|
52
|
+
];
|
|
53
|
+
// Merge non-specific properties
|
|
54
|
+
for (const [key, value] of Object.entries(element)) {
|
|
55
|
+
if (!specificProps.includes(key) && value !== undefined) {
|
|
56
|
+
snapshot[key] = value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Override with specific properties from the first element
|
|
61
|
+
for (const prop of ["choices", "binding", "refers", "elementReference"]) {
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
if (hierarchy[0] &&
|
|
64
|
+
hierarchy[0][prop] !== undefined) {
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
snapshot[prop] = hierarchy[0][prop];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return snapshot;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check if a field is required based on parent required arrays
|
|
73
|
+
*/
|
|
74
|
+
export function isRequired(fhirSchema, path, _manager) {
|
|
75
|
+
if (path.length === 0)
|
|
76
|
+
return false;
|
|
77
|
+
const fieldName = path[path.length - 1];
|
|
78
|
+
const parentPath = path.slice(0, -1);
|
|
79
|
+
// Navigate to parent element
|
|
80
|
+
let parentElement = fhirSchema;
|
|
81
|
+
for (const key of parentPath) {
|
|
82
|
+
parentElement = parentElement.elements?.[key];
|
|
83
|
+
if (!parentElement)
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
// Check if field is in required array
|
|
87
|
+
if (parentElement?.required?.includes(fieldName)) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
// Also check at root level
|
|
91
|
+
if (parentPath.length === 0 &&
|
|
92
|
+
fieldName &&
|
|
93
|
+
fhirSchema.required?.includes(fieldName)) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check if a field is excluded
|
|
100
|
+
*/
|
|
101
|
+
export function isExcluded(fhirSchema, path, _manager) {
|
|
102
|
+
if (path.length === 0)
|
|
103
|
+
return false;
|
|
104
|
+
const fieldName = path[path.length - 1];
|
|
105
|
+
const parentPath = path.slice(0, -1);
|
|
106
|
+
// Navigate to parent element
|
|
107
|
+
let parentElement = fhirSchema;
|
|
108
|
+
for (const key of parentPath) {
|
|
109
|
+
parentElement = parentElement.elements?.[key];
|
|
110
|
+
if (!parentElement)
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
// Check if field is in excluded array
|
|
114
|
+
if (parentElement?.excluded?.includes(fieldName)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
// Also check at root level
|
|
118
|
+
if (parentPath.length === 0 &&
|
|
119
|
+
fieldName &&
|
|
120
|
+
fhirSchema.excluded?.includes(fieldName)) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Build reference array from element refers
|
|
127
|
+
*/
|
|
128
|
+
export async function buildReferences(element, manager, packageInfo) {
|
|
129
|
+
if (!element.refers || element.refers.length === 0) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
const references = [];
|
|
133
|
+
for (const ref of element.refers) {
|
|
134
|
+
try {
|
|
135
|
+
const resource = await manager.resolve(ref);
|
|
136
|
+
if (resource) {
|
|
137
|
+
references.push(buildSchemaIdentifier(resource, packageInfo));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch { }
|
|
141
|
+
}
|
|
142
|
+
return references;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build field type identifier
|
|
146
|
+
*/
|
|
147
|
+
export function buildFieldType(fhirSchema, _path, element, _manager, packageInfo) {
|
|
148
|
+
// Handle element reference (for slicing)
|
|
149
|
+
if (element.elementReference) {
|
|
150
|
+
const refPath = element.elementReference
|
|
151
|
+
.filter((_, i) => i % 2 === 1) // Get odd indices (the actual path parts)
|
|
152
|
+
.map((p) => p)
|
|
153
|
+
.filter((p) => p !== "elements"); // Remove 'elements' which is just a container
|
|
154
|
+
// Only return nested identifier if we have a non-empty path
|
|
155
|
+
if (refPath.length > 0) {
|
|
156
|
+
return buildNestedIdentifier(fhirSchema, refPath, packageInfo);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Handle normal type
|
|
160
|
+
if (element.type) {
|
|
161
|
+
const typeUrl = element.type.includes("/")
|
|
162
|
+
? element.type
|
|
163
|
+
: `http://hl7.org/fhir/StructureDefinition/${element.type}`;
|
|
164
|
+
// Always create a type identifier, even if we can't resolve
|
|
165
|
+
const kind = element.type.match(/^[a-z]/)
|
|
166
|
+
? "primitive-type"
|
|
167
|
+
: "complex-type";
|
|
168
|
+
const isStandardFhir = typeUrl.startsWith("http://hl7.org/fhir/");
|
|
169
|
+
return {
|
|
170
|
+
kind: kind,
|
|
171
|
+
package: isStandardFhir
|
|
172
|
+
? "hl7.fhir.r4.core"
|
|
173
|
+
: packageInfo?.name || "undefined",
|
|
174
|
+
version: isStandardFhir ? "4.0.1" : packageInfo?.version || "undefined",
|
|
175
|
+
name: element.type,
|
|
176
|
+
url: typeUrl,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Build a TypeSchema field from a FHIRSchema element
|
|
183
|
+
*/
|
|
184
|
+
export async function buildField(fhirSchema, path, element, manager, packageInfo) {
|
|
185
|
+
const field = {
|
|
186
|
+
array: element.array || false,
|
|
187
|
+
required: isRequired(fhirSchema, path, manager),
|
|
188
|
+
excluded: isExcluded(fhirSchema, path, manager),
|
|
189
|
+
};
|
|
190
|
+
// Add type if present
|
|
191
|
+
const type = buildFieldType(fhirSchema, path, element, manager, packageInfo);
|
|
192
|
+
if (type) {
|
|
193
|
+
field.type = type;
|
|
194
|
+
}
|
|
195
|
+
// Add cardinality
|
|
196
|
+
if (element.min !== undefined)
|
|
197
|
+
field.min = element.min;
|
|
198
|
+
if (element.max !== undefined)
|
|
199
|
+
field.max = element.max;
|
|
200
|
+
// Add choices
|
|
201
|
+
// @ts-ignore
|
|
202
|
+
if (element.choices)
|
|
203
|
+
field.choices = element.choices;
|
|
204
|
+
// @ts-ignore
|
|
205
|
+
if (element.choiceOf)
|
|
206
|
+
field.choiceOf = element.choiceOf;
|
|
207
|
+
// Add binding if present
|
|
208
|
+
if (element.binding) {
|
|
209
|
+
field.binding = buildBindingIdentifier(fhirSchema, path, element.binding.bindingName, packageInfo);
|
|
210
|
+
// Add enum for required bindings on code types
|
|
211
|
+
if (element.binding.strength === "required" && element.type === "code") {
|
|
212
|
+
const enumValues = await buildEnum(element, manager);
|
|
213
|
+
if (enumValues && enumValues.length > 0) {
|
|
214
|
+
field.enum = enumValues;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Add references
|
|
219
|
+
const references = await buildReferences(element, manager, packageInfo);
|
|
220
|
+
if (references) {
|
|
221
|
+
field.reference = references;
|
|
222
|
+
}
|
|
223
|
+
// Remove empty/default values
|
|
224
|
+
return removeEmptyValues(field);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Remove empty values from an object
|
|
228
|
+
*/
|
|
229
|
+
function removeEmptyValues(obj) {
|
|
230
|
+
const result = {};
|
|
231
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
232
|
+
if (value !== undefined && value !== null) {
|
|
233
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
result[key] = value;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Check if an element represents a nested type (BackboneElement)
|
|
243
|
+
*/
|
|
244
|
+
export function isNestedElement(element) {
|
|
245
|
+
return (element.type === "BackboneElement" ||
|
|
246
|
+
(element.elements && Object.keys(element.elements).length > 0) ||
|
|
247
|
+
false);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Build a field reference to a nested type
|
|
251
|
+
*/
|
|
252
|
+
export function buildNestedField(fhirSchema, path, element, manager, packageInfo) {
|
|
253
|
+
return {
|
|
254
|
+
type: buildNestedIdentifier(fhirSchema, path, packageInfo),
|
|
255
|
+
array: element.array || false,
|
|
256
|
+
required: isRequired(fhirSchema, path, manager),
|
|
257
|
+
excluded: isExcluded(fhirSchema, path, manager),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifier Building Utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions for creating TypeSchema identifiers from FHIRSchema entities
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Drop version suffix from canonical URL (e.g., "http://example.com|1.0.0" -> "http://example.com")
|
|
8
|
+
*/
|
|
9
|
+
export function dropVersionFromUrl(url) {
|
|
10
|
+
if (!url)
|
|
11
|
+
return undefined;
|
|
12
|
+
return url.split("|")[0];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Determine the kind of schema based on FHIRSchema properties
|
|
16
|
+
*/
|
|
17
|
+
function determineKind(fhirSchema) {
|
|
18
|
+
// Check for constraint/profile
|
|
19
|
+
if (fhirSchema.derivation === "constraint") {
|
|
20
|
+
// Distinguish between profiles and other constraints
|
|
21
|
+
// Profiles typically constrain resources or complex types and have a base type
|
|
22
|
+
if (fhirSchema.base &&
|
|
23
|
+
(fhirSchema.type === "Resource" ||
|
|
24
|
+
fhirSchema.kind === "resource" ||
|
|
25
|
+
fhirSchema.kind === "complex-type")) {
|
|
26
|
+
return "profile";
|
|
27
|
+
}
|
|
28
|
+
return "profile";
|
|
29
|
+
}
|
|
30
|
+
// Use explicit kind if available
|
|
31
|
+
if (fhirSchema.kind) {
|
|
32
|
+
switch (fhirSchema.kind) {
|
|
33
|
+
case "primitive-type":
|
|
34
|
+
return "primitive-type";
|
|
35
|
+
case "complex-type":
|
|
36
|
+
return "complex-type";
|
|
37
|
+
case "resource":
|
|
38
|
+
return "resource";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Default to resource
|
|
42
|
+
return "resource";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build identifier for primitive-type, complex-type, resource, or constraint
|
|
46
|
+
*/
|
|
47
|
+
export function buildSchemaIdentifier(fhirSchema, packageInfo) {
|
|
48
|
+
const kind = determineKind(fhirSchema);
|
|
49
|
+
return {
|
|
50
|
+
kind,
|
|
51
|
+
package: packageInfo?.name || fhirSchema.package_name || "undefined",
|
|
52
|
+
version: packageInfo?.version || fhirSchema.package_version || "undefined",
|
|
53
|
+
name: fhirSchema.name,
|
|
54
|
+
url: fhirSchema.url,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Build nested type identifier for BackboneElements
|
|
59
|
+
*/
|
|
60
|
+
export function buildNestedIdentifier(fhirSchema, path, packageInfo) {
|
|
61
|
+
const nestedName = path.join(".");
|
|
62
|
+
return {
|
|
63
|
+
kind: "nested",
|
|
64
|
+
package: packageInfo?.name || fhirSchema.package_name || "undefined",
|
|
65
|
+
version: packageInfo?.version || fhirSchema.package_version || "undefined",
|
|
66
|
+
name: nestedName,
|
|
67
|
+
url: `${fhirSchema.url}#${nestedName}`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Build value set identifier
|
|
72
|
+
*/
|
|
73
|
+
export function buildValueSetIdentifier(valueSetUrl, valueSet, packageInfo) {
|
|
74
|
+
const cleanUrl = dropVersionFromUrl(valueSetUrl) || valueSetUrl;
|
|
75
|
+
// Generate a meaningful name from the URL instead of using potentially hash-like IDs
|
|
76
|
+
let name = "unknown";
|
|
77
|
+
// First try to get the last segment of the URL path
|
|
78
|
+
const urlParts = cleanUrl.split("/");
|
|
79
|
+
const lastSegment = urlParts[urlParts.length - 1];
|
|
80
|
+
if (lastSegment && lastSegment.length > 0) {
|
|
81
|
+
// Convert kebab-case or snake_case to PascalCase for better readability
|
|
82
|
+
name = lastSegment
|
|
83
|
+
.split(/[-_]/)
|
|
84
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
85
|
+
.join("");
|
|
86
|
+
}
|
|
87
|
+
// Only fall back to valueSet.id if we couldn't extract a meaningful name from URL
|
|
88
|
+
// and the ID doesn't look like a hash (no long alphanumeric strings)
|
|
89
|
+
if (name === "unknown" &&
|
|
90
|
+
valueSet?.id &&
|
|
91
|
+
!/^[a-zA-Z0-9_-]{20,}$/.test(valueSet.id)) {
|
|
92
|
+
name = valueSet.id;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
kind: "value-set",
|
|
96
|
+
package: packageInfo?.name || valueSet?.package_name || "undefined",
|
|
97
|
+
version: packageInfo?.version || valueSet?.package_version || "undefined",
|
|
98
|
+
name,
|
|
99
|
+
url: cleanUrl,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build binding identifier for an element with value set binding
|
|
104
|
+
*/
|
|
105
|
+
export function buildBindingIdentifier(fhirSchema, path, bindingName, packageInfo) {
|
|
106
|
+
const pathStr = path.join(".");
|
|
107
|
+
const name = bindingName || `${fhirSchema.name}.${pathStr}_binding`;
|
|
108
|
+
return {
|
|
109
|
+
kind: "binding",
|
|
110
|
+
package: packageInfo?.name || fhirSchema.package_name || "undefined",
|
|
111
|
+
version: packageInfo?.version || fhirSchema.package_version || "undefined",
|
|
112
|
+
name,
|
|
113
|
+
url: bindingName
|
|
114
|
+
? `urn:fhir:binding:${name}`
|
|
115
|
+
: `${fhirSchema.url}#${pathStr}_binding`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { CanonicalManager } from "@atomic-ehr/fhir-canonical-manager";
|
|
7
7
|
import type { FHIRSchema, FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
8
|
-
import type { PackageInfo, TypeSchemaField, TypeSchemaIdentifier } from "../types";
|
|
8
|
+
import type { PackageInfo, TypeSchemaField, TypeSchemaIdentifier } from "../types.js";
|
|
9
9
|
/**
|
|
10
10
|
* Collect all nested elements from a FHIRSchema
|
|
11
11
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-types.d.ts","sourceRoot":"","sources":["../../../src/typeschema/core/nested-types.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EACX,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,MAAM,
|
|
1
|
+
{"version":3,"file":"nested-types.d.ts","sourceRoot":"","sources":["../../../src/typeschema/core/nested-types.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EACX,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,MAAM,aAAa,CAAC;AAQrB;;GAEG;AACH,wBAAgB,qBAAqB,CACpC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,MAAM,EAAE,EACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GACzC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAkBtC;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC5C,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,MAAM,EAAE,EACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAC3C,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EAC5C,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CA4B1C;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACrC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EAC5C,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,GAAG,EAAE,CAAC,CAgEhB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACxC,WAAW,EAAE,oBAAoB,EAAE,GACjC,oBAAoB,EAAE,CAwBxB"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { buildField, buildNestedField, isNestedElement, } from "./field-builder.js";
|
|
3
|
+
import { buildNestedIdentifier } from "./identifier.js";
|
|
4
|
+
/**
|
|
5
|
+
* Collect all nested elements from a FHIRSchema
|
|
6
|
+
*/
|
|
7
|
+
export function collectNestedElements(fhirSchema, parentPath, elements) {
|
|
8
|
+
const nested = [];
|
|
9
|
+
for (const [key, element] of Object.entries(elements)) {
|
|
10
|
+
const path = [...parentPath, key];
|
|
11
|
+
// Add this element if it's nested (BackboneElement or has elements)
|
|
12
|
+
if (isNestedElement(element)) {
|
|
13
|
+
nested.push([path, element]);
|
|
14
|
+
}
|
|
15
|
+
// Recursively collect from child elements
|
|
16
|
+
if (element.elements) {
|
|
17
|
+
nested.push(...collectNestedElements(fhirSchema, path, element.elements));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return nested;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Transform elements into fields for a nested type
|
|
24
|
+
*/
|
|
25
|
+
export async function transformNestedElements(fhirSchema, parentPath, elements, manager, packageInfo) {
|
|
26
|
+
const fields = {};
|
|
27
|
+
for (const [key, element] of Object.entries(elements)) {
|
|
28
|
+
const path = [...parentPath, key];
|
|
29
|
+
if (isNestedElement(element)) {
|
|
30
|
+
// Reference to another nested type
|
|
31
|
+
fields[key] = buildNestedField(fhirSchema, path, element, manager, packageInfo);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Regular field
|
|
35
|
+
fields[key] = await buildField(fhirSchema, path, element, manager, packageInfo);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return fields;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build TypeSchema for all nested types in a FHIRSchema
|
|
42
|
+
*/
|
|
43
|
+
export async function buildNestedTypes(fhirSchema, manager, packageInfo) {
|
|
44
|
+
if (!fhirSchema.elements)
|
|
45
|
+
return [];
|
|
46
|
+
const nestedTypes = [];
|
|
47
|
+
const nestedElements = collectNestedElements(fhirSchema, [], fhirSchema.elements);
|
|
48
|
+
// Filter to only include elements that have sub-elements (actual nested types)
|
|
49
|
+
const actualNested = nestedElements.filter(([_, element]) => element.elements && Object.keys(element.elements).length > 0);
|
|
50
|
+
for (const [path, element] of actualNested) {
|
|
51
|
+
const identifier = buildNestedIdentifier(fhirSchema, path, packageInfo);
|
|
52
|
+
// Base is usually BackboneElement - ensure all nested types have a base
|
|
53
|
+
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
|
54
|
+
let base;
|
|
55
|
+
if (element.type === "BackboneElement" || !element.type) {
|
|
56
|
+
// For BackboneElement or undefined type, always use BackboneElement as base
|
|
57
|
+
base = {
|
|
58
|
+
kind: "complex-type",
|
|
59
|
+
package: packageInfo?.name || "hl7.fhir.r4.core",
|
|
60
|
+
version: packageInfo?.version || "4.0.1",
|
|
61
|
+
name: "BackboneElement",
|
|
62
|
+
url: "http://hl7.org/fhir/StructureDefinition/BackboneElement",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// Use the specified type as base
|
|
67
|
+
base = {
|
|
68
|
+
kind: "complex-type",
|
|
69
|
+
package: packageInfo?.name || "hl7.fhir.r4.core",
|
|
70
|
+
version: packageInfo?.version || "4.0.1",
|
|
71
|
+
name: element.type,
|
|
72
|
+
url: `http://hl7.org/fhir/StructureDefinition/${element.type}`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Transform sub-elements into fields
|
|
76
|
+
const fields = await transformNestedElements(fhirSchema, path, element.elements, manager, packageInfo);
|
|
77
|
+
const nestedType = {
|
|
78
|
+
identifier,
|
|
79
|
+
base, // Always include base
|
|
80
|
+
fields,
|
|
81
|
+
};
|
|
82
|
+
nestedTypes.push(nestedType);
|
|
83
|
+
}
|
|
84
|
+
// Sort by URL for consistent output
|
|
85
|
+
nestedTypes.sort((a, b) => a.identifier.url.localeCompare(b.identifier.url));
|
|
86
|
+
return nestedTypes;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Extract dependencies from nested types
|
|
90
|
+
*/
|
|
91
|
+
export function extractNestedDependencies(nestedTypes) {
|
|
92
|
+
const deps = [];
|
|
93
|
+
for (const nested of nestedTypes) {
|
|
94
|
+
// Add the nested type itself as a dependency
|
|
95
|
+
deps.push(nested.identifier);
|
|
96
|
+
// Add base dependency
|
|
97
|
+
if (nested.base) {
|
|
98
|
+
deps.push(nested.base);
|
|
99
|
+
}
|
|
100
|
+
// Add field type dependencies
|
|
101
|
+
for (const field of Object.values(nested.fields)) {
|
|
102
|
+
if ("type" in field && field.type) {
|
|
103
|
+
deps.push(field.type);
|
|
104
|
+
}
|
|
105
|
+
if ("binding" in field && field.binding) {
|
|
106
|
+
deps.push(field.binding);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return deps;
|
|
111
|
+
}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { CanonicalManager } from "@atomic-ehr/fhir-canonical-manager";
|
|
7
7
|
import type { FHIRSchema, FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
8
|
-
import type { TypeSchema, TypeSchemaField } from "../type-schema.types";
|
|
9
|
-
import type { PackageInfo } from "../types";
|
|
8
|
+
import type { TypeSchema, TypeSchemaField } from "../type-schema.types.js";
|
|
9
|
+
import type { PackageInfo } from "../types.js";
|
|
10
10
|
/**
|
|
11
11
|
* Transform elements into fields
|
|
12
12
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.d.ts","sourceRoot":"","sources":["../../../src/typeschema/core/transformer.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,OAAO,KAAK,EACX,UAAU,EACV,eAAe,EAGf,MAAM,
|
|
1
|
+
{"version":3,"file":"transformer.d.ts","sourceRoot":"","sources":["../../../src/typeschema/core/transformer.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,OAAO,KAAK,EACX,UAAU,EACV,eAAe,EAGf,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAY/C;;GAEG;AACH,wBAAsB,iBAAiB,CACtC,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,MAAM,EAAE,EACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAC3C,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EAC5C,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAiC1C;AAqOD;;;GAGG;AACH,wBAAsB,mBAAmB,CACxC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EAC5C,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,UAAU,EAAE,CAAC,CAmMvB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACzC,WAAW,EAAE,UAAU,EAAE,EACzB,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EAC5C,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,UAAU,EAAE,CAAC,CASvB"}
|