@atomic-ehr/codegen 0.0.1-canary.20250929141928.699688c → 0.0.1-canary.20250930124137.175bd5f
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 +2 -2
- package/dist/api/builder.js +1 -1
- package/dist/api/generators/base/BaseGenerator.js +5 -12
- package/dist/api/generators/base/FileManager.js +1 -3
- package/dist/api/generators/base/TemplateEngine.js +2 -2
- package/dist/api/generators/base/TypeScriptTypeMapper.js +1 -1
- package/dist/api/generators/base/builders/FileBuilder.js +6 -8
- package/dist/api/generators/base/errors.js +1 -3
- package/dist/api/generators/base/index.d.ts +1 -1
- package/dist/api/generators/base/index.js +1 -2
- package/dist/api/generators/base/types.d.ts +1 -1
- package/dist/api/generators/typescript.d.ts +1 -3
- package/dist/api/generators/typescript.js +13 -38
- package/dist/api/index.d.ts +1 -2
- package/dist/cli/commands/typeschema/generate.js +4 -10
- package/dist/cli/commands/typeschema.js +1 -2
- package/dist/cli/index.js +54 -54
- package/dist/cli/utils/spinner.js +2 -6
- package/dist/config.js +4 -16
- package/dist/logger.js +4 -13
- package/dist/typeschema/cache.d.ts +1 -1
- package/dist/typeschema/core/binding.d.ts +4 -7
- package/dist/typeschema/core/binding.js +16 -30
- package/dist/typeschema/core/field-builder.d.ts +6 -14
- package/dist/typeschema/core/field-builder.js +42 -88
- package/dist/typeschema/core/identifier.d.ts +5 -8
- package/dist/typeschema/core/identifier.js +8 -15
- package/dist/typeschema/core/nested-types.d.ts +4 -7
- package/dist/typeschema/core/nested-types.js +15 -14
- package/dist/typeschema/core/transformer.d.ts +5 -13
- package/dist/typeschema/core/transformer.js +70 -147
- package/dist/typeschema/generator.d.ts +5 -8
- package/dist/typeschema/generator.js +26 -24
- package/dist/typeschema/parser.d.ts +7 -8
- package/dist/typeschema/parser.js +67 -82
- package/dist/typeschema/profile/processor.d.ts +3 -2
- package/dist/typeschema/profile/processor.js +13 -23
- package/dist/typeschema/register.d.ts +17 -0
- package/dist/typeschema/register.js +77 -0
- package/dist/typeschema/types.d.ts +32 -21
- package/dist/typeschema/types.js +5 -5
- package/dist/typeschema/value-set/processor.d.ts +2 -2
- package/dist/typeschema/value-set/processor.js +3 -3
- package/dist/utils/codegen-logger.js +4 -12
- package/package.json +2 -2
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Nested Types (BackboneElement) Handling
|
|
3
|
+
*
|
|
4
|
+
* Functions for extracting and transforming nested types from FHIRSchema
|
|
5
|
+
*/
|
|
6
|
+
import { buildField, isNestedElement, mkNestedField } from "./field-builder";
|
|
7
|
+
import { mkNestedIdentifier } from "./identifier";
|
|
4
8
|
/**
|
|
5
9
|
* Collect all nested elements from a FHIRSchema
|
|
6
10
|
*/
|
|
@@ -19,20 +23,17 @@ export function collectNestedElements(fhirSchema, parentPath, elements) {
|
|
|
19
23
|
}
|
|
20
24
|
return nested;
|
|
21
25
|
}
|
|
22
|
-
|
|
23
|
-
* Transform elements into fields for a nested type
|
|
24
|
-
*/
|
|
25
|
-
export async function transformNestedElements(fhirSchema, parentPath, elements, manager, packageInfo) {
|
|
26
|
+
export async function transformNestedElements(fhirSchema, parentPath, elements, register, packageInfo) {
|
|
26
27
|
const fields = {};
|
|
27
28
|
for (const [key, element] of Object.entries(elements)) {
|
|
28
29
|
const path = [...parentPath, key];
|
|
29
30
|
if (isNestedElement(element)) {
|
|
30
31
|
// Reference to another nested type
|
|
31
|
-
fields[key] =
|
|
32
|
+
fields[key] = mkNestedField(fhirSchema, path, element, register, packageInfo);
|
|
32
33
|
}
|
|
33
34
|
else {
|
|
34
35
|
// Regular field
|
|
35
|
-
fields[key] = await buildField(fhirSchema, path, element,
|
|
36
|
+
fields[key] = await buildField(fhirSchema, path, element, register, packageInfo);
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
return fields;
|
|
@@ -40,15 +41,15 @@ export async function transformNestedElements(fhirSchema, parentPath, elements,
|
|
|
40
41
|
/**
|
|
41
42
|
* Build TypeSchema for all nested types in a FHIRSchema
|
|
42
43
|
*/
|
|
43
|
-
export async function buildNestedTypes(fhirSchema,
|
|
44
|
+
export async function buildNestedTypes(fhirSchema, register, packageInfo) {
|
|
44
45
|
if (!fhirSchema.elements)
|
|
45
|
-
return
|
|
46
|
+
return undefined;
|
|
46
47
|
const nestedTypes = [];
|
|
47
48
|
const nestedElements = collectNestedElements(fhirSchema, [], fhirSchema.elements);
|
|
48
49
|
// Filter to only include elements that have sub-elements (actual nested types)
|
|
49
50
|
const actualNested = nestedElements.filter(([_, element]) => element.elements && Object.keys(element.elements).length > 0);
|
|
50
51
|
for (const [path, element] of actualNested) {
|
|
51
|
-
const identifier =
|
|
52
|
+
const identifier = mkNestedIdentifier(fhirSchema, path);
|
|
52
53
|
// Base is usually BackboneElement - ensure all nested types have a base
|
|
53
54
|
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
|
54
55
|
let base;
|
|
@@ -73,7 +74,7 @@ export async function buildNestedTypes(fhirSchema, manager, packageInfo) {
|
|
|
73
74
|
};
|
|
74
75
|
}
|
|
75
76
|
// Transform sub-elements into fields
|
|
76
|
-
const fields = await transformNestedElements(fhirSchema, path, element.elements,
|
|
77
|
+
const fields = await transformNestedElements(fhirSchema, path, element.elements, register, packageInfo);
|
|
77
78
|
const nestedType = {
|
|
78
79
|
identifier,
|
|
79
80
|
base, // Always include base
|
|
@@ -98,7 +99,7 @@ export function extractNestedDependencies(nestedTypes) {
|
|
|
98
99
|
deps.push(nested.base);
|
|
99
100
|
}
|
|
100
101
|
// Add field type dependencies
|
|
101
|
-
for (const field of Object.values(nested.fields)) {
|
|
102
|
+
for (const field of Object.values(nested.fields || {})) {
|
|
102
103
|
if ("type" in field && field.type) {
|
|
103
104
|
deps.push(field.type);
|
|
104
105
|
}
|
|
@@ -3,16 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Core transformation logic for converting FHIRSchema to TypeSchema format
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
7
|
-
import type {
|
|
8
|
-
import type { TypeSchema, TypeSchemaField
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* Transform elements into fields
|
|
12
|
-
*/
|
|
13
|
-
export declare function transformElements(fhirSchema: FHIRSchema, parentPath: string[], elements: Record<string, FHIRSchemaElement>, manager: ReturnType<typeof CanonicalManager>, packageInfo?: PackageInfo): Promise<Record<string, TypeSchemaField>>;
|
|
14
|
-
/**
|
|
15
|
-
* Transform a single FHIRSchema to TypeSchema(s) with enhanced categorization
|
|
16
|
-
* Returns the main schema plus any binding schemas
|
|
17
|
-
*/
|
|
18
|
-
export declare function transformFHIRSchema(manager: ReturnType<typeof CanonicalManager>, fhirSchema: RichFHIRSchema): Promise<TypeSchema[]>;
|
|
6
|
+
import type { FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
7
|
+
import type { Register } from "@typeschema/register";
|
|
8
|
+
import type { RichFHIRSchema, TypeSchema, TypeSchemaField } from "@typeschema/types";
|
|
9
|
+
export declare function transformElements(register: Register, fhirSchema: RichFHIRSchema, parentPath: string[], elements: Record<string, FHIRSchemaElement> | undefined): Promise<Record<string, TypeSchemaField> | undefined>;
|
|
10
|
+
export declare function transformFHIRSchema(register: Register, fhirSchema: RichFHIRSchema): Promise<TypeSchema[]>;
|
|
@@ -1,33 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Main FHIRSchema to TypeSchema Transformer
|
|
3
|
+
*
|
|
4
|
+
* Core transformation logic for converting FHIRSchema to TypeSchema format
|
|
5
|
+
*/
|
|
2
6
|
import { transformProfile } from "../profile/processor";
|
|
3
7
|
import { collectBindingSchemas } from "./binding";
|
|
4
|
-
import { buildField,
|
|
5
|
-
import {
|
|
8
|
+
import { buildField, getElementHierarchy, isNestedElement, mergeElementHierarchy, mkNestedField, } from "./field-builder";
|
|
9
|
+
import { mkIdentifier } from "./identifier";
|
|
6
10
|
import { buildNestedTypes, extractNestedDependencies } from "./nested-types";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export async function transformElements(fhirSchema, parentPath, elements, manager, packageInfo) {
|
|
11
|
+
export async function transformElements(register, fhirSchema, parentPath, elements) {
|
|
12
|
+
if (!elements)
|
|
13
|
+
return undefined;
|
|
11
14
|
const fields = {};
|
|
12
15
|
for (const [key, element] of Object.entries(elements)) {
|
|
13
16
|
const path = [...parentPath, key];
|
|
14
|
-
|
|
15
|
-
const hierarchy = getElementHierarchy(fhirSchema, path, manager);
|
|
17
|
+
const hierarchy = getElementHierarchy(fhirSchema, path, register);
|
|
16
18
|
const snapshot = hierarchy.length > 0 ? mergeElementHierarchy(hierarchy) : element;
|
|
17
19
|
if (isNestedElement(snapshot)) {
|
|
18
|
-
|
|
19
|
-
fields[key] = buildNestedField(fhirSchema, path, snapshot, manager, packageInfo);
|
|
20
|
+
fields[key] = mkNestedField(fhirSchema, path, snapshot, register, fhirSchema.package_meta);
|
|
20
21
|
}
|
|
21
22
|
else {
|
|
22
|
-
|
|
23
|
-
fields[key] = await buildField(fhirSchema, path, snapshot, manager, packageInfo);
|
|
23
|
+
fields[key] = buildField(fhirSchema, path, snapshot, register, fhirSchema.package_meta);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
return fields;
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Extract dependencies from fields
|
|
30
|
-
*/
|
|
31
28
|
function extractFieldDependencies(fields) {
|
|
32
29
|
const deps = [];
|
|
33
30
|
for (const field of Object.values(fields)) {
|
|
@@ -40,9 +37,6 @@ function extractFieldDependencies(fields) {
|
|
|
40
37
|
}
|
|
41
38
|
return deps;
|
|
42
39
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Remove duplicate dependencies
|
|
45
|
-
*/
|
|
46
40
|
function deduplicateDependencies(deps) {
|
|
47
41
|
const seen = new Set();
|
|
48
42
|
const unique = [];
|
|
@@ -62,13 +56,11 @@ function deduplicateDependencies(deps) {
|
|
|
62
56
|
*/
|
|
63
57
|
function isExtensionSchema(fhirSchema, _identifier) {
|
|
64
58
|
// Check if this is based on Extension
|
|
65
|
-
if (fhirSchema.base === "Extension" ||
|
|
66
|
-
fhirSchema.base === "http://hl7.org/fhir/StructureDefinition/Extension") {
|
|
59
|
+
if (fhirSchema.base === "Extension" || fhirSchema.base === "http://hl7.org/fhir/StructureDefinition/Extension") {
|
|
67
60
|
return true;
|
|
68
61
|
}
|
|
69
62
|
// Check if the URL indicates this is an extension
|
|
70
|
-
if (fhirSchema.url?.includes("/extension/") ||
|
|
71
|
-
fhirSchema.url?.includes("-extension")) {
|
|
63
|
+
if (fhirSchema.url?.includes("/extension/") || fhirSchema.url?.includes("-extension")) {
|
|
72
64
|
return true;
|
|
73
65
|
}
|
|
74
66
|
// Check if the name indicates this is an extension
|
|
@@ -84,12 +76,12 @@ function isExtensionSchema(fhirSchema, _identifier) {
|
|
|
84
76
|
/**
|
|
85
77
|
* Transform a ValueSet FHIRSchema to TypeSchemaValueSet
|
|
86
78
|
*/
|
|
87
|
-
async function transformValueSet(fhirSchema,
|
|
79
|
+
async function transformValueSet(fhirSchema, _register, _packageInfo) {
|
|
88
80
|
try {
|
|
89
|
-
const identifier =
|
|
90
|
-
identifier.kind = "value-set";
|
|
81
|
+
const identifier = mkIdentifier(fhirSchema);
|
|
82
|
+
identifier.kind = "value-set";
|
|
91
83
|
const valueSetSchema = {
|
|
92
|
-
identifier,
|
|
84
|
+
identifier: identifier,
|
|
93
85
|
description: fhirSchema.description,
|
|
94
86
|
};
|
|
95
87
|
// If there are elements that represent concepts
|
|
@@ -121,9 +113,9 @@ async function transformValueSet(fhirSchema, _manager, packageInfo) {
|
|
|
121
113
|
/**
|
|
122
114
|
* Transform an Extension FHIRSchema to TypeSchema with extension metadata
|
|
123
115
|
*/
|
|
124
|
-
async function transformExtension(fhirSchema,
|
|
116
|
+
async function transformExtension(fhirSchema, register, packageInfo) {
|
|
125
117
|
try {
|
|
126
|
-
const identifier =
|
|
118
|
+
const identifier = mkIdentifier(fhirSchema);
|
|
127
119
|
// Build base identifier if present
|
|
128
120
|
let base;
|
|
129
121
|
if (fhirSchema.base && fhirSchema.base !== "Extension") {
|
|
@@ -164,15 +156,15 @@ async function transformExtension(fhirSchema, manager, packageInfo) {
|
|
|
164
156
|
}
|
|
165
157
|
// Transform elements into fields if present
|
|
166
158
|
if (fhirSchema.elements) {
|
|
167
|
-
const fields = await transformElements(fhirSchema, [], fhirSchema.elements
|
|
168
|
-
if (Object.keys(fields).length > 0) {
|
|
159
|
+
const fields = await transformElements(register, fhirSchema, [], fhirSchema.elements);
|
|
160
|
+
if (fields && Object.keys(fields).length > 0) {
|
|
169
161
|
extensionSchema.fields = fields;
|
|
170
162
|
extensionSchema.dependencies.push(...extractFieldDependencies(fields));
|
|
171
163
|
}
|
|
172
164
|
}
|
|
173
165
|
// Build nested types
|
|
174
|
-
const nestedTypes = await buildNestedTypes(fhirSchema,
|
|
175
|
-
if (nestedTypes.length > 0) {
|
|
166
|
+
const nestedTypes = await buildNestedTypes(fhirSchema, register, packageInfo);
|
|
167
|
+
if (nestedTypes && nestedTypes.length > 0) {
|
|
176
168
|
extensionSchema.nested = nestedTypes;
|
|
177
169
|
extensionSchema.dependencies.push(...extractNestedDependencies(nestedTypes));
|
|
178
170
|
}
|
|
@@ -187,25 +179,59 @@ async function transformExtension(fhirSchema, manager, packageInfo) {
|
|
|
187
179
|
return null;
|
|
188
180
|
}
|
|
189
181
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
182
|
+
function extractDependencies(identifier, base, fields, nestedTypes) {
|
|
183
|
+
const deps = [];
|
|
184
|
+
if (base)
|
|
185
|
+
deps.push(base);
|
|
186
|
+
if (fields)
|
|
187
|
+
deps.push(...extractFieldDependencies(fields));
|
|
188
|
+
if (nestedTypes)
|
|
189
|
+
deps.push(...extractNestedDependencies(nestedTypes));
|
|
190
|
+
const uniqDeps = {};
|
|
191
|
+
for (const dep of deps) {
|
|
192
|
+
if (dep.url === identifier.url)
|
|
193
|
+
continue;
|
|
194
|
+
uniqDeps[dep.url] = dep;
|
|
195
|
+
}
|
|
196
|
+
const result = Object.values(uniqDeps).sort((a, b) => a.name.localeCompare(b.name));
|
|
197
|
+
return result.length > 0 ? result : undefined;
|
|
198
|
+
}
|
|
199
|
+
async function transformResource(register, fhirSchema) {
|
|
200
|
+
const identifier = mkIdentifier(fhirSchema);
|
|
201
|
+
let base;
|
|
202
|
+
if (fhirSchema.base && fhirSchema.type !== "Element") {
|
|
203
|
+
const baseFs = register.resolveFs(register.ensureCanonicalUrl(fhirSchema.base));
|
|
204
|
+
base = mkIdentifier(baseFs);
|
|
205
|
+
}
|
|
206
|
+
const fields = await transformElements(register, fhirSchema, [], fhirSchema.elements);
|
|
207
|
+
const nested = await buildNestedTypes(fhirSchema, register, fhirSchema.package_meta);
|
|
208
|
+
const dependencies = extractDependencies(identifier, base, fields, nested);
|
|
209
|
+
const typeSchema = {
|
|
210
|
+
identifier,
|
|
211
|
+
base,
|
|
212
|
+
fields,
|
|
213
|
+
nested,
|
|
214
|
+
description: fhirSchema.description,
|
|
215
|
+
dependencies,
|
|
216
|
+
};
|
|
217
|
+
const bindingSchemas = await collectBindingSchemas(fhirSchema, register);
|
|
218
|
+
return [typeSchema, ...bindingSchemas];
|
|
219
|
+
}
|
|
220
|
+
export async function transformFHIRSchema(register, fhirSchema) {
|
|
195
221
|
const results = [];
|
|
196
|
-
const identifier =
|
|
222
|
+
const identifier = mkIdentifier(fhirSchema);
|
|
197
223
|
// Handle profiles with specialized processor
|
|
198
224
|
if (identifier.kind === "profile") {
|
|
199
|
-
const profileSchema = await transformProfile(
|
|
225
|
+
const profileSchema = await transformProfile(register, fhirSchema);
|
|
200
226
|
results.push(profileSchema);
|
|
201
227
|
// Collect binding schemas for profiles too
|
|
202
|
-
const bindingSchemas = await collectBindingSchemas(fhirSchema,
|
|
228
|
+
const bindingSchemas = await collectBindingSchemas(fhirSchema, register);
|
|
203
229
|
results.push(...bindingSchemas);
|
|
204
230
|
return results;
|
|
205
231
|
}
|
|
206
232
|
// Handle value sets specially
|
|
207
233
|
if (identifier.kind === "value-set" || fhirSchema.kind === "value-set") {
|
|
208
|
-
const valueSetSchema = await transformValueSet(fhirSchema,
|
|
234
|
+
const valueSetSchema = await transformValueSet(fhirSchema, register, fhirSchema.package_meta);
|
|
209
235
|
if (valueSetSchema) {
|
|
210
236
|
results.push(valueSetSchema);
|
|
211
237
|
}
|
|
@@ -213,114 +239,11 @@ export async function transformFHIRSchema(manager, fhirSchema) {
|
|
|
213
239
|
}
|
|
214
240
|
// Handle extensions specially
|
|
215
241
|
if (isExtensionSchema(fhirSchema, identifier)) {
|
|
216
|
-
const extensionSchema = await transformExtension(fhirSchema,
|
|
242
|
+
const extensionSchema = await transformExtension(fhirSchema, register, fhirSchema.package_meta);
|
|
217
243
|
if (extensionSchema) {
|
|
218
244
|
results.push(extensionSchema);
|
|
219
245
|
}
|
|
220
246
|
return results;
|
|
221
247
|
}
|
|
222
|
-
|
|
223
|
-
let base;
|
|
224
|
-
if (fhirSchema.base && fhirSchema.type !== "Element") {
|
|
225
|
-
// Create base identifier directly
|
|
226
|
-
const baseUrl = fhirSchema.base.includes("/")
|
|
227
|
-
? fhirSchema.base
|
|
228
|
-
: `http://hl7.org/fhir/StructureDefinition/${fhirSchema.base}`;
|
|
229
|
-
const baseName = fhirSchema.base.split("/").pop() || fhirSchema.base;
|
|
230
|
-
// Check if this is a known complex type by looking at common FHIR complex types
|
|
231
|
-
const complexTypes = new Set([
|
|
232
|
-
"Element",
|
|
233
|
-
"BackboneElement",
|
|
234
|
-
"Quantity",
|
|
235
|
-
"Duration",
|
|
236
|
-
"Distance",
|
|
237
|
-
"Count",
|
|
238
|
-
"Age",
|
|
239
|
-
"Address",
|
|
240
|
-
"Annotation",
|
|
241
|
-
"Attachment",
|
|
242
|
-
"CodeableConcept",
|
|
243
|
-
"Coding",
|
|
244
|
-
"ContactPoint",
|
|
245
|
-
"HumanName",
|
|
246
|
-
"Identifier",
|
|
247
|
-
"Period",
|
|
248
|
-
"Range",
|
|
249
|
-
"Ratio",
|
|
250
|
-
"Reference",
|
|
251
|
-
"Timing",
|
|
252
|
-
"Money",
|
|
253
|
-
"SampledData",
|
|
254
|
-
"Signature",
|
|
255
|
-
"ContactDetail",
|
|
256
|
-
"Contributor",
|
|
257
|
-
"DataRequirement",
|
|
258
|
-
"Expression",
|
|
259
|
-
"ParameterDefinition",
|
|
260
|
-
"RelatedArtifact",
|
|
261
|
-
"TriggerDefinition",
|
|
262
|
-
"UsageContext",
|
|
263
|
-
"Dosage",
|
|
264
|
-
"Meta",
|
|
265
|
-
"Extension",
|
|
266
|
-
]);
|
|
267
|
-
const kind = complexTypes.has(baseName) ? "complex-type" : "resource";
|
|
268
|
-
// For standard FHIR types, use the standard package even if no package info
|
|
269
|
-
const isStandardFhir = baseUrl.startsWith("http://hl7.org/fhir/");
|
|
270
|
-
base = {
|
|
271
|
-
kind: kind,
|
|
272
|
-
package: isStandardFhir
|
|
273
|
-
? "hl7.fhir.r4.core"
|
|
274
|
-
: fhirSchema.package_meta.name || "undefined",
|
|
275
|
-
version: isStandardFhir
|
|
276
|
-
? "4.0.1"
|
|
277
|
-
: fhirSchema.package_meta.version || "undefined",
|
|
278
|
-
name: baseName,
|
|
279
|
-
url: baseUrl,
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
// Initialize the main schema
|
|
283
|
-
const mainSchema = {
|
|
284
|
-
identifier,
|
|
285
|
-
dependencies: [],
|
|
286
|
-
};
|
|
287
|
-
// Collect dependencies in the same order as Clojure implementation
|
|
288
|
-
const allDependencies = [];
|
|
289
|
-
// Add base if present (first in dependencies)
|
|
290
|
-
if (base) {
|
|
291
|
-
mainSchema.base = base;
|
|
292
|
-
allDependencies.push(base);
|
|
293
|
-
}
|
|
294
|
-
// Add description if present
|
|
295
|
-
if (fhirSchema.description) {
|
|
296
|
-
mainSchema.description = fhirSchema.description;
|
|
297
|
-
}
|
|
298
|
-
// Transform elements into fields (for non-primitive types)
|
|
299
|
-
if (fhirSchema.kind !== "primitive-type" && fhirSchema.elements) {
|
|
300
|
-
const fields = await transformElements(fhirSchema, [], fhirSchema.elements, manager, fhirSchema.package_meta);
|
|
301
|
-
if (Object.keys(fields).length > 0) {
|
|
302
|
-
mainSchema.fields = fields;
|
|
303
|
-
}
|
|
304
|
-
// Extract field dependencies (types and bindings)
|
|
305
|
-
allDependencies.push(...extractFieldDependencies(fields));
|
|
306
|
-
// Build nested types
|
|
307
|
-
const nestedTypes = await buildNestedTypes(fhirSchema, manager, fhirSchema.package_meta);
|
|
308
|
-
if (nestedTypes.length > 0) {
|
|
309
|
-
mainSchema.nested = nestedTypes;
|
|
310
|
-
// Add nested type dependencies
|
|
311
|
-
allDependencies.push(...extractNestedDependencies(nestedTypes));
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
// Set all dependencies at once
|
|
315
|
-
mainSchema.dependencies = allDependencies;
|
|
316
|
-
// Deduplicate and sort dependencies
|
|
317
|
-
mainSchema.dependencies = deduplicateDependencies(mainSchema.dependencies);
|
|
318
|
-
// Remove self-reference from dependencies
|
|
319
|
-
mainSchema.dependencies = mainSchema.dependencies.filter((dep) => dep.url !== identifier.url);
|
|
320
|
-
// Add main schema to results
|
|
321
|
-
results.push(mainSchema);
|
|
322
|
-
// Collect and add binding schemas
|
|
323
|
-
const bindingSchemas = await collectBindingSchemas(fhirSchema, manager, fhirSchema.package_meta);
|
|
324
|
-
results.push(...bindingSchemas);
|
|
325
|
-
return results;
|
|
248
|
+
return await transformResource(register, fhirSchema);
|
|
326
249
|
}
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* Generates TypeSchema documents from FHIR packages using fhrischema.
|
|
5
5
|
* Provides high-level API for converting FHIR Structure Definitions to TypeSchema format.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import type { FHIRSchema, StructureDefinition } from "@atomic-ehr/fhirschema";
|
|
8
8
|
import type { TypeSchemaConfig } from "@root/config";
|
|
9
|
-
import type {
|
|
9
|
+
import type { Register } from "@typeschema/register";
|
|
10
|
+
import type { PackageMeta, TypeSchema, TypeschemaGeneratorOptions } from "./types";
|
|
10
11
|
/**
|
|
11
12
|
* TypeSchema Generator class
|
|
12
13
|
*
|
|
@@ -21,14 +22,10 @@ export declare class TypeSchemaGenerator {
|
|
|
21
22
|
private logger;
|
|
22
23
|
constructor(options?: TypeschemaGeneratorOptions, cacheConfig?: TypeSchemaConfig);
|
|
23
24
|
private initializeCache;
|
|
24
|
-
|
|
25
|
-
structureDefinitions: StructureDefinition[];
|
|
26
|
-
valueSets: any[];
|
|
27
|
-
}>;
|
|
25
|
+
registerFromPackageMetas(packageMetas: PackageMeta[]): Promise<Register>;
|
|
28
26
|
generateFhirSchemas(structureDefinitions: StructureDefinition[]): FHIRSchema[];
|
|
29
|
-
generateValueSetSchemas(valueSets: any[], packageInfo:
|
|
27
|
+
generateValueSetSchemas(valueSets: any[], packageInfo: PackageMeta): Promise<TypeSchema[]>;
|
|
30
28
|
generateFromPackage(packageName: string, packageVersion?: string): Promise<TypeSchema[]>;
|
|
31
|
-
generateResourceTypeSchemas(fhirSchemas: RichFHIRSchema[]): Promise<TypeSchema[]>;
|
|
32
29
|
/**
|
|
33
30
|
* Apply treeshaking to StructureDefinitions before FHIR schema transformation
|
|
34
31
|
* This is more efficient and includes smart reference handling
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
import { CanonicalManager } from "@atomic-ehr/fhir-canonical-manager";
|
|
8
8
|
import * as fhirschema from "@atomic-ehr/fhirschema";
|
|
9
9
|
import { createLogger } from "@root/utils/codegen-logger";
|
|
10
|
+
import { registerFromManager } from "@typeschema/register";
|
|
10
11
|
import { TypeSchemaCache } from "./cache";
|
|
11
12
|
import { transformFHIRSchema } from "./core/transformer";
|
|
12
|
-
import { enrichFHIRSchema } from "./types";
|
|
13
13
|
import { transformValueSet } from "./value-set/processor";
|
|
14
14
|
/**
|
|
15
15
|
* TypeSchema Generator class
|
|
@@ -25,8 +25,7 @@ export class TypeSchemaGenerator {
|
|
|
25
25
|
logger;
|
|
26
26
|
constructor(options = {}, cacheConfig) {
|
|
27
27
|
this.options = { verbose: false, ...options };
|
|
28
|
-
this.manager = options.manager ||
|
|
29
|
-
CanonicalManager({ packages: [], workingDir: "tmp/fhir" });
|
|
28
|
+
this.manager = options.manager || CanonicalManager({ packages: [], workingDir: "tmp/fhir" });
|
|
30
29
|
this.cacheConfig = cacheConfig;
|
|
31
30
|
this.logger =
|
|
32
31
|
options.logger ||
|
|
@@ -41,14 +40,11 @@ export class TypeSchemaGenerator {
|
|
|
41
40
|
await this.cache.initialize();
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
|
-
async
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const valueSets = allResources.filter((resource) => resource.resourceType === "ValueSet");
|
|
50
|
-
this.logger.info(`Found ${structureDefinitions.length} StructureDefinitions and ${valueSets.length} ValueSets in package`);
|
|
51
|
-
return { structureDefinitions, valueSets };
|
|
43
|
+
async registerFromPackageMetas(packageMetas) {
|
|
44
|
+
const packageNames = packageMetas.map((meta) => `${meta.name}${meta.version}`);
|
|
45
|
+
this.logger.step(`Loading FHIR packages: ${packageNames.join(", ")}`);
|
|
46
|
+
await this.manager.init();
|
|
47
|
+
return registerFromManager(this.manager);
|
|
52
48
|
}
|
|
53
49
|
generateFhirSchemas(structureDefinitions) {
|
|
54
50
|
this.logger.progress(`Converting ${structureDefinitions.length} StructureDefinitions to FHIRSchemas`);
|
|
@@ -113,11 +109,11 @@ export class TypeSchemaGenerator {
|
|
|
113
109
|
name: packageName,
|
|
114
110
|
version: packageVersion || "latest",
|
|
115
111
|
};
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
112
|
+
const register = await this.registerFromPackageMetas([packageInfo]);
|
|
113
|
+
const allSchemas = [
|
|
114
|
+
...(await Promise.all(register.allFs().map(async (fs) => await transformFHIRSchema(register, fs)))).flat(),
|
|
115
|
+
...(await this.generateValueSetSchemas(register.allVs(), packageInfo)),
|
|
116
|
+
];
|
|
121
117
|
if (this.cache) {
|
|
122
118
|
for (const schema of allSchemas) {
|
|
123
119
|
await this.cache.set(schema);
|
|
@@ -125,14 +121,20 @@ export class TypeSchemaGenerator {
|
|
|
125
121
|
}
|
|
126
122
|
return allSchemas;
|
|
127
123
|
}
|
|
128
|
-
async generateResourceTypeSchemas(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
124
|
+
// async generateResourceTypeSchemas(
|
|
125
|
+
// fhirSchemas: RichFHIRSchema[],
|
|
126
|
+
// ): Promise<TypeSchema[]> {
|
|
127
|
+
// this.logger.info(
|
|
128
|
+
// `Transforming ${fhirSchemas.length} FHIR schemas to Type Schema`,
|
|
129
|
+
// );
|
|
130
|
+
// const typeSchemas: TypeSchema[] = [];
|
|
131
|
+
// for (const fhirSchema of fhirSchemas) {
|
|
132
|
+
// typeSchemas.push(
|
|
133
|
+
// ...(await transformFHIRSchema(this.manager, fhirSchema)),
|
|
134
|
+
// );
|
|
135
|
+
// }
|
|
136
|
+
// return typeSchemas;
|
|
137
|
+
// }
|
|
136
138
|
/**
|
|
137
139
|
* Apply treeshaking to StructureDefinitions before FHIR schema transformation
|
|
138
140
|
* This is more efficient and includes smart reference handling
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* TypeSchema Parser
|
|
3
|
+
*
|
|
4
|
+
* Parser for reading and manipulating TypeSchema documents from various formats.
|
|
5
|
+
* Supports both NDJSON and JSON formats with automatic format detection.
|
|
6
|
+
*/
|
|
7
|
+
import type { Identifier, TypeSchema, TypeschemaParserOptions } from "@typeschema/types";
|
|
3
8
|
/**
|
|
4
9
|
* TypeSchema Parser class
|
|
5
10
|
*
|
|
@@ -44,11 +49,9 @@ export declare class TypeSchemaParser {
|
|
|
44
49
|
/**
|
|
45
50
|
* Get all dependencies from a schema
|
|
46
51
|
*/
|
|
47
|
-
getDependencies(schema: TypeSchema): Identifier[];
|
|
48
52
|
/**
|
|
49
53
|
* Resolve schema dependencies
|
|
50
54
|
*/
|
|
51
|
-
resolveDependencies(schemas: TypeSchema[], targetSchema: TypeSchema): TypeSchema[];
|
|
52
55
|
/**
|
|
53
56
|
* Detect format from content or filename
|
|
54
57
|
*/
|
|
@@ -73,10 +76,6 @@ export declare class TypeSchemaParser {
|
|
|
73
76
|
* Check if identifier matches criteria
|
|
74
77
|
*/
|
|
75
78
|
private matchesIdentifier;
|
|
76
|
-
/**
|
|
77
|
-
* Remove duplicate dependencies
|
|
78
|
-
*/
|
|
79
|
-
private deduplicateDependencies;
|
|
80
79
|
}
|
|
81
80
|
/**
|
|
82
81
|
* Convenience function to parse TypeSchema from file
|