@atomic-ehr/codegen 0.0.1-canary.20250930151649.b68ce8a → 0.0.1-canary.20251001124254.ddbda7d
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/index.d.ts +1 -1
- package/dist/cli/index.js +19 -19
- package/dist/typeschema/core/field-builder.d.ts +5 -22
- package/dist/typeschema/core/field-builder.js +18 -95
- package/dist/typeschema/core/identifier.d.ts +1 -1
- package/dist/typeschema/core/identifier.js +1 -1
- package/dist/typeschema/core/nested-types.d.ts +4 -13
- package/dist/typeschema/core/nested-types.js +9 -25
- package/dist/typeschema/core/transformer.d.ts +3 -3
- package/dist/typeschema/core/transformer.js +29 -15
- package/dist/typeschema/profile/processor.js +7 -5
- package/dist/typeschema/register.d.ts +1 -1
- package/dist/typeschema/register.js +11 -5
- package/dist/typeschema/types.d.ts +7 -14
- package/package.json +1 -1
|
@@ -6,31 +6,14 @@
|
|
|
6
6
|
import type { CanonicalManager } from "@atomic-ehr/fhir-canonical-manager";
|
|
7
7
|
import type { FHIRSchema, FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
8
8
|
import type { Register } from "@root/typeschema/register";
|
|
9
|
-
import type { Identifier, PackageMeta,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*/
|
|
13
|
-
export declare function getElementHierarchy(fhirSchema: FHIRSchema, path: string[], _manager: ReturnType<typeof CanonicalManager>): FHIRSchemaElement[];
|
|
14
|
-
/**
|
|
15
|
-
* Merge element hierarchy into a snapshot
|
|
16
|
-
*/
|
|
17
|
-
export declare function mergeElementHierarchy(hierarchy: FHIRSchemaElement[]): FHIRSchemaElement;
|
|
18
|
-
/**
|
|
19
|
-
* Check if a field is required based on parent required arrays
|
|
20
|
-
*/
|
|
21
|
-
export declare function isRequired(fhirSchema: FHIRSchema, path: string[], _manager: ReturnType<typeof CanonicalManager>): boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Check if a field is excluded
|
|
24
|
-
*/
|
|
25
|
-
export declare function isExcluded(fhirSchema: FHIRSchema, path: string[], _manager: ReturnType<typeof CanonicalManager>): boolean;
|
|
9
|
+
import type { Field, Identifier, PackageMeta, RegularField, RichFHIRSchema } from "../types";
|
|
10
|
+
export declare function isRequired(fhirSchema: FHIRSchema, path: string[]): boolean;
|
|
11
|
+
export declare function isExcluded(fhirSchema: FHIRSchema, path: string[]): boolean;
|
|
26
12
|
export declare const buildReferences: (element: FHIRSchemaElement, register: Register, _packageInfo?: PackageMeta) => Identifier[] | undefined;
|
|
27
13
|
/**
|
|
28
14
|
* Build field type identifier
|
|
29
15
|
*/
|
|
30
16
|
export declare function buildFieldType(fhirSchema: RichFHIRSchema, _path: string[], element: FHIRSchemaElement, _manager: ReturnType<typeof CanonicalManager>, packageInfo?: PackageMeta): Identifier | undefined;
|
|
31
|
-
export declare const buildField: (fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement, register: Register, packageInfo?: PackageMeta) =>
|
|
32
|
-
/**
|
|
33
|
-
* Check if an element represents a nested type (BackboneElement)
|
|
34
|
-
*/
|
|
17
|
+
export declare const buildField: (fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement, register: Register, packageInfo?: PackageMeta) => Field;
|
|
35
18
|
export declare function isNestedElement(element: FHIRSchemaElement): boolean;
|
|
36
|
-
export declare function mkNestedField(fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement
|
|
19
|
+
export declare function mkNestedField(_register: Register, fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement): RegularField;
|
|
@@ -5,76 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { buildEnum } from "./binding";
|
|
7
7
|
import { mkBindingIdentifier, mkIdentifier, mkNestedIdentifier } from "./identifier";
|
|
8
|
-
|
|
9
|
-
* Get the full element hierarchy for a given path
|
|
10
|
-
*/
|
|
11
|
-
export function getElementHierarchy(fhirSchema, path, _manager) {
|
|
12
|
-
const hierarchy = [];
|
|
13
|
-
// Get element at path from current schema
|
|
14
|
-
let element = fhirSchema.elements;
|
|
15
|
-
for (const key of path) {
|
|
16
|
-
element = element?.[key];
|
|
17
|
-
if (!element)
|
|
18
|
-
break;
|
|
19
|
-
}
|
|
20
|
-
if (element) {
|
|
21
|
-
hierarchy.push(element);
|
|
22
|
-
}
|
|
23
|
-
// For now, we only use the current schema's element
|
|
24
|
-
// TODO: Implement base schema traversal when we have proper schema loading
|
|
25
|
-
return hierarchy;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Merge element hierarchy into a snapshot
|
|
29
|
-
*/
|
|
30
|
-
export function mergeElementHierarchy(hierarchy) {
|
|
31
|
-
// Handle empty hierarchy
|
|
32
|
-
if (hierarchy.length === 0) {
|
|
33
|
-
return {};
|
|
34
|
-
}
|
|
35
|
-
// Start with the most specific (first) element
|
|
36
|
-
const snapshot = { ...hierarchy[0] };
|
|
37
|
-
// Merge properties from base elements (reverse order to apply from base to specific)
|
|
38
|
-
for (let i = hierarchy.length - 1; i >= 0; i--) {
|
|
39
|
-
const element = hierarchy[i];
|
|
40
|
-
// Properties that should be taken from the most specific element
|
|
41
|
-
const specificProps = [
|
|
42
|
-
"choices",
|
|
43
|
-
"short",
|
|
44
|
-
"index",
|
|
45
|
-
"elements",
|
|
46
|
-
"required",
|
|
47
|
-
"excluded",
|
|
48
|
-
"binding",
|
|
49
|
-
"refers",
|
|
50
|
-
"elementReference",
|
|
51
|
-
"mustSupport",
|
|
52
|
-
"slices",
|
|
53
|
-
"slicing",
|
|
54
|
-
"url",
|
|
55
|
-
"extensions",
|
|
56
|
-
];
|
|
57
|
-
// Merge non-specific properties
|
|
58
|
-
for (const [key, value] of Object.entries(element)) {
|
|
59
|
-
if (!specificProps.includes(key) && value !== undefined) {
|
|
60
|
-
snapshot[key] = value;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
// Override with specific properties from the first element
|
|
65
|
-
for (const prop of ["choices", "binding", "refers", "elementReference"]) {
|
|
66
|
-
// @ts-ignore
|
|
67
|
-
if (hierarchy[0] && hierarchy[0][prop] !== undefined) {
|
|
68
|
-
// @ts-ignore
|
|
69
|
-
snapshot[prop] = hierarchy[0][prop];
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return snapshot;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Check if a field is required based on parent required arrays
|
|
76
|
-
*/
|
|
77
|
-
export function isRequired(fhirSchema, path, _manager) {
|
|
8
|
+
export function isRequired(fhirSchema, path) {
|
|
78
9
|
if (path.length === 0)
|
|
79
10
|
return false;
|
|
80
11
|
const fieldName = path[path.length - 1];
|
|
@@ -96,10 +27,7 @@ export function isRequired(fhirSchema, path, _manager) {
|
|
|
96
27
|
}
|
|
97
28
|
return false;
|
|
98
29
|
}
|
|
99
|
-
|
|
100
|
-
* Check if a field is excluded
|
|
101
|
-
*/
|
|
102
|
-
export function isExcluded(fhirSchema, path, _manager) {
|
|
30
|
+
export function isExcluded(fhirSchema, path) {
|
|
103
31
|
if (path.length === 0)
|
|
104
32
|
return false;
|
|
105
33
|
const fieldName = path[path.length - 1];
|
|
@@ -174,8 +102,8 @@ export const buildField = (fhirSchema, path, element, register, packageInfo) =>
|
|
|
174
102
|
}
|
|
175
103
|
return {
|
|
176
104
|
type: buildFieldType(fhirSchema, path, element, register, packageInfo),
|
|
177
|
-
required: isRequired(fhirSchema, path
|
|
178
|
-
excluded: isExcluded(fhirSchema, path
|
|
105
|
+
required: isRequired(fhirSchema, path),
|
|
106
|
+
excluded: isExcluded(fhirSchema, path),
|
|
179
107
|
reference: buildReferences(element, register, packageInfo),
|
|
180
108
|
array: element.array || false,
|
|
181
109
|
min: element.min,
|
|
@@ -185,29 +113,24 @@ export const buildField = (fhirSchema, path, element, register, packageInfo) =>
|
|
|
185
113
|
binding: binding,
|
|
186
114
|
};
|
|
187
115
|
};
|
|
188
|
-
function _removeEmptyValues(obj) {
|
|
189
|
-
const result = {};
|
|
190
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
191
|
-
if (value !== undefined && value !== null) {
|
|
192
|
-
if (Array.isArray(value) && value.length === 0) {
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
result[key] = value;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
return result;
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Check if an element represents a nested type (BackboneElement)
|
|
202
|
-
*/
|
|
203
116
|
export function isNestedElement(element) {
|
|
204
|
-
|
|
117
|
+
const isBackbone = element.type === "BackboneElement";
|
|
118
|
+
const isElement = element.type === "Element" && element.elements !== undefined && Object.keys(element.elements).length > 0;
|
|
119
|
+
// ;; TODO: Observation <- vitalsigns <- bodyweight
|
|
120
|
+
// ;; In Observation we have value[x] with choices
|
|
121
|
+
// ;; In bodyweight we have valueQuantity with additional constaraints on it's elements
|
|
122
|
+
// ;; So we need to build nested type from Quantity for here, but don't do that right now.
|
|
123
|
+
const elementsWithoutType = element.type === undefined &&
|
|
124
|
+
element.choiceOf === undefined &&
|
|
125
|
+
element.elements !== undefined &&
|
|
126
|
+
Object.keys(element.elements).length > 0;
|
|
127
|
+
return isBackbone || isElement || elementsWithoutType;
|
|
205
128
|
}
|
|
206
|
-
export function mkNestedField(fhirSchema, path, element
|
|
129
|
+
export function mkNestedField(_register, fhirSchema, path, element) {
|
|
207
130
|
return {
|
|
208
131
|
type: mkNestedIdentifier(fhirSchema, path),
|
|
209
132
|
array: element.array || false,
|
|
210
|
-
required: isRequired(fhirSchema, path
|
|
211
|
-
excluded: isExcluded(fhirSchema, path
|
|
133
|
+
required: isRequired(fhirSchema, path),
|
|
134
|
+
excluded: isExcluded(fhirSchema, path),
|
|
212
135
|
};
|
|
213
136
|
}
|
|
@@ -9,4 +9,4 @@ export declare function dropVersionFromUrl(url: string | undefined): string | un
|
|
|
9
9
|
export declare function mkIdentifier(fhirSchema: RichFHIRSchema): Identifier;
|
|
10
10
|
export declare function mkNestedIdentifier(fhirSchema: RichFHIRSchema, path: string[]): NestedIdentifier;
|
|
11
11
|
export declare function mkValueSetIdentifier(valueSetUrl: string, valueSet: any, packageInfo?: PackageMeta): TypeSchemaForValueSet["identifier"];
|
|
12
|
-
export declare function mkBindingIdentifier(fhirSchema: FHIRSchema, path: string[], bindingName?: string,
|
|
12
|
+
export declare function mkBindingIdentifier(fhirSchema: FHIRSchema, path: string[], bindingName?: string, _packageInfo?: PackageMeta): BindingIdentifier;
|
|
@@ -65,7 +65,7 @@ export function mkValueSetIdentifier(valueSetUrl, valueSet, packageInfo) {
|
|
|
65
65
|
url: cleanUrl,
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
|
-
export function mkBindingIdentifier(fhirSchema, path, bindingName,
|
|
68
|
+
export function mkBindingIdentifier(fhirSchema, path, bindingName, _packageInfo) {
|
|
69
69
|
const pathStr = path.join(".");
|
|
70
70
|
const [name, url] = bindingName
|
|
71
71
|
? [bindingName, `urn:fhir:binding:${bindingName}`]
|
|
@@ -5,17 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { FHIRSchema, FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
7
7
|
import type { Register } from "@root/typeschema/register";
|
|
8
|
-
import type {
|
|
9
|
-
/**
|
|
10
|
-
* Collect all nested elements from a FHIRSchema
|
|
11
|
-
*/
|
|
8
|
+
import type { Field, Identifier, NestedType, PackageMeta, RichFHIRSchema } from "../types";
|
|
12
9
|
export declare function collectNestedElements(fhirSchema: FHIRSchema, parentPath: string[], elements: Record<string, FHIRSchemaElement>): Array<[string[], FHIRSchemaElement]>;
|
|
13
|
-
export declare function transformNestedElements(fhirSchema: RichFHIRSchema, parentPath: string[], elements: Record<string, FHIRSchemaElement>, register: Register, packageInfo?: PackageMeta): Promise<Record<string,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*/
|
|
17
|
-
export declare function buildNestedTypes(fhirSchema: RichFHIRSchema, register: Register, packageInfo?: PackageMeta): Promise<any[] | undefined>;
|
|
18
|
-
/**
|
|
19
|
-
* Extract dependencies from nested types
|
|
20
|
-
*/
|
|
21
|
-
export declare function extractNestedDependencies(nestedTypes: TypeSchemaNestedType[]): Identifier[];
|
|
10
|
+
export declare function transformNestedElements(fhirSchema: RichFHIRSchema, parentPath: string[], elements: Record<string, FHIRSchemaElement>, register: Register, packageInfo?: PackageMeta): Promise<Record<string, Field>>;
|
|
11
|
+
export declare function mkNestedTypes(register: Register, fhirSchema: RichFHIRSchema): Promise<NestedType[] | undefined>;
|
|
12
|
+
export declare function extractNestedDependencies(nestedTypes: NestedType[]): Identifier[];
|
|
@@ -5,18 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { buildField, isNestedElement, mkNestedField } from "./field-builder";
|
|
7
7
|
import { mkNestedIdentifier } from "./identifier";
|
|
8
|
-
/**
|
|
9
|
-
* Collect all nested elements from a FHIRSchema
|
|
10
|
-
*/
|
|
11
8
|
export function collectNestedElements(fhirSchema, parentPath, elements) {
|
|
12
9
|
const nested = [];
|
|
13
10
|
for (const [key, element] of Object.entries(elements)) {
|
|
14
11
|
const path = [...parentPath, key];
|
|
15
|
-
// Add this element if it's nested (BackboneElement or has elements)
|
|
16
12
|
if (isNestedElement(element)) {
|
|
17
13
|
nested.push([path, element]);
|
|
18
14
|
}
|
|
19
|
-
// Recursively collect from child elements
|
|
20
15
|
if (element.elements) {
|
|
21
16
|
nested.push(...collectNestedElements(fhirSchema, path, element.elements));
|
|
22
17
|
}
|
|
@@ -29,7 +24,7 @@ export async function transformNestedElements(fhirSchema, parentPath, elements,
|
|
|
29
24
|
const path = [...parentPath, key];
|
|
30
25
|
if (isNestedElement(element)) {
|
|
31
26
|
// Reference to another nested type
|
|
32
|
-
fields[key] = mkNestedField(fhirSchema, path, element
|
|
27
|
+
fields[key] = mkNestedField(register, fhirSchema, path, element);
|
|
33
28
|
}
|
|
34
29
|
else {
|
|
35
30
|
// Regular field
|
|
@@ -38,16 +33,12 @@ export async function transformNestedElements(fhirSchema, parentPath, elements,
|
|
|
38
33
|
}
|
|
39
34
|
return fields;
|
|
40
35
|
}
|
|
41
|
-
|
|
42
|
-
* Build TypeSchema for all nested types in a FHIRSchema
|
|
43
|
-
*/
|
|
44
|
-
export async function buildNestedTypes(fhirSchema, register, packageInfo) {
|
|
36
|
+
export async function mkNestedTypes(register, fhirSchema) {
|
|
45
37
|
if (!fhirSchema.elements)
|
|
46
38
|
return undefined;
|
|
47
|
-
const nestedTypes = [];
|
|
48
39
|
const nestedElements = collectNestedElements(fhirSchema, [], fhirSchema.elements);
|
|
49
|
-
// Filter to only include elements that have sub-elements (actual nested types)
|
|
50
40
|
const actualNested = nestedElements.filter(([_, element]) => element.elements && Object.keys(element.elements).length > 0);
|
|
41
|
+
const nestedTypes = [];
|
|
51
42
|
for (const [path, element] of actualNested) {
|
|
52
43
|
const identifier = mkNestedIdentifier(fhirSchema, path);
|
|
53
44
|
// Base is usually BackboneElement - ensure all nested types have a base
|
|
@@ -57,8 +48,8 @@ export async function buildNestedTypes(fhirSchema, register, packageInfo) {
|
|
|
57
48
|
// For BackboneElement or undefined type, always use BackboneElement as base
|
|
58
49
|
base = {
|
|
59
50
|
kind: "complex-type",
|
|
60
|
-
package:
|
|
61
|
-
version:
|
|
51
|
+
package: fhirSchema.package_meta.name,
|
|
52
|
+
version: fhirSchema.package_meta.version,
|
|
62
53
|
name: "BackboneElement",
|
|
63
54
|
url: "http://hl7.org/fhir/StructureDefinition/BackboneElement",
|
|
64
55
|
};
|
|
@@ -67,17 +58,17 @@ export async function buildNestedTypes(fhirSchema, register, packageInfo) {
|
|
|
67
58
|
// Use the specified type as base
|
|
68
59
|
base = {
|
|
69
60
|
kind: "complex-type",
|
|
70
|
-
package:
|
|
71
|
-
version:
|
|
61
|
+
package: fhirSchema.package_meta.name,
|
|
62
|
+
version: fhirSchema.package_meta.version,
|
|
72
63
|
name: element.type,
|
|
73
64
|
url: `http://hl7.org/fhir/StructureDefinition/${element.type}`,
|
|
74
65
|
};
|
|
75
66
|
}
|
|
76
67
|
// Transform sub-elements into fields
|
|
77
|
-
const fields = await transformNestedElements(fhirSchema, path, element.elements, register,
|
|
68
|
+
const fields = await transformNestedElements(fhirSchema, path, element.elements, register, fhirSchema.package_meta);
|
|
78
69
|
const nestedType = {
|
|
79
70
|
identifier,
|
|
80
|
-
base,
|
|
71
|
+
base,
|
|
81
72
|
fields,
|
|
82
73
|
};
|
|
83
74
|
nestedTypes.push(nestedType);
|
|
@@ -86,19 +77,12 @@ export async function buildNestedTypes(fhirSchema, register, packageInfo) {
|
|
|
86
77
|
nestedTypes.sort((a, b) => a.identifier.url.localeCompare(b.identifier.url));
|
|
87
78
|
return nestedTypes;
|
|
88
79
|
}
|
|
89
|
-
/**
|
|
90
|
-
* Extract dependencies from nested types
|
|
91
|
-
*/
|
|
92
80
|
export function extractNestedDependencies(nestedTypes) {
|
|
93
81
|
const deps = [];
|
|
94
82
|
for (const nested of nestedTypes) {
|
|
95
|
-
// Add the nested type itself as a dependency
|
|
96
|
-
deps.push(nested.identifier);
|
|
97
|
-
// Add base dependency
|
|
98
83
|
if (nested.base) {
|
|
99
84
|
deps.push(nested.base);
|
|
100
85
|
}
|
|
101
|
-
// Add field type dependencies
|
|
102
86
|
for (const field of Object.values(nested.fields || {})) {
|
|
103
87
|
if ("type" in field && field.type) {
|
|
104
88
|
deps.push(field.type);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Core transformation logic for converting FHIRSchema to TypeSchema format
|
|
5
5
|
*/
|
|
6
6
|
import type { FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
7
|
-
import type
|
|
8
|
-
import type { RichFHIRSchema, TypeSchema
|
|
9
|
-
export declare function
|
|
7
|
+
import { type Register } from "@typeschema/register";
|
|
8
|
+
import type { Field, RichFHIRSchema, TypeSchema } from "@typeschema/types";
|
|
9
|
+
export declare function mkFields(register: Register, fhirSchema: RichFHIRSchema, parentPath: string[], elements: Record<string, FHIRSchemaElement> | undefined): Promise<Record<string, Field> | undefined>;
|
|
10
10
|
export declare function transformFHIRSchema(register: Register, fhirSchema: RichFHIRSchema): Promise<TypeSchema[]>;
|
|
@@ -3,24 +3,26 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Core transformation logic for converting FHIRSchema to TypeSchema format
|
|
5
5
|
*/
|
|
6
|
+
import { fsElementSnapshot, resolveFsElementGenealogy } from "@typeschema/register";
|
|
6
7
|
import { transformProfile } from "../profile/processor";
|
|
7
8
|
import { collectBindingSchemas } from "./binding";
|
|
8
|
-
import { buildField,
|
|
9
|
+
import { buildField, isNestedElement, mkNestedField } from "./field-builder";
|
|
9
10
|
import { mkIdentifier } from "./identifier";
|
|
10
|
-
import {
|
|
11
|
-
export async function
|
|
11
|
+
import { extractNestedDependencies, mkNestedTypes } from "./nested-types";
|
|
12
|
+
export async function mkFields(register, fhirSchema, parentPath, elements) {
|
|
12
13
|
if (!elements)
|
|
13
14
|
return undefined;
|
|
15
|
+
const geneology = register.resolveFsGenealogy(fhirSchema.url);
|
|
14
16
|
const fields = {};
|
|
15
|
-
for (const [key,
|
|
17
|
+
for (const [key, _element] of Object.entries(elements)) {
|
|
16
18
|
const path = [...parentPath, key];
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
if (isNestedElement(
|
|
20
|
-
fields[key] = mkNestedField(fhirSchema, path,
|
|
19
|
+
const elemGeneology = resolveFsElementGenealogy(geneology, path);
|
|
20
|
+
const elemSnapshot = fsElementSnapshot(elemGeneology);
|
|
21
|
+
if (isNestedElement(elemSnapshot)) {
|
|
22
|
+
fields[key] = mkNestedField(register, fhirSchema, path, elemSnapshot);
|
|
21
23
|
}
|
|
22
24
|
else {
|
|
23
|
-
fields[key] = buildField(fhirSchema, path,
|
|
25
|
+
fields[key] = buildField(fhirSchema, path, elemSnapshot, register, fhirSchema.package_meta);
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
return fields;
|
|
@@ -113,7 +115,7 @@ async function transformValueSet(fhirSchema, _register, _packageInfo) {
|
|
|
113
115
|
/**
|
|
114
116
|
* Transform an Extension FHIRSchema to TypeSchema with extension metadata
|
|
115
117
|
*/
|
|
116
|
-
async function transformExtension(fhirSchema, register,
|
|
118
|
+
async function transformExtension(fhirSchema, register, _packageInfo) {
|
|
117
119
|
try {
|
|
118
120
|
const identifier = mkIdentifier(fhirSchema);
|
|
119
121
|
// Build base identifier if present
|
|
@@ -156,14 +158,14 @@ async function transformExtension(fhirSchema, register, packageInfo) {
|
|
|
156
158
|
}
|
|
157
159
|
// Transform elements into fields if present
|
|
158
160
|
if (fhirSchema.elements) {
|
|
159
|
-
const fields = await
|
|
161
|
+
const fields = await mkFields(register, fhirSchema, [], fhirSchema.elements);
|
|
160
162
|
if (fields && Object.keys(fields).length > 0) {
|
|
161
163
|
extensionSchema.fields = fields;
|
|
162
164
|
extensionSchema.dependencies.push(...extractFieldDependencies(fields));
|
|
163
165
|
}
|
|
164
166
|
}
|
|
165
167
|
// Build nested types
|
|
166
|
-
const nestedTypes = await
|
|
168
|
+
const nestedTypes = await mkNestedTypes(register, fhirSchema);
|
|
167
169
|
if (nestedTypes && nestedTypes.length > 0) {
|
|
168
170
|
extensionSchema.nested = nestedTypes;
|
|
169
171
|
extensionSchema.dependencies.push(...extractNestedDependencies(nestedTypes));
|
|
@@ -193,18 +195,29 @@ function extractDependencies(identifier, base, fields, nestedTypes) {
|
|
|
193
195
|
continue;
|
|
194
196
|
uniqDeps[dep.url] = dep;
|
|
195
197
|
}
|
|
196
|
-
const
|
|
198
|
+
const localNestedTypeUrls = new Set(nestedTypes?.map((nt) => nt.identifier.url));
|
|
199
|
+
console.log(1, Object.values(uniqDeps));
|
|
200
|
+
console.log(2, localNestedTypeUrls);
|
|
201
|
+
const result = Object.values(uniqDeps)
|
|
202
|
+
.filter((e) => !(e.kind === "nested" && localNestedTypeUrls.has(e.url)))
|
|
203
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
204
|
+
console.log(3, result);
|
|
197
205
|
return result.length > 0 ? result : undefined;
|
|
198
206
|
}
|
|
199
207
|
async function transformResource(register, fhirSchema) {
|
|
200
208
|
const identifier = mkIdentifier(fhirSchema);
|
|
209
|
+
console.log(6, fhirSchema.name);
|
|
201
210
|
let base;
|
|
202
211
|
if (fhirSchema.base && fhirSchema.type !== "Element") {
|
|
203
212
|
const baseFs = register.resolveFs(register.ensureCanonicalUrl(fhirSchema.base));
|
|
213
|
+
if (!baseFs) {
|
|
214
|
+
throw new Error(`Base resource not found '${fhirSchema.base}' for '${fhirSchema.url}'`);
|
|
215
|
+
}
|
|
204
216
|
base = mkIdentifier(baseFs);
|
|
205
217
|
}
|
|
206
|
-
const fields = await
|
|
207
|
-
|
|
218
|
+
const fields = await mkFields(register, fhirSchema, [], fhirSchema.elements);
|
|
219
|
+
console.log(0, fields);
|
|
220
|
+
const nested = await mkNestedTypes(register, fhirSchema);
|
|
208
221
|
const dependencies = extractDependencies(identifier, base, fields, nested);
|
|
209
222
|
const typeSchema = {
|
|
210
223
|
identifier,
|
|
@@ -220,6 +233,7 @@ async function transformResource(register, fhirSchema) {
|
|
|
220
233
|
export async function transformFHIRSchema(register, fhirSchema) {
|
|
221
234
|
const results = [];
|
|
222
235
|
const identifier = mkIdentifier(fhirSchema);
|
|
236
|
+
console.log(5, fhirSchema.name);
|
|
223
237
|
// Handle profiles with specialized processor
|
|
224
238
|
if (identifier.kind === "profile") {
|
|
225
239
|
const profileSchema = await transformProfile(register, fhirSchema);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* This file is deprecated as profiles are not part of the core TypeSchema specification
|
|
6
6
|
*/
|
|
7
7
|
import { mkIdentifier } from "../core/identifier";
|
|
8
|
-
import {
|
|
8
|
+
import { mkFields } from "../core/transformer";
|
|
9
9
|
/**
|
|
10
10
|
* Transform a FHIR profile to TypeSchema format
|
|
11
11
|
* Profiles are treated as specialized resources that extend base resources
|
|
@@ -13,7 +13,7 @@ import { transformElements } from "../core/transformer";
|
|
|
13
13
|
export async function transformProfile(register, fhirSchema) {
|
|
14
14
|
// Build profile identifier
|
|
15
15
|
const identifier = mkIdentifier(fhirSchema);
|
|
16
|
-
const
|
|
16
|
+
const _packageInfo = fhirSchema.package_meta;
|
|
17
17
|
// Ensure this is recognized as a profile
|
|
18
18
|
if (identifier.kind !== "profile") {
|
|
19
19
|
throw new Error(`Expected profile, got ${identifier.kind} for ${fhirSchema.name}`);
|
|
@@ -54,7 +54,7 @@ export async function transformProfile(register, fhirSchema) {
|
|
|
54
54
|
}
|
|
55
55
|
// Process profile fields from differential elements
|
|
56
56
|
if (fhirSchema.elements) {
|
|
57
|
-
const fields = await
|
|
57
|
+
const fields = await mkFields(register, fhirSchema, [], fhirSchema.elements);
|
|
58
58
|
if (fields && Object.keys(fields).length > 0) {
|
|
59
59
|
profileSchema.fields = fields;
|
|
60
60
|
}
|
|
@@ -79,10 +79,12 @@ export async function transformProfile(register, fhirSchema) {
|
|
|
79
79
|
/**
|
|
80
80
|
* Determine the kind of the base type for a profile
|
|
81
81
|
*/
|
|
82
|
-
async function determineBaseKind(baseUrl,
|
|
82
|
+
async function determineBaseKind(baseUrl, register) {
|
|
83
83
|
try {
|
|
84
84
|
// Try to resolve the base schema
|
|
85
|
-
const baseSchema =
|
|
85
|
+
const baseSchema = register.resolveFs(baseUrl);
|
|
86
|
+
if (!baseSchema)
|
|
87
|
+
return "resource";
|
|
86
88
|
if (baseSchema) {
|
|
87
89
|
// If it's also a constraint, it's likely another profile
|
|
88
90
|
if (baseSchema.derivation === "constraint") {
|
|
@@ -7,7 +7,7 @@ export type Register = {
|
|
|
7
7
|
ensureCanonicalUrl(name: Name | CanonicalUrl): CanonicalUrl;
|
|
8
8
|
resolveSd(canonicalUrl: CanonicalUrl): StructureDefinition | undefined;
|
|
9
9
|
resolveFs(canonicalUrl: CanonicalUrl): RichFHIRSchema | undefined;
|
|
10
|
-
resolveFsGenealogy(canonicalUrl: CanonicalUrl): RichFHIRSchema[]
|
|
10
|
+
resolveFsGenealogy(canonicalUrl: CanonicalUrl): RichFHIRSchema[];
|
|
11
11
|
allSd(): StructureDefinition[];
|
|
12
12
|
allFs(): RichFHIRSchema[];
|
|
13
13
|
allVs(): any[];
|
|
@@ -40,12 +40,14 @@ export const registerFromManager = async (manager, logger, packageInfo) => {
|
|
|
40
40
|
}
|
|
41
41
|
const resolveFsGenealogy = (canonicalUrl) => {
|
|
42
42
|
let fs = fhirSchemas[canonicalUrl];
|
|
43
|
-
if (
|
|
44
|
-
|
|
43
|
+
if (fs === undefined)
|
|
44
|
+
throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
|
|
45
45
|
const genealogy = [fs];
|
|
46
|
-
while (fs
|
|
47
|
-
fs = fhirSchemas[fs.base];
|
|
46
|
+
while (fs?.base) {
|
|
47
|
+
fs = fhirSchemas[fs.base] || fhirSchemas[nameDict[fs.base]];
|
|
48
48
|
genealogy.push(fs);
|
|
49
|
+
if (fs === undefined)
|
|
50
|
+
throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
|
|
49
51
|
}
|
|
50
52
|
return genealogy;
|
|
51
53
|
};
|
|
@@ -54,6 +56,7 @@ export const registerFromManager = async (manager, logger, packageInfo) => {
|
|
|
54
56
|
appendFs(fs) {
|
|
55
57
|
const rfs = enrichFHIRSchema(fs);
|
|
56
58
|
fhirSchemas[rfs.url] = rfs;
|
|
59
|
+
nameDict[rfs.name] = rfs.url;
|
|
57
60
|
},
|
|
58
61
|
resolveFs: (canonicalUrl) => fhirSchemas[canonicalUrl],
|
|
59
62
|
resolveFsGenealogy: resolveFsGenealogy,
|
|
@@ -94,5 +97,8 @@ export const resolveFsElementGenealogy = (genealogy, path) => {
|
|
|
94
97
|
};
|
|
95
98
|
export function fsElementSnapshot(genealogy) {
|
|
96
99
|
// FIXME: nested elements will break it
|
|
97
|
-
|
|
100
|
+
const snapshot = genealogy.reverse().reduce((snapshot, elem) => ({ ...snapshot, ...elem }), {});
|
|
101
|
+
// NOTE: to avoid regeneration nested types
|
|
102
|
+
snapshot.elements = undefined;
|
|
103
|
+
return snapshot;
|
|
98
104
|
}
|
|
@@ -62,13 +62,13 @@ interface TypeSchemaForPrimitiveType {
|
|
|
62
62
|
export interface NestedType {
|
|
63
63
|
identifier: NestedIdentifier;
|
|
64
64
|
base: Identifier;
|
|
65
|
-
fields: Record<string,
|
|
65
|
+
fields: Record<string, Field>;
|
|
66
66
|
}
|
|
67
67
|
export interface TypeSchemaForProfile {
|
|
68
68
|
identifier: ProfileIdentifier;
|
|
69
69
|
base: Identifier;
|
|
70
70
|
description?: string;
|
|
71
|
-
fields?: Record<string,
|
|
71
|
+
fields?: Record<string, Field>;
|
|
72
72
|
constraints?: Record<string, ProfileConstraint>;
|
|
73
73
|
extensions?: ProfileExtension[];
|
|
74
74
|
validation?: ValidationRule[];
|
|
@@ -121,21 +121,14 @@ export interface ProfileMetadata {
|
|
|
121
121
|
jurisdiction?: any[];
|
|
122
122
|
package?: string;
|
|
123
123
|
}
|
|
124
|
-
export interface TypeSchemaNestedType {
|
|
125
|
-
identifier: NestedIdentifier;
|
|
126
|
-
base: Identifier;
|
|
127
|
-
fields?: {
|
|
128
|
-
[k: string]: RegularField | PolymorphicValueXFieldDeclaration | PolymorphicValueXFieldInstance;
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
124
|
export interface TypeSchemaForResourceComplexTypeLogical {
|
|
132
125
|
identifier: Identifier;
|
|
133
126
|
base?: Identifier;
|
|
134
127
|
description?: string;
|
|
135
128
|
fields?: {
|
|
136
|
-
[k: string]:
|
|
129
|
+
[k: string]: Field;
|
|
137
130
|
};
|
|
138
|
-
nested?:
|
|
131
|
+
nested?: NestedType[];
|
|
139
132
|
dependencies?: Identifier[];
|
|
140
133
|
}
|
|
141
134
|
export interface RegularField {
|
|
@@ -149,7 +142,7 @@ export interface RegularField {
|
|
|
149
142
|
min?: number;
|
|
150
143
|
max?: number;
|
|
151
144
|
}
|
|
152
|
-
export interface
|
|
145
|
+
export interface PolymorphicDeclarationField {
|
|
153
146
|
choices: string[];
|
|
154
147
|
required?: boolean;
|
|
155
148
|
excluded?: boolean;
|
|
@@ -157,7 +150,7 @@ export interface PolymorphicValueXFieldDeclaration {
|
|
|
157
150
|
min?: number;
|
|
158
151
|
max?: number;
|
|
159
152
|
}
|
|
160
|
-
export interface
|
|
153
|
+
export interface PolymorphicInstanceField {
|
|
161
154
|
choiceOf: string;
|
|
162
155
|
type: Identifier;
|
|
163
156
|
required?: boolean;
|
|
@@ -190,7 +183,7 @@ export interface TypeSchemaForBinding {
|
|
|
190
183
|
valueset?: ValueSetIdentifier;
|
|
191
184
|
dependencies?: Identifier[];
|
|
192
185
|
}
|
|
193
|
-
export type
|
|
186
|
+
export type Field = RegularField | PolymorphicDeclarationField | PolymorphicInstanceField;
|
|
194
187
|
export interface TypeschemaGeneratorOptions {
|
|
195
188
|
verbose?: boolean;
|
|
196
189
|
logger?: import("../utils/codegen-logger").CodegenLogger;
|
package/package.json
CHANGED