@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.
@@ -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, RichFHIRSchema, TypeSchemaField } from "../types";
10
- /**
11
- * Get the full element hierarchy for a given path
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) => TypeSchemaField;
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, manager: ReturnType<typeof CanonicalManager>, _packageInfo?: PackageMeta): TypeSchemaField;
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, register),
178
- excluded: isExcluded(fhirSchema, path, register),
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
- return (element.type === "BackboneElement" || (element.elements && Object.keys(element.elements).length > 0) || false);
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, manager, _packageInfo) {
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, manager),
211
- excluded: isExcluded(fhirSchema, path, manager),
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, packageInfo?: PackageMeta): BindingIdentifier;
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, packageInfo) {
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 { Identifier, PackageMeta, RichFHIRSchema, TypeSchemaField, TypeSchemaNestedType } from "../types";
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, TypeSchemaField>>;
14
- /**
15
- * Build TypeSchema for all nested types in a FHIRSchema
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, register, packageInfo);
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: packageInfo?.name || "hl7.fhir.r4.core",
61
- version: packageInfo?.version || "4.0.1",
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: packageInfo?.name || "hl7.fhir.r4.core",
71
- version: packageInfo?.version || "4.0.1",
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, packageInfo);
68
+ const fields = await transformNestedElements(fhirSchema, path, element.elements, register, fhirSchema.package_meta);
78
69
  const nestedType = {
79
70
  identifier,
80
- base, // Always include 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 { 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>;
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, getElementHierarchy, isNestedElement, mergeElementHierarchy, mkNestedField, } from "./field-builder";
9
+ import { buildField, isNestedElement, mkNestedField } from "./field-builder";
9
10
  import { mkIdentifier } from "./identifier";
10
- import { buildNestedTypes, extractNestedDependencies } from "./nested-types";
11
- export async function transformElements(register, fhirSchema, parentPath, elements) {
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, element] of Object.entries(elements)) {
17
+ for (const [key, _element] of Object.entries(elements)) {
16
18
  const path = [...parentPath, key];
17
- const hierarchy = getElementHierarchy(fhirSchema, path, register);
18
- const snapshot = hierarchy.length > 0 ? mergeElementHierarchy(hierarchy) : element;
19
- if (isNestedElement(snapshot)) {
20
- fields[key] = mkNestedField(fhirSchema, path, snapshot, register, fhirSchema.package_meta);
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, snapshot, register, fhirSchema.package_meta);
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, packageInfo) {
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 transformElements(register, fhirSchema, [], fhirSchema.elements);
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 buildNestedTypes(fhirSchema, register, packageInfo);
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 result = Object.values(uniqDeps).sort((a, b) => a.name.localeCompare(b.name));
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 transformElements(register, fhirSchema, [], fhirSchema.elements);
207
- const nested = await buildNestedTypes(fhirSchema, register, fhirSchema.package_meta);
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 { transformElements } from "../core/transformer";
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 packageInfo = fhirSchema.package_meta;
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 transformElements(register, fhirSchema, [], fhirSchema.elements);
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, manager) {
82
+ async function determineBaseKind(baseUrl, register) {
83
83
  try {
84
84
  // Try to resolve the base schema
85
- const baseSchema = await manager.resolve(baseUrl);
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[] | undefined;
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 (!fs)
44
- return undefined;
43
+ if (fs === undefined)
44
+ throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
45
45
  const genealogy = [fs];
46
- while (fs && fs.base) {
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
- return genealogy.reverse().reduce((snapshot, elem) => ({ ...snapshot, ...elem }), {});
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, TypeSchemaField>;
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, TypeSchemaField>;
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]: RegularField | PolymorphicValueXFieldDeclaration | PolymorphicValueXFieldInstance;
129
+ [k: string]: Field;
137
130
  };
138
- nested?: TypeSchemaNestedType[];
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 PolymorphicValueXFieldDeclaration {
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 PolymorphicValueXFieldInstance {
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 TypeSchemaField = RegularField | PolymorphicValueXFieldDeclaration | PolymorphicValueXFieldInstance;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomic-ehr/codegen",
3
- "version": "0.0.1-canary.20250930151649.b68ce8a",
3
+ "version": "0.0.1-canary.20251001124254.ddbda7d",
4
4
  "description": "Code generation tools for FHIR resources and TypeSchema definitions",
5
5
  "keywords": [
6
6
  "fhir",