@atomic-ehr/codegen 0.0.1-canary.20251006092200.fdb4a88 → 0.0.1-canary.20251006094042.7f0be72
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/cli/index.js +45 -124
- package/dist/index.d.ts +2130 -62
- package/dist/index.js +5865 -84
- package/dist/index.js.map +1 -0
- package/package.json +3 -7
- package/dist/api/builder.d.ts +0 -154
- package/dist/api/builder.js +0 -341
- package/dist/api/generators/base/BaseGenerator.d.ts +0 -186
- package/dist/api/generators/base/BaseGenerator.js +0 -565
- package/dist/api/generators/base/FileManager.d.ts +0 -88
- package/dist/api/generators/base/FileManager.js +0 -202
- package/dist/api/generators/base/PythonTypeMapper.d.ts +0 -16
- package/dist/api/generators/base/PythonTypeMapper.js +0 -71
- package/dist/api/generators/base/TemplateEngine.d.ts +0 -126
- package/dist/api/generators/base/TemplateEngine.js +0 -133
- package/dist/api/generators/base/TypeMapper.d.ts +0 -129
- package/dist/api/generators/base/TypeMapper.js +0 -153
- package/dist/api/generators/base/TypeScriptTypeMapper.d.ts +0 -51
- package/dist/api/generators/base/TypeScriptTypeMapper.js +0 -232
- package/dist/api/generators/base/builders/DirectoryBuilder.d.ts +0 -99
- package/dist/api/generators/base/builders/DirectoryBuilder.js +0 -215
- package/dist/api/generators/base/builders/FileBuilder.d.ts +0 -160
- package/dist/api/generators/base/builders/FileBuilder.js +0 -406
- package/dist/api/generators/base/builders/IndexBuilder.d.ts +0 -126
- package/dist/api/generators/base/builders/IndexBuilder.js +0 -290
- package/dist/api/generators/base/enhanced-errors.d.ts +0 -84
- package/dist/api/generators/base/enhanced-errors.js +0 -259
- package/dist/api/generators/base/error-handler.d.ts +0 -89
- package/dist/api/generators/base/error-handler.js +0 -243
- package/dist/api/generators/base/errors.d.ts +0 -251
- package/dist/api/generators/base/errors.js +0 -692
- package/dist/api/generators/base/index.d.ts +0 -99
- package/dist/api/generators/base/index.js +0 -160
- package/dist/api/generators/base/types.d.ts +0 -433
- package/dist/api/generators/base/types.js +0 -12
- package/dist/api/generators/types.d.ts +0 -53
- package/dist/api/generators/types.js +0 -4
- package/dist/api/generators/typescript.d.ts +0 -190
- package/dist/api/generators/typescript.js +0 -819
- package/dist/api/index.d.ts +0 -51
- package/dist/api/index.js +0 -50
- package/dist/cli/commands/generate/typescript.d.ts +0 -10
- package/dist/cli/commands/generate/typescript.js +0 -52
- package/dist/cli/commands/generate.d.ts +0 -15
- package/dist/cli/commands/generate.js +0 -159
- package/dist/cli/commands/index.d.ts +0 -29
- package/dist/cli/commands/index.js +0 -100
- package/dist/cli/commands/typeschema/generate.d.ts +0 -19
- package/dist/cli/commands/typeschema/generate.js +0 -124
- package/dist/cli/commands/typeschema.d.ts +0 -10
- package/dist/cli/commands/typeschema.js +0 -47
- package/dist/cli/index.d.ts +0 -9
- package/dist/cli/utils/log.d.ts +0 -10
- package/dist/cli/utils/log.js +0 -23
- package/dist/cli/utils/prompts.d.ts +0 -56
- package/dist/cli/utils/prompts.js +0 -202
- package/dist/cli/utils/spinner.d.ts +0 -110
- package/dist/cli/utils/spinner.js +0 -266
- package/dist/config.d.ts +0 -217
- package/dist/config.js +0 -591
- package/dist/logger.d.ts +0 -157
- package/dist/logger.js +0 -281
- package/dist/typeschema/cache.d.ts +0 -80
- package/dist/typeschema/cache.js +0 -239
- package/dist/typeschema/core/binding.d.ts +0 -11
- package/dist/typeschema/core/binding.js +0 -143
- package/dist/typeschema/core/field-builder.d.ts +0 -12
- package/dist/typeschema/core/field-builder.js +0 -123
- package/dist/typeschema/core/identifier.d.ts +0 -13
- package/dist/typeschema/core/identifier.js +0 -94
- package/dist/typeschema/core/nested-types.d.ts +0 -9
- package/dist/typeschema/core/nested-types.js +0 -93
- package/dist/typeschema/core/transformer.d.ts +0 -11
- package/dist/typeschema/core/transformer.js +0 -235
- package/dist/typeschema/generator.d.ts +0 -36
- package/dist/typeschema/generator.js +0 -243
- package/dist/typeschema/index.d.ts +0 -15
- package/dist/typeschema/index.js +0 -15
- package/dist/typeschema/parser.d.ts +0 -79
- package/dist/typeschema/parser.js +0 -274
- package/dist/typeschema/profile/processor.d.ts +0 -14
- package/dist/typeschema/profile/processor.js +0 -261
- package/dist/typeschema/register.d.ts +0 -21
- package/dist/typeschema/register.js +0 -117
- package/dist/typeschema/types.d.ts +0 -240
- package/dist/typeschema/types.js +0 -19
- package/dist/utils/codegen-logger.d.ts +0 -102
- package/dist/utils/codegen-logger.js +0 -196
- package/dist/utils.d.ts +0 -22
- package/dist/utils.js +0 -42
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Nested Types (BackboneElement) Handling
|
|
3
|
-
*
|
|
4
|
-
* Functions for extracting and transforming nested types from FHIRSchema
|
|
5
|
-
*/
|
|
6
|
-
import { isNestedElement, mkField, mkNestedField } from "./field-builder";
|
|
7
|
-
import { mkNestedIdentifier } from "./identifier";
|
|
8
|
-
function collectNestedElements(fhirSchema, parentPath, elements) {
|
|
9
|
-
const nested = [];
|
|
10
|
-
for (const [key, element] of Object.entries(elements)) {
|
|
11
|
-
const path = [...parentPath, key];
|
|
12
|
-
if (isNestedElement(element)) {
|
|
13
|
-
nested.push([path, element]);
|
|
14
|
-
}
|
|
15
|
-
if (element.elements) {
|
|
16
|
-
nested.push(...collectNestedElements(fhirSchema, path, element.elements));
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return nested;
|
|
20
|
-
}
|
|
21
|
-
function transformNestedElements(fhirSchema, parentPath, elements, register) {
|
|
22
|
-
const fields = {};
|
|
23
|
-
for (const [key, element] of Object.entries(elements)) {
|
|
24
|
-
const path = [...parentPath, key];
|
|
25
|
-
if (isNestedElement(element)) {
|
|
26
|
-
fields[key] = mkNestedField(register, fhirSchema, path, element);
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
fields[key] = mkField(register, fhirSchema, path, element);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return fields;
|
|
33
|
-
}
|
|
34
|
-
export function mkNestedTypes(register, fhirSchema) {
|
|
35
|
-
if (!fhirSchema.elements)
|
|
36
|
-
return undefined;
|
|
37
|
-
const nestedElements = collectNestedElements(fhirSchema, [], fhirSchema.elements);
|
|
38
|
-
const actualNested = nestedElements.filter(([_, element]) => element.elements && Object.keys(element.elements).length > 0);
|
|
39
|
-
const nestedTypes = [];
|
|
40
|
-
for (const [path, element] of actualNested) {
|
|
41
|
-
const identifier = mkNestedIdentifier(fhirSchema, path);
|
|
42
|
-
// Base is usually BackboneElement - ensure all nested types have a base
|
|
43
|
-
// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
|
|
44
|
-
let base;
|
|
45
|
-
if (element.type === "BackboneElement" || !element.type) {
|
|
46
|
-
// For BackboneElement or undefined type, always use BackboneElement as base
|
|
47
|
-
base = {
|
|
48
|
-
kind: "complex-type",
|
|
49
|
-
package: fhirSchema.package_meta.name,
|
|
50
|
-
version: fhirSchema.package_meta.version,
|
|
51
|
-
name: "BackboneElement",
|
|
52
|
-
url: "http://hl7.org/fhir/StructureDefinition/BackboneElement",
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
// Use the specified type as base
|
|
57
|
-
base = {
|
|
58
|
-
kind: "complex-type",
|
|
59
|
-
package: fhirSchema.package_meta.name,
|
|
60
|
-
version: fhirSchema.package_meta.version,
|
|
61
|
-
name: element.type,
|
|
62
|
-
url: `http://hl7.org/fhir/StructureDefinition/${element.type}`,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
const fields = transformNestedElements(fhirSchema, path, element.elements, register);
|
|
66
|
-
const nestedType = {
|
|
67
|
-
identifier,
|
|
68
|
-
base,
|
|
69
|
-
fields,
|
|
70
|
-
};
|
|
71
|
-
nestedTypes.push(nestedType);
|
|
72
|
-
}
|
|
73
|
-
// Sort by URL for consistent output
|
|
74
|
-
nestedTypes.sort((a, b) => a.identifier.url.localeCompare(b.identifier.url));
|
|
75
|
-
return nestedTypes.length === 0 ? undefined : nestedTypes;
|
|
76
|
-
}
|
|
77
|
-
export function extractNestedDependencies(nestedTypes) {
|
|
78
|
-
const deps = [];
|
|
79
|
-
for (const nested of nestedTypes) {
|
|
80
|
-
if (nested.base) {
|
|
81
|
-
deps.push(nested.base);
|
|
82
|
-
}
|
|
83
|
-
for (const field of Object.values(nested.fields || {})) {
|
|
84
|
-
if ("type" in field && field.type) {
|
|
85
|
-
deps.push(field.type);
|
|
86
|
-
}
|
|
87
|
-
if ("binding" in field && field.binding) {
|
|
88
|
-
deps.push(field.binding);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return deps;
|
|
93
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Main FHIRSchema to TypeSchema Transformer
|
|
3
|
-
*
|
|
4
|
-
* Core transformation logic for converting FHIRSchema to TypeSchema format
|
|
5
|
-
*/
|
|
6
|
-
import type { FHIRSchemaElement } from "@atomic-ehr/fhirschema";
|
|
7
|
-
import { type Register } from "@typeschema/register";
|
|
8
|
-
import type { Field, RichFHIRSchema, RichValueSet, TypeSchema, ValueSetTypeSchema } from "@typeschema/types";
|
|
9
|
-
export declare function mkFields(register: Register, fhirSchema: RichFHIRSchema, parentPath: string[], elements: Record<string, FHIRSchemaElement> | undefined): Record<string, Field> | undefined;
|
|
10
|
-
export declare function transformValueSet(register: Register, valueSet: RichValueSet): Promise<ValueSetTypeSchema>;
|
|
11
|
-
export declare function transformFhirSchema(register: Register, fhirSchema: RichFHIRSchema): Promise<TypeSchema[]>;
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Main FHIRSchema to TypeSchema Transformer
|
|
3
|
-
*
|
|
4
|
-
* Core transformation logic for converting FHIRSchema to TypeSchema format
|
|
5
|
-
*/
|
|
6
|
-
import { fsElementSnapshot, resolveFsElementGenealogy } from "@typeschema/register";
|
|
7
|
-
import { transformProfile } from "../profile/processor";
|
|
8
|
-
import { collectBindingSchemas, extractValueSetConceptsByUrl } from "./binding";
|
|
9
|
-
import { isNestedElement, mkField, mkNestedField } from "./field-builder";
|
|
10
|
-
import { mkIdentifier, mkValueSetIdentifierByUrl } from "./identifier";
|
|
11
|
-
import { extractNestedDependencies, mkNestedTypes } from "./nested-types";
|
|
12
|
-
export function mkFields(register, fhirSchema, parentPath, elements) {
|
|
13
|
-
if (!elements)
|
|
14
|
-
return undefined;
|
|
15
|
-
const geneology = register.resolveFsGenealogy(fhirSchema.url);
|
|
16
|
-
const elems = {};
|
|
17
|
-
for (const [key, elem] of Object.entries(elements)) {
|
|
18
|
-
const path = [...parentPath, key];
|
|
19
|
-
const elemGeneology = resolveFsElementGenealogy(geneology, path);
|
|
20
|
-
const elemSnapshot = fsElementSnapshot(elemGeneology);
|
|
21
|
-
elems[key] = { elem, elemSnapshot, path };
|
|
22
|
-
}
|
|
23
|
-
for (const [_key, { elem, elemSnapshot, path }] of Object.entries(elems)) {
|
|
24
|
-
for (const choiceKey of elem?.choices || []) {
|
|
25
|
-
if (!elems[choiceKey]) {
|
|
26
|
-
const path = [...parentPath, choiceKey];
|
|
27
|
-
const elemGeneology = resolveFsElementGenealogy(geneology, path);
|
|
28
|
-
const elemSnapshot = fsElementSnapshot(elemGeneology);
|
|
29
|
-
elems[choiceKey] = { elem: undefined, elemSnapshot, path };
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
const fields = {};
|
|
34
|
-
for (const [key, { elem, elemSnapshot, path }] of Object.entries(elems)) {
|
|
35
|
-
if (isNestedElement(elemSnapshot)) {
|
|
36
|
-
fields[key] = mkNestedField(register, fhirSchema, path, elemSnapshot);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
fields[key] = mkField(register, fhirSchema, path, elemSnapshot);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return fields;
|
|
43
|
-
}
|
|
44
|
-
function extractFieldDependencies(fields) {
|
|
45
|
-
const deps = [];
|
|
46
|
-
for (const field of Object.values(fields)) {
|
|
47
|
-
if ("type" in field && field.type) {
|
|
48
|
-
deps.push(field.type);
|
|
49
|
-
}
|
|
50
|
-
if ("binding" in field && field.binding) {
|
|
51
|
-
deps.push(field.binding);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return deps;
|
|
55
|
-
}
|
|
56
|
-
function deduplicateDependencies(deps) {
|
|
57
|
-
const seen = new Set();
|
|
58
|
-
const unique = [];
|
|
59
|
-
for (const dep of deps) {
|
|
60
|
-
const key = dep.url;
|
|
61
|
-
if (!seen.has(key)) {
|
|
62
|
-
seen.add(key);
|
|
63
|
-
unique.push(dep);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
// Sort by name for consistent output (matching Clojure implementation)
|
|
67
|
-
unique.sort((a, b) => a.name.localeCompare(b.name));
|
|
68
|
-
return unique;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Check if a FHIR schema represents an extension
|
|
72
|
-
*/
|
|
73
|
-
function isExtensionSchema(fhirSchema, _identifier) {
|
|
74
|
-
// Check if this is based on Extension
|
|
75
|
-
if (fhirSchema.base === "Extension" || fhirSchema.base === "http://hl7.org/fhir/StructureDefinition/Extension") {
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
// Check if the URL indicates this is an extension
|
|
79
|
-
if (fhirSchema.url?.includes("/extension/") || fhirSchema.url?.includes("-extension")) {
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
// Check if the name indicates this is an extension
|
|
83
|
-
if (fhirSchema.name?.toLowerCase().includes("extension")) {
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
// Check if the type is Extension
|
|
87
|
-
if (fhirSchema.type === "Extension") {
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
export async function transformValueSet(register, valueSet) {
|
|
93
|
-
if (!valueSet.url)
|
|
94
|
-
throw new Error("ValueSet URL is required");
|
|
95
|
-
const identifier = mkValueSetIdentifierByUrl(register, valueSet.url);
|
|
96
|
-
const concept = extractValueSetConceptsByUrl(register, valueSet.url);
|
|
97
|
-
return {
|
|
98
|
-
identifier: identifier,
|
|
99
|
-
description: valueSet.description,
|
|
100
|
-
concept: concept,
|
|
101
|
-
compose: !concept ? valueSet.compose : undefined,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Transform an Extension FHIRSchema to TypeSchema with extension metadata
|
|
106
|
-
*/
|
|
107
|
-
async function transformExtension(fhirSchema, register, _packageInfo) {
|
|
108
|
-
try {
|
|
109
|
-
const identifier = mkIdentifier(fhirSchema);
|
|
110
|
-
// Build base identifier if present
|
|
111
|
-
let base;
|
|
112
|
-
if (fhirSchema.base && fhirSchema.base !== "Extension") {
|
|
113
|
-
const baseUrl = fhirSchema.base.includes("/")
|
|
114
|
-
? fhirSchema.base
|
|
115
|
-
: `http://hl7.org/fhir/StructureDefinition/${fhirSchema.base}`;
|
|
116
|
-
const baseName = fhirSchema.base.split("/").pop() || fhirSchema.base;
|
|
117
|
-
base = {
|
|
118
|
-
kind: "complex-type",
|
|
119
|
-
package: "hl7.fhir.r4.core",
|
|
120
|
-
version: "4.0.1",
|
|
121
|
-
name: baseName,
|
|
122
|
-
url: baseUrl,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
// Default to Extension base
|
|
127
|
-
base = {
|
|
128
|
-
kind: "complex-type",
|
|
129
|
-
package: "hl7.fhir.r4.core",
|
|
130
|
-
version: "4.0.1",
|
|
131
|
-
name: "Extension",
|
|
132
|
-
url: "http://hl7.org/fhir/StructureDefinition/Extension",
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
const extensionSchema = {
|
|
136
|
-
identifier,
|
|
137
|
-
base,
|
|
138
|
-
description: fhirSchema.description,
|
|
139
|
-
dependencies: [],
|
|
140
|
-
metadata: {
|
|
141
|
-
isExtension: true, // Mark as extension for file organization
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
// Add base to dependencies
|
|
145
|
-
if (base) {
|
|
146
|
-
extensionSchema.dependencies.push(base);
|
|
147
|
-
}
|
|
148
|
-
// Transform elements into fields if present
|
|
149
|
-
if (fhirSchema.elements) {
|
|
150
|
-
const fields = mkFields(register, fhirSchema, [], fhirSchema.elements);
|
|
151
|
-
if (fields && Object.keys(fields).length > 0) {
|
|
152
|
-
extensionSchema.fields = fields;
|
|
153
|
-
extensionSchema.dependencies.push(...extractFieldDependencies(fields));
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// Build nested types
|
|
157
|
-
const nestedTypes = mkNestedTypes(register, fhirSchema);
|
|
158
|
-
if (nestedTypes && nestedTypes.length > 0) {
|
|
159
|
-
extensionSchema.nested = nestedTypes;
|
|
160
|
-
extensionSchema.dependencies.push(...extractNestedDependencies(nestedTypes));
|
|
161
|
-
}
|
|
162
|
-
// Deduplicate and sort dependencies
|
|
163
|
-
extensionSchema.dependencies = deduplicateDependencies(extensionSchema.dependencies);
|
|
164
|
-
// Remove self-reference from dependencies
|
|
165
|
-
extensionSchema.dependencies = extensionSchema.dependencies.filter((dep) => dep.url !== identifier.url);
|
|
166
|
-
return extensionSchema;
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
console.warn(`Failed to transform extension ${fhirSchema.name}: ${error}`);
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
function extractDependencies(identifier, base, fields, nestedTypes) {
|
|
174
|
-
const deps = [];
|
|
175
|
-
if (base)
|
|
176
|
-
deps.push(base);
|
|
177
|
-
if (fields)
|
|
178
|
-
deps.push(...extractFieldDependencies(fields));
|
|
179
|
-
if (nestedTypes)
|
|
180
|
-
deps.push(...extractNestedDependencies(nestedTypes));
|
|
181
|
-
const uniqDeps = {};
|
|
182
|
-
for (const dep of deps) {
|
|
183
|
-
if (dep.url === identifier.url)
|
|
184
|
-
continue;
|
|
185
|
-
uniqDeps[dep.url] = dep;
|
|
186
|
-
}
|
|
187
|
-
const localNestedTypeUrls = new Set(nestedTypes?.map((nt) => nt.identifier.url));
|
|
188
|
-
const result = Object.values(uniqDeps)
|
|
189
|
-
.filter((e) => !(e.kind === "nested" && localNestedTypeUrls.has(e.url)))
|
|
190
|
-
.sort((a, b) => a.url.localeCompare(b.url));
|
|
191
|
-
return result.length > 0 ? result : undefined;
|
|
192
|
-
}
|
|
193
|
-
function transformFhirSchemaResource(register, fhirSchema) {
|
|
194
|
-
const identifier = mkIdentifier(fhirSchema);
|
|
195
|
-
let base;
|
|
196
|
-
if (fhirSchema.base && fhirSchema.type !== "Element") {
|
|
197
|
-
const baseFs = register.resolveFs(register.ensureCanonicalUrl(fhirSchema.base));
|
|
198
|
-
if (!baseFs) {
|
|
199
|
-
throw new Error(`Base resource not found '${fhirSchema.base}' for '${fhirSchema.url}'`);
|
|
200
|
-
}
|
|
201
|
-
base = mkIdentifier(baseFs);
|
|
202
|
-
}
|
|
203
|
-
const fields = mkFields(register, fhirSchema, [], fhirSchema.elements);
|
|
204
|
-
const nested = mkNestedTypes(register, fhirSchema);
|
|
205
|
-
const dependencies = extractDependencies(identifier, base, fields, nested);
|
|
206
|
-
const typeSchema = {
|
|
207
|
-
identifier,
|
|
208
|
-
base,
|
|
209
|
-
fields,
|
|
210
|
-
nested,
|
|
211
|
-
description: fhirSchema.description,
|
|
212
|
-
dependencies,
|
|
213
|
-
};
|
|
214
|
-
const bindingSchemas = collectBindingSchemas(register, fhirSchema);
|
|
215
|
-
return [typeSchema, ...bindingSchemas];
|
|
216
|
-
}
|
|
217
|
-
export async function transformFhirSchema(register, fhirSchema) {
|
|
218
|
-
const results = [];
|
|
219
|
-
const identifier = mkIdentifier(fhirSchema);
|
|
220
|
-
if (identifier.kind === "profile") {
|
|
221
|
-
const profileSchema = await transformProfile(register, fhirSchema);
|
|
222
|
-
results.push(profileSchema);
|
|
223
|
-
const bindingSchemas = collectBindingSchemas(register, fhirSchema);
|
|
224
|
-
results.push(...bindingSchemas);
|
|
225
|
-
return results;
|
|
226
|
-
}
|
|
227
|
-
if (isExtensionSchema(fhirSchema, identifier)) {
|
|
228
|
-
const extensionSchema = await transformExtension(fhirSchema, register, fhirSchema.package_meta);
|
|
229
|
-
if (extensionSchema) {
|
|
230
|
-
results.push(extensionSchema);
|
|
231
|
-
}
|
|
232
|
-
return results;
|
|
233
|
-
}
|
|
234
|
-
return transformFhirSchemaResource(register, fhirSchema);
|
|
235
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeSchema Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates TypeSchema documents from FHIR packages using fhrischema.
|
|
5
|
-
* Provides high-level API for converting FHIR Structure Definitions to TypeSchema format.
|
|
6
|
-
*/
|
|
7
|
-
import type { FHIRSchema, StructureDefinition } from "@atomic-ehr/fhirschema";
|
|
8
|
-
import type { TypeSchemaConfig } from "@root/config";
|
|
9
|
-
import type { Register } from "@typeschema/register";
|
|
10
|
-
import type { PackageMeta, TypeSchema, TypeschemaGeneratorOptions } from "./types";
|
|
11
|
-
/**
|
|
12
|
-
* TypeSchema Generator class
|
|
13
|
-
*
|
|
14
|
-
* Main class for generating TypeSchema documents from FHIR packages.
|
|
15
|
-
* Leverages fhrischema for FHIR parsing and canonical manager for dependency resolution.
|
|
16
|
-
*/
|
|
17
|
-
export declare class TypeSchemaGenerator {
|
|
18
|
-
private manager;
|
|
19
|
-
private options;
|
|
20
|
-
private cacheConfig?;
|
|
21
|
-
private cache?;
|
|
22
|
-
private logger;
|
|
23
|
-
constructor(options?: TypeschemaGeneratorOptions, cacheConfig?: TypeSchemaConfig);
|
|
24
|
-
private initializeCache;
|
|
25
|
-
registerFromPackageMetas(packageMetas: PackageMeta[]): Promise<Register>;
|
|
26
|
-
generateFhirSchemas(structureDefinitions: StructureDefinition[]): FHIRSchema[];
|
|
27
|
-
generateValueSetSchemas(valueSets: any[], _packageInfo: PackageMeta): Promise<TypeSchema[]>;
|
|
28
|
-
generateFromPackage(packageName: string, packageVersion?: string): Promise<TypeSchema[]>;
|
|
29
|
-
/**
|
|
30
|
-
* Apply treeshaking to StructureDefinitions before FHIR schema transformation
|
|
31
|
-
* This is more efficient and includes smart reference handling
|
|
32
|
-
*/
|
|
33
|
-
private applyStructureDefinitionTreeshaking;
|
|
34
|
-
private extractStructureDefinitionDependenciesWithReferences;
|
|
35
|
-
private extractResourceNameFromUrl;
|
|
36
|
-
}
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeSchema Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates TypeSchema documents from FHIR packages using fhrischema.
|
|
5
|
-
* Provides high-level API for converting FHIR Structure Definitions to TypeSchema format.
|
|
6
|
-
*/
|
|
7
|
-
import { CanonicalManager } from "@atomic-ehr/fhir-canonical-manager";
|
|
8
|
-
import * as fhirschema from "@atomic-ehr/fhirschema";
|
|
9
|
-
import { createLogger } from "@root/utils/codegen-logger";
|
|
10
|
-
import { registerFromManager } from "@typeschema/register";
|
|
11
|
-
import { TypeSchemaCache } from "./cache";
|
|
12
|
-
import { transformFhirSchema, transformValueSet } from "./core/transformer";
|
|
13
|
-
/**
|
|
14
|
-
* TypeSchema Generator class
|
|
15
|
-
*
|
|
16
|
-
* Main class for generating TypeSchema documents from FHIR packages.
|
|
17
|
-
* Leverages fhrischema for FHIR parsing and canonical manager for dependency resolution.
|
|
18
|
-
*/
|
|
19
|
-
export class TypeSchemaGenerator {
|
|
20
|
-
manager;
|
|
21
|
-
options;
|
|
22
|
-
cacheConfig;
|
|
23
|
-
cache;
|
|
24
|
-
logger;
|
|
25
|
-
constructor(options = {}, cacheConfig) {
|
|
26
|
-
this.options = { verbose: false, ...options };
|
|
27
|
-
this.manager = options.manager || CanonicalManager({ packages: [], workingDir: "tmp/fhir" });
|
|
28
|
-
this.cacheConfig = cacheConfig;
|
|
29
|
-
this.logger =
|
|
30
|
-
options.logger ||
|
|
31
|
-
createLogger({
|
|
32
|
-
verbose: this.options.verbose,
|
|
33
|
-
prefix: "TypeSchema",
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
async initializeCache() {
|
|
37
|
-
if (this.cacheConfig && !this.cache) {
|
|
38
|
-
this.cache = new TypeSchemaCache(this.cacheConfig);
|
|
39
|
-
await this.cache.initialize();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
async registerFromPackageMetas(packageMetas) {
|
|
43
|
-
const packageNames = packageMetas.map((meta) => `${meta.name}${meta.version}`);
|
|
44
|
-
this.logger.step(`Loading FHIR packages: ${packageNames.join(", ")}`);
|
|
45
|
-
await this.manager.init();
|
|
46
|
-
return registerFromManager(this.manager);
|
|
47
|
-
}
|
|
48
|
-
generateFhirSchemas(structureDefinitions) {
|
|
49
|
-
this.logger.progress(`Converting ${structureDefinitions.length} StructureDefinitions to FHIRSchemas`);
|
|
50
|
-
// TODO: do it on the TypeSchema?
|
|
51
|
-
const filteredStructureDefinitions = this.applyStructureDefinitionTreeshaking(structureDefinitions);
|
|
52
|
-
const fhirSchemas = [];
|
|
53
|
-
let convertedCount = 0;
|
|
54
|
-
let failedCount = 0;
|
|
55
|
-
for (const sd of filteredStructureDefinitions) {
|
|
56
|
-
try {
|
|
57
|
-
const fhirSchema = fhirschema.translate(sd);
|
|
58
|
-
fhirSchemas.push(fhirSchema);
|
|
59
|
-
convertedCount++;
|
|
60
|
-
this.logger.debug(`Converted StructureDefinition: ${sd.name || sd.id} (${sd.resourceType})`);
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
failedCount++;
|
|
64
|
-
this.logger.warn(`Failed to convert StructureDefinition ${sd.name || sd.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
this.logger.success(`FHIR Schema conversion completed: ${convertedCount}/${filteredStructureDefinitions.length} successful, ${failedCount} failed`);
|
|
68
|
-
return fhirSchemas;
|
|
69
|
-
}
|
|
70
|
-
async generateValueSetSchemas(valueSets, _packageInfo) {
|
|
71
|
-
if (valueSets.length > 0) {
|
|
72
|
-
this.logger.debug(`${valueSets.length} ValueSets available for enum extraction`);
|
|
73
|
-
}
|
|
74
|
-
// Process ValueSets separately to add to TypeSchema output
|
|
75
|
-
const valueSetSchemas = [];
|
|
76
|
-
if (valueSets.length > 0) {
|
|
77
|
-
this.logger.progress(`Converting ${valueSets.length} ValueSets to TypeSchema`);
|
|
78
|
-
let valueSetConvertedCount = 0;
|
|
79
|
-
let valueSetFailedCount = 0;
|
|
80
|
-
for (const vs of valueSets) {
|
|
81
|
-
try {
|
|
82
|
-
const valueSetSchema = await transformValueSet(await registerFromManager(this.manager), vs);
|
|
83
|
-
if (valueSetSchema) {
|
|
84
|
-
valueSetSchemas.push(valueSetSchema);
|
|
85
|
-
valueSetConvertedCount++;
|
|
86
|
-
this.logger.debug(`Converted ValueSet: ${vs.name || vs.id}`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
valueSetFailedCount++;
|
|
91
|
-
this.logger.warn(`Failed to convert ValueSet ${vs.name || vs.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
this.logger.success(`ValueSet conversion completed: ${valueSetConvertedCount}/${valueSets.length} successful, ${valueSetFailedCount} failed`);
|
|
95
|
-
}
|
|
96
|
-
return valueSetSchemas;
|
|
97
|
-
}
|
|
98
|
-
async generateFromPackage(packageName, packageVersion) {
|
|
99
|
-
await this.initializeCache();
|
|
100
|
-
if (this.cache && !(this.cacheConfig?.forceRegenerate ?? false)) {
|
|
101
|
-
const cachedSchemas = this.cache.getByPackage(packageName);
|
|
102
|
-
if (cachedSchemas.length > 0) {
|
|
103
|
-
this.logger.info(`Using cached TypeSchemas for package: ${packageName} (${cachedSchemas.length} schemas)`);
|
|
104
|
-
return cachedSchemas;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
const packageInfo = {
|
|
108
|
-
name: packageName,
|
|
109
|
-
version: packageVersion || "latest",
|
|
110
|
-
};
|
|
111
|
-
const register = await this.registerFromPackageMetas([packageInfo]);
|
|
112
|
-
const allSchemas = [
|
|
113
|
-
...(await Promise.all(register.allFs().map(async (fs) => await transformFhirSchema(register, fs)))).flat(),
|
|
114
|
-
...(await this.generateValueSetSchemas(register.allVs(), packageInfo)),
|
|
115
|
-
];
|
|
116
|
-
if (this.cache) {
|
|
117
|
-
for (const schema of allSchemas) {
|
|
118
|
-
await this.cache.set(schema);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return allSchemas;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Apply treeshaking to StructureDefinitions before FHIR schema transformation
|
|
125
|
-
* This is more efficient and includes smart reference handling
|
|
126
|
-
*/
|
|
127
|
-
applyStructureDefinitionTreeshaking(structureDefinitions) {
|
|
128
|
-
const treeshakeList = this.options.treeshake;
|
|
129
|
-
if (!treeshakeList || treeshakeList.length === 0) {
|
|
130
|
-
return structureDefinitions;
|
|
131
|
-
}
|
|
132
|
-
this.logger.info(`Applying treeshaking filter for ResourceTypes: ${treeshakeList.join(", ")}`);
|
|
133
|
-
const allStructureDefinitions = new Map();
|
|
134
|
-
const realDependencies = new Map();
|
|
135
|
-
const referenceTargets = new Map();
|
|
136
|
-
for (const sd of structureDefinitions) {
|
|
137
|
-
const name = sd.name || sd.id;
|
|
138
|
-
if (name) {
|
|
139
|
-
allStructureDefinitions.set(name, sd);
|
|
140
|
-
realDependencies.set(name, new Set());
|
|
141
|
-
referenceTargets.set(name, new Set());
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
for (const sd of structureDefinitions) {
|
|
145
|
-
const name = sd.name || sd.id;
|
|
146
|
-
if (!name)
|
|
147
|
-
continue;
|
|
148
|
-
const { realDeps, refTargets } = this.extractStructureDefinitionDependenciesWithReferences(sd);
|
|
149
|
-
realDependencies.set(name, new Set(realDeps));
|
|
150
|
-
referenceTargets.set(name, new Set(refTargets));
|
|
151
|
-
}
|
|
152
|
-
const structureDefinitionsToKeep = new Set();
|
|
153
|
-
for (const resourceType of treeshakeList) {
|
|
154
|
-
if (allStructureDefinitions.has(resourceType)) {
|
|
155
|
-
structureDefinitionsToKeep.add(resourceType);
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
this.logger.warn(`ResourceType '${resourceType}' not found in structure definitions`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
const addRealDependenciesRecursively = (name, visited = new Set()) => {
|
|
162
|
-
if (visited.has(name) || !realDependencies.has(name)) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
visited.add(name);
|
|
166
|
-
const deps = realDependencies.get(name) || new Set();
|
|
167
|
-
for (const dep of Array.from(deps)) {
|
|
168
|
-
if (allStructureDefinitions.has(dep)) {
|
|
169
|
-
structureDefinitionsToKeep.add(dep);
|
|
170
|
-
addRealDependenciesRecursively(dep, visited);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
for (const resourceType of Array.from(structureDefinitionsToKeep)) {
|
|
175
|
-
addRealDependenciesRecursively(resourceType);
|
|
176
|
-
}
|
|
177
|
-
const filteredStructureDefinitions = structureDefinitions.filter((sd) => {
|
|
178
|
-
const name = sd.name || sd.id;
|
|
179
|
-
return name && structureDefinitionsToKeep.has(name);
|
|
180
|
-
});
|
|
181
|
-
const excludedReferenceTargets = new Set();
|
|
182
|
-
for (const sd of structureDefinitions) {
|
|
183
|
-
const name = sd.name || sd.id;
|
|
184
|
-
if (name && !structureDefinitionsToKeep.has(name)) {
|
|
185
|
-
const isOnlyReferenceTarget = Array.from(referenceTargets.values()).some((targets) => targets.has(name));
|
|
186
|
-
if (isOnlyReferenceTarget) {
|
|
187
|
-
excludedReferenceTargets.add(name);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
if (excludedReferenceTargets.size > 0) {
|
|
192
|
-
this.logger.info(`Excluded reference-only targets: ${Array.from(excludedReferenceTargets).join(", ")}`);
|
|
193
|
-
}
|
|
194
|
-
this.logger.success(`Treeshaking completed: kept ${filteredStructureDefinitions.length}/${structureDefinitions.length} structure definitions`);
|
|
195
|
-
return filteredStructureDefinitions;
|
|
196
|
-
}
|
|
197
|
-
extractStructureDefinitionDependenciesWithReferences(sd) {
|
|
198
|
-
const realDeps = new Set();
|
|
199
|
-
const refTargets = new Set();
|
|
200
|
-
if (sd.baseDefinition) {
|
|
201
|
-
const baseName = this.extractResourceNameFromUrl(sd.baseDefinition);
|
|
202
|
-
if (baseName) {
|
|
203
|
-
realDeps.add(baseName);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
if (sd.snapshot?.element || sd.differential?.element) {
|
|
207
|
-
const elements = sd.snapshot?.element || sd.differential?.element;
|
|
208
|
-
for (const element of elements) {
|
|
209
|
-
if (element.type) {
|
|
210
|
-
for (const type of element.type) {
|
|
211
|
-
if (type.code) {
|
|
212
|
-
realDeps.add(type.code);
|
|
213
|
-
if (type.code === "Reference" && type.targetProfile) {
|
|
214
|
-
for (const targetProfile of type.targetProfile) {
|
|
215
|
-
const targetName = this.extractResourceNameFromUrl(targetProfile);
|
|
216
|
-
if (targetName) {
|
|
217
|
-
refTargets.add(targetName);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
if (type.profile) {
|
|
223
|
-
for (const profile of type.profile) {
|
|
224
|
-
const profileName = this.extractResourceNameFromUrl(profile);
|
|
225
|
-
if (profileName) {
|
|
226
|
-
realDeps.add(profileName);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return {
|
|
235
|
-
realDeps: Array.from(realDeps),
|
|
236
|
-
refTargets: Array.from(refTargets),
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
extractResourceNameFromUrl(url) {
|
|
240
|
-
const match = url.match(/\/([^/]+)$/);
|
|
241
|
-
return match ? (match[1] ?? null) : null;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeSchema Core Module
|
|
3
|
-
*
|
|
4
|
-
* Main entry point for the TypeSchema library providing core functions
|
|
5
|
-
* for FHIR-to-TypeSchema generation, parsing, and validation.
|
|
6
|
-
*
|
|
7
|
-
* This module focuses on:
|
|
8
|
-
* - Converting FHIR to TypeSchema format
|
|
9
|
-
* - Reading TypeSchema documents
|
|
10
|
-
* - Validating TypeSchema documents
|
|
11
|
-
*/
|
|
12
|
-
export { TypeSchemaCache } from "./cache";
|
|
13
|
-
export { TypeSchemaGenerator } from "./generator";
|
|
14
|
-
export { TypeSchemaParser } from "./parser";
|
|
15
|
-
export type { Identifier, TypeSchema } from "./types";
|
package/dist/typeschema/index.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeSchema Core Module
|
|
3
|
-
*
|
|
4
|
-
* Main entry point for the TypeSchema library providing core functions
|
|
5
|
-
* for FHIR-to-TypeSchema generation, parsing, and validation.
|
|
6
|
-
*
|
|
7
|
-
* This module focuses on:
|
|
8
|
-
* - Converting FHIR to TypeSchema format
|
|
9
|
-
* - Reading TypeSchema documents
|
|
10
|
-
* - Validating TypeSchema documents
|
|
11
|
-
*/
|
|
12
|
-
// Re-export core dependencies
|
|
13
|
-
export { TypeSchemaCache } from "./cache";
|
|
14
|
-
export { TypeSchemaGenerator } from "./generator";
|
|
15
|
-
export { TypeSchemaParser } from "./parser";
|