@atomic-ehr/codegen 0.0.1-canary.20251001075906.44a8bb9 → 0.0.1-canary.20251001154933.613f6c7

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.
@@ -3,23 +3,23 @@
3
3
  *
4
4
  * Functions for processing value set bindings and generating enums
5
5
  */
6
- import type { CanonicalManager } from "@atomic-ehr/fhir-canonical-manager";
7
6
  import type { FHIRSchemaElement } from "@atomic-ehr/fhirschema";
8
- import type { PackageMeta, RichFHIRSchema, TypeSchemaForBinding } from "../types";
7
+ import type { Register } from "@typeschema/register";
8
+ import type { CanonicalUrl, PackageMeta, RichFHIRSchema, TypeSchemaForBinding } from "@typeschema/types";
9
9
  /**
10
10
  * Extract concepts from a ValueSet
11
11
  */
12
- export declare function extractValueSetConcepts(valueSetUrl: string, manager: ReturnType<typeof CanonicalManager>): Promise<Array<{
12
+ export declare function extractValueSetConcepts(valueSetUrl: CanonicalUrl, register: Register): {
13
13
  system: string;
14
14
  code: string;
15
15
  display?: string;
16
- }> | undefined>;
16
+ }[] | undefined;
17
17
  /**
18
18
  * Build enum values from binding if applicable
19
19
  */
20
- export declare function buildEnum(element: FHIRSchemaElement, manager: ReturnType<typeof CanonicalManager>): Promise<string[] | undefined>;
21
- export declare function generateBindingSchema(fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement, manager: ReturnType<typeof CanonicalManager>, packageInfo?: PackageMeta): Promise<TypeSchemaForBinding | undefined>;
20
+ export declare function buildEnum(element: FHIRSchemaElement, register: Register): string[] | undefined;
21
+ export declare function generateBindingSchema(fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement, register: Register, packageInfo?: PackageMeta): Promise<TypeSchemaForBinding | undefined>;
22
22
  /**
23
23
  * Collect all binding schemas from a FHIRSchema
24
24
  */
25
- export declare function collectBindingSchemas(fhirSchema: RichFHIRSchema, manager: ReturnType<typeof CanonicalManager>): Promise<TypeSchemaForBinding[]>;
25
+ export declare function collectBindingSchemas(fhirSchema: RichFHIRSchema, register: Register): Promise<TypeSchemaForBinding[]>;
@@ -8,10 +8,10 @@ import { dropVersionFromUrl, mkBindingIdentifier, mkValueSetIdentifier } from ".
8
8
  /**
9
9
  * Extract concepts from a ValueSet
10
10
  */
11
- export async function extractValueSetConcepts(valueSetUrl, manager) {
11
+ export function extractValueSetConcepts(valueSetUrl, register) {
12
12
  try {
13
13
  const cleanUrl = dropVersionFromUrl(valueSetUrl) || valueSetUrl;
14
- const valueSet = await manager.resolve(cleanUrl);
14
+ const valueSet = register.resolveVs(cleanUrl);
15
15
  if (!valueSet)
16
16
  return undefined;
17
17
  // If expansion is available, use it
@@ -39,7 +39,7 @@ export async function extractValueSetConcepts(valueSetUrl, manager) {
39
39
  else if (include.system && !include.filter) {
40
40
  // Include all from CodeSystem
41
41
  try {
42
- const codeSystem = await manager.resolve(include.system);
42
+ const codeSystem = register.resolveAny(include.system);
43
43
  if (codeSystem?.concept) {
44
44
  const extractConcepts = (conceptList, system) => {
45
45
  for (const concept of conceptList) {
@@ -72,7 +72,7 @@ export async function extractValueSetConcepts(valueSetUrl, manager) {
72
72
  /**
73
73
  * Build enum values from binding if applicable
74
74
  */
75
- export async function buildEnum(element, manager) {
75
+ export function buildEnum(element, register) {
76
76
  if (!element.binding)
77
77
  return undefined;
78
78
  const { strength, valueSet } = element.binding;
@@ -90,12 +90,8 @@ export async function buildEnum(element, manager) {
90
90
  if (!shouldGenerateEnum) {
91
91
  return undefined;
92
92
  }
93
- // Check if manager is available and functional
94
- if (!manager.resolve) {
95
- return undefined;
96
- }
97
93
  try {
98
- const concepts = await extractValueSetConcepts(valueSet, manager);
94
+ const concepts = extractValueSetConcepts(valueSet, register);
99
95
  if (!concepts || concepts.length === 0)
100
96
  return undefined;
101
97
  // Extract just the codes and filter out any empty/invalid ones
@@ -112,18 +108,18 @@ export async function buildEnum(element, manager) {
112
108
  return undefined;
113
109
  }
114
110
  }
115
- export async function generateBindingSchema(fhirSchema, path, element, manager, packageInfo) {
111
+ export async function generateBindingSchema(fhirSchema, path, element, register, packageInfo) {
116
112
  if (!element.binding?.valueSet)
117
113
  return undefined;
118
114
  const identifier = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName, packageInfo);
119
- const fieldType = buildFieldType(fhirSchema, path, element, manager, packageInfo);
115
+ const fieldType = buildFieldType(fhirSchema, path, element, register, packageInfo);
120
116
  const valueSetIdentifier = mkValueSetIdentifier(element.binding.valueSet, undefined, packageInfo);
121
117
  const dependencies = [];
122
118
  if (fieldType) {
123
119
  dependencies.push(fieldType);
124
120
  }
125
121
  dependencies.push(valueSetIdentifier);
126
- const enumValues = await buildEnum(element, manager);
122
+ const enumValues = await buildEnum(element, register);
127
123
  return {
128
124
  identifier,
129
125
  type: fieldType,
@@ -136,7 +132,7 @@ export async function generateBindingSchema(fhirSchema, path, element, manager,
136
132
  /**
137
133
  * Collect all binding schemas from a FHIRSchema
138
134
  */
139
- export async function collectBindingSchemas(fhirSchema, manager) {
135
+ export async function collectBindingSchemas(fhirSchema, register) {
140
136
  const packageInfo = fhirSchema.package_meta;
141
137
  const bindings = [];
142
138
  const processedPaths = new Set();
@@ -151,7 +147,7 @@ export async function collectBindingSchemas(fhirSchema, manager) {
151
147
  processedPaths.add(pathKey);
152
148
  // Generate binding if present
153
149
  if (element.binding) {
154
- const binding = await generateBindingSchema(fhirSchema, path, element, manager, packageInfo);
150
+ const binding = await generateBindingSchema(fhirSchema, path, element, register, packageInfo);
155
151
  if (binding) {
156
152
  bindings.push(binding);
157
153
  }
@@ -6,20 +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
- export declare function isRequired(fhirSchema: FHIRSchema, path: string[], _manager: ReturnType<typeof CanonicalManager>): boolean;
11
- /**
12
- * Check if a field is excluded
13
- */
14
- 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;
15
12
  export declare const buildReferences: (element: FHIRSchemaElement, register: Register, _packageInfo?: PackageMeta) => Identifier[] | undefined;
16
13
  /**
17
14
  * Build field type identifier
18
15
  */
19
16
  export declare function buildFieldType(fhirSchema: RichFHIRSchema, _path: string[], element: FHIRSchemaElement, _manager: ReturnType<typeof CanonicalManager>, packageInfo?: PackageMeta): Identifier | undefined;
20
- export declare const buildField: (fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement, register: Register, packageInfo?: PackageMeta) => TypeSchemaField;
21
- /**
22
- * Check if an element represents a nested type (BackboneElement)
23
- */
17
+ export declare const mkField: (register: Register, fhirSchema: RichFHIRSchema, path: string[], element: FHIRSchemaElement) => Field;
24
18
  export declare function isNestedElement(element: FHIRSchemaElement): boolean;
25
- 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,7 +5,7 @@
5
5
  */
6
6
  import { buildEnum } from "./binding";
7
7
  import { mkBindingIdentifier, mkIdentifier, mkNestedIdentifier } from "./identifier";
8
- export function isRequired(fhirSchema, path, _manager) {
8
+ export function isRequired(fhirSchema, path) {
9
9
  if (path.length === 0)
10
10
  return false;
11
11
  const fieldName = path[path.length - 1];
@@ -27,10 +27,7 @@ export function isRequired(fhirSchema, path, _manager) {
27
27
  }
28
28
  return false;
29
29
  }
30
- /**
31
- * Check if a field is excluded
32
- */
33
- export function isExcluded(fhirSchema, path, _manager) {
30
+ export function isExcluded(fhirSchema, path) {
34
31
  if (path.length === 0)
35
32
  return false;
36
33
  const fieldName = path[path.length - 1];
@@ -94,51 +91,47 @@ export function buildFieldType(fhirSchema, _path, element, _manager, packageInfo
94
91
  }
95
92
  return undefined;
96
93
  }
97
- export const buildField = (fhirSchema, path, element, register, packageInfo) => {
94
+ export const mkField = (register, fhirSchema, path, element) => {
98
95
  let binding;
99
- let _enumValues;
96
+ let enumValues;
100
97
  if (element.binding) {
101
- binding = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName, packageInfo);
98
+ binding = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName, fhirSchema.package_meta);
102
99
  if (element.binding.strength === "required" && element.type === "code") {
103
- _enumValues = buildEnum(element, register);
100
+ enumValues = buildEnum(element, register);
104
101
  }
105
102
  }
106
103
  return {
107
- type: buildFieldType(fhirSchema, path, element, register, packageInfo),
108
- required: isRequired(fhirSchema, path, register),
109
- excluded: isExcluded(fhirSchema, path, register),
110
- reference: buildReferences(element, register, packageInfo),
104
+ type: buildFieldType(fhirSchema, path, element, register, fhirSchema.package_meta),
105
+ required: isRequired(fhirSchema, path),
106
+ excluded: isExcluded(fhirSchema, path),
107
+ reference: buildReferences(element, register, fhirSchema.package_meta),
111
108
  array: element.array || false,
112
109
  min: element.min,
113
110
  max: element.max,
114
111
  choices: element.choices,
115
112
  choiceOf: element.choiceOf,
116
113
  binding: binding,
114
+ enum: enumValues,
117
115
  };
118
116
  };
119
- function _removeEmptyValues(obj) {
120
- const result = {};
121
- for (const [key, value] of Object.entries(obj)) {
122
- if (value !== undefined && value !== null) {
123
- if (Array.isArray(value) && value.length === 0) {
124
- continue;
125
- }
126
- result[key] = value;
127
- }
128
- }
129
- return result;
130
- }
131
- /**
132
- * Check if an element represents a nested type (BackboneElement)
133
- */
134
117
  export function isNestedElement(element) {
135
- return (element.type === "BackboneElement" || (element.elements && Object.keys(element.elements).length > 0) || false);
118
+ const isBackbone = element.type === "BackboneElement";
119
+ const isElement = element.type === "Element" && element.elements !== undefined && Object.keys(element.elements).length > 0;
120
+ // TODO: Observation <- vitalsigns <- bodyweight
121
+ // In Observation we have value[x] with choices
122
+ // In bodyweight we have valueQuantity with additional constaraints on it's elements
123
+ // So we need to build nested type from Quantity for here, but don't do that right now.
124
+ const elementsWithoutType = element.type === undefined &&
125
+ element.choiceOf === undefined &&
126
+ element.elements !== undefined &&
127
+ Object.keys(element.elements).length > 0;
128
+ return isBackbone || isElement || elementsWithoutType;
136
129
  }
137
- export function mkNestedField(fhirSchema, path, element, manager, _packageInfo) {
130
+ export function mkNestedField(_register, fhirSchema, path, element) {
138
131
  return {
139
132
  type: mkNestedIdentifier(fhirSchema, path),
140
133
  array: element.array || false,
141
- required: isRequired(fhirSchema, path, manager),
142
- excluded: isExcluded(fhirSchema, path, manager),
134
+ required: isRequired(fhirSchema, path),
135
+ excluded: isExcluded(fhirSchema, path),
143
136
  };
144
137
  }
@@ -4,9 +4,9 @@
4
4
  * Functions for creating TypeSchema identifiers from FHIRSchema entities
5
5
  */
6
6
  import type { FHIRSchema } from "@atomic-ehr/fhirschema";
7
- import type { BindingIdentifier, Identifier, NestedIdentifier, PackageMeta, RichFHIRSchema, TypeSchemaForValueSet } from "@typeschema/types";
8
- export declare function dropVersionFromUrl(url: string | undefined): string | undefined;
7
+ import type { BindingIdentifier, CanonicalUrl, Identifier, NestedIdentifier, PackageMeta, RichFHIRSchema, TypeSchemaForValueSet } from "@typeschema/types";
8
+ export declare function dropVersionFromUrl(url: CanonicalUrl | undefined): CanonicalUrl | undefined;
9
9
  export declare function mkIdentifier(fhirSchema: RichFHIRSchema): Identifier;
10
10
  export declare function mkNestedIdentifier(fhirSchema: RichFHIRSchema, path: string[]): NestedIdentifier;
11
- export declare function mkValueSetIdentifier(valueSetUrl: string, valueSet: any, packageInfo?: PackageMeta): TypeSchemaForValueSet["identifier"];
11
+ export declare function mkValueSetIdentifier(valueSetUrl: CanonicalUrl, valueSet: any, packageInfo?: PackageMeta): TypeSchemaForValueSet["identifier"];
12
12
  export declare function mkBindingIdentifier(fhirSchema: FHIRSchema, path: string[], bindingName?: string, _packageInfo?: PackageMeta): BindingIdentifier;
@@ -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[];
@@ -3,51 +3,40 @@
3
3
  *
4
4
  * Functions for extracting and transforming nested types from FHIRSchema
5
5
  */
6
- import { buildField, isNestedElement, mkNestedField } from "./field-builder";
6
+ import { isNestedElement, mkField, 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
  }
23
18
  }
24
19
  return nested;
25
20
  }
26
- export async function transformNestedElements(fhirSchema, parentPath, elements, register, packageInfo) {
21
+ export async function transformNestedElements(fhirSchema, parentPath, elements, register, _packageInfo) {
27
22
  const fields = {};
28
23
  for (const [key, element] of Object.entries(elements)) {
29
24
  const path = [...parentPath, key];
30
25
  if (isNestedElement(element)) {
31
- // Reference to another nested type
32
- fields[key] = mkNestedField(fhirSchema, path, element, register, packageInfo);
26
+ fields[key] = mkNestedField(register, fhirSchema, path, element);
33
27
  }
34
28
  else {
35
- // Regular field
36
- fields[key] = await buildField(fhirSchema, path, element, register, packageInfo);
29
+ fields[key] = mkField(register, fhirSchema, path, element);
37
30
  }
38
31
  }
39
32
  return fields;
40
33
  }
41
- /**
42
- * Build TypeSchema for all nested types in a FHIRSchema
43
- */
44
- export async function buildNestedTypes(fhirSchema, register, packageInfo) {
34
+ export async function mkNestedTypes(register, fhirSchema) {
45
35
  if (!fhirSchema.elements)
46
36
  return undefined;
47
- const nestedTypes = [];
48
37
  const nestedElements = collectNestedElements(fhirSchema, [], fhirSchema.elements);
49
- // Filter to only include elements that have sub-elements (actual nested types)
50
38
  const actualNested = nestedElements.filter(([_, element]) => element.elements && Object.keys(element.elements).length > 0);
39
+ const nestedTypes = [];
51
40
  for (const [path, element] of actualNested) {
52
41
  const identifier = mkNestedIdentifier(fhirSchema, path);
53
42
  // Base is usually BackboneElement - ensure all nested types have a base
@@ -57,8 +46,8 @@ export async function buildNestedTypes(fhirSchema, register, packageInfo) {
57
46
  // For BackboneElement or undefined type, always use BackboneElement as base
58
47
  base = {
59
48
  kind: "complex-type",
60
- package: packageInfo?.name || "hl7.fhir.r4.core",
61
- version: packageInfo?.version || "4.0.1",
49
+ package: fhirSchema.package_meta.name,
50
+ version: fhirSchema.package_meta.version,
62
51
  name: "BackboneElement",
63
52
  url: "http://hl7.org/fhir/StructureDefinition/BackboneElement",
64
53
  };
@@ -67,38 +56,31 @@ export async function buildNestedTypes(fhirSchema, register, packageInfo) {
67
56
  // Use the specified type as base
68
57
  base = {
69
58
  kind: "complex-type",
70
- package: packageInfo?.name || "hl7.fhir.r4.core",
71
- version: packageInfo?.version || "4.0.1",
59
+ package: fhirSchema.package_meta.name,
60
+ version: fhirSchema.package_meta.version,
72
61
  name: element.type,
73
62
  url: `http://hl7.org/fhir/StructureDefinition/${element.type}`,
74
63
  };
75
64
  }
76
65
  // Transform sub-elements into fields
77
- const fields = await transformNestedElements(fhirSchema, path, element.elements, register, packageInfo);
66
+ const fields = await transformNestedElements(fhirSchema, path, element.elements, register, fhirSchema.package_meta);
78
67
  const nestedType = {
79
68
  identifier,
80
- base, // Always include base
69
+ base,
81
70
  fields,
82
71
  };
83
72
  nestedTypes.push(nestedType);
84
73
  }
85
74
  // Sort by URL for consistent output
86
75
  nestedTypes.sort((a, b) => a.identifier.url.localeCompare(b.identifier.url));
87
- return nestedTypes;
76
+ return nestedTypes.length === 0 ? undefined : nestedTypes;
88
77
  }
89
- /**
90
- * Extract dependencies from nested types
91
- */
92
78
  export function extractNestedDependencies(nestedTypes) {
93
79
  const deps = [];
94
80
  for (const nested of nestedTypes) {
95
- // Add the nested type itself as a dependency
96
- deps.push(nested.identifier);
97
- // Add base dependency
98
81
  if (nested.base) {
99
82
  deps.push(nested.base);
100
83
  }
101
- // Add field type dependencies
102
84
  for (const field of Object.values(nested.fields || {})) {
103
85
  if ("type" in field && field.type) {
104
86
  deps.push(field.type);
@@ -5,6 +5,6 @@
5
5
  */
6
6
  import type { FHIRSchemaElement } from "@atomic-ehr/fhirschema";
7
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>;
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[]>;
@@ -6,23 +6,37 @@
6
6
  import { fsElementSnapshot, resolveFsElementGenealogy } from "@typeschema/register";
7
7
  import { transformProfile } from "../profile/processor";
8
8
  import { collectBindingSchemas } from "./binding";
9
- import { buildField, isNestedElement, mkNestedField } from "./field-builder";
9
+ import { isNestedElement, mkField, mkNestedField } from "./field-builder";
10
10
  import { mkIdentifier } from "./identifier";
11
- import { buildNestedTypes, extractNestedDependencies } from "./nested-types";
12
- export async function transformElements(register, fhirSchema, parentPath, elements) {
11
+ import { extractNestedDependencies, mkNestedTypes } from "./nested-types";
12
+ export async function mkFields(register, fhirSchema, parentPath, elements) {
13
13
  if (!elements)
14
14
  return undefined;
15
15
  const geneology = register.resolveFsGenealogy(fhirSchema.url);
16
- const fields = {};
17
- for (const [key, _element] of Object.entries(elements)) {
16
+ const elems = {};
17
+ for (const [key, elem] of Object.entries(elements)) {
18
18
  const path = [...parentPath, key];
19
19
  const elemGeneology = resolveFsElementGenealogy(geneology, path);
20
- const snapshot = fsElementSnapshot(elemGeneology);
21
- if (isNestedElement(snapshot)) {
22
- fields[key] = mkNestedField(fhirSchema, path, snapshot, register, fhirSchema.package_meta);
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);
23
37
  }
24
38
  else {
25
- fields[key] = buildField(fhirSchema, path, snapshot, register, fhirSchema.package_meta);
39
+ fields[key] = mkField(register, fhirSchema, path, elemSnapshot);
26
40
  }
27
41
  }
28
42
  return fields;
@@ -115,7 +129,7 @@ async function transformValueSet(fhirSchema, _register, _packageInfo) {
115
129
  /**
116
130
  * Transform an Extension FHIRSchema to TypeSchema with extension metadata
117
131
  */
118
- async function transformExtension(fhirSchema, register, packageInfo) {
132
+ async function transformExtension(fhirSchema, register, _packageInfo) {
119
133
  try {
120
134
  const identifier = mkIdentifier(fhirSchema);
121
135
  // Build base identifier if present
@@ -158,14 +172,14 @@ async function transformExtension(fhirSchema, register, packageInfo) {
158
172
  }
159
173
  // Transform elements into fields if present
160
174
  if (fhirSchema.elements) {
161
- const fields = await transformElements(register, fhirSchema, [], fhirSchema.elements);
175
+ const fields = await mkFields(register, fhirSchema, [], fhirSchema.elements);
162
176
  if (fields && Object.keys(fields).length > 0) {
163
177
  extensionSchema.fields = fields;
164
178
  extensionSchema.dependencies.push(...extractFieldDependencies(fields));
165
179
  }
166
180
  }
167
181
  // Build nested types
168
- const nestedTypes = await buildNestedTypes(fhirSchema, register, packageInfo);
182
+ const nestedTypes = await mkNestedTypes(register, fhirSchema);
169
183
  if (nestedTypes && nestedTypes.length > 0) {
170
184
  extensionSchema.nested = nestedTypes;
171
185
  extensionSchema.dependencies.push(...extractNestedDependencies(nestedTypes));
@@ -195,7 +209,10 @@ function extractDependencies(identifier, base, fields, nestedTypes) {
195
209
  continue;
196
210
  uniqDeps[dep.url] = dep;
197
211
  }
198
- const result = Object.values(uniqDeps).sort((a, b) => a.name.localeCompare(b.name));
212
+ const localNestedTypeUrls = new Set(nestedTypes?.map((nt) => nt.identifier.url));
213
+ const result = Object.values(uniqDeps)
214
+ .filter((e) => !(e.kind === "nested" && localNestedTypeUrls.has(e.url)))
215
+ .sort((a, b) => a.name.localeCompare(b.name));
199
216
  return result.length > 0 ? result : undefined;
200
217
  }
201
218
  async function transformResource(register, fhirSchema) {
@@ -203,10 +220,13 @@ async function transformResource(register, fhirSchema) {
203
220
  let base;
204
221
  if (fhirSchema.base && fhirSchema.type !== "Element") {
205
222
  const baseFs = register.resolveFs(register.ensureCanonicalUrl(fhirSchema.base));
223
+ if (!baseFs) {
224
+ throw new Error(`Base resource not found '${fhirSchema.base}' for '${fhirSchema.url}'`);
225
+ }
206
226
  base = mkIdentifier(baseFs);
207
227
  }
208
- const fields = await transformElements(register, fhirSchema, [], fhirSchema.elements);
209
- const nested = await buildNestedTypes(fhirSchema, register, fhirSchema.package_meta);
228
+ const fields = await mkFields(register, fhirSchema, [], fhirSchema.elements);
229
+ const nested = await mkNestedTypes(register, fhirSchema);
210
230
  const dependencies = extractDependencies(identifier, base, fields, nested);
211
231
  const typeSchema = {
212
232
  identifier,
@@ -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
@@ -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") {
@@ -11,7 +11,9 @@ export type Register = {
11
11
  allSd(): StructureDefinition[];
12
12
  allFs(): RichFHIRSchema[];
13
13
  allVs(): any[];
14
+ resolveVs(canonicalUrl: CanonicalUrl): any | undefined;
14
15
  complexTypeDict(): Record<string, RichFHIRSchema>;
16
+ resolveAny(canonicalUrl: CanonicalUrl): any | undefined;
15
17
  } & ReturnType<typeof CanonicalManager>;
16
18
  export declare const registerFromManager: (manager: ReturnType<typeof CanonicalManager>, logger?: CodegenLogger, packageInfo?: PackageMeta) => Promise<Register>;
17
19
  export declare const registerFromPackageMetas: (packageMetas: PackageMeta[], logger?: CodegenLogger) => Promise<Register>;
@@ -3,6 +3,13 @@ import * as fhirschema from "@atomic-ehr/fhirschema";
3
3
  import { enrichFHIRSchema } from "@typeschema/types";
4
4
  export const registerFromManager = async (manager, logger, packageInfo) => {
5
5
  const resources = await manager.search({});
6
+ const any = {};
7
+ for (const resource of resources) {
8
+ const url = resource.url;
9
+ if (!url)
10
+ continue;
11
+ any[url] = resource;
12
+ }
6
13
  const structureDefinitions = {};
7
14
  for (const resource of resources) {
8
15
  if (resource.resourceType === "StructureDefinition") {
@@ -41,14 +48,13 @@ export const registerFromManager = async (manager, logger, packageInfo) => {
41
48
  const resolveFsGenealogy = (canonicalUrl) => {
42
49
  let fs = fhirSchemas[canonicalUrl];
43
50
  if (fs === undefined)
44
- throw new Error(`Failed to resolve FHIR Schema genealogy for ${canonicalUrl}`);
51
+ throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
45
52
  const genealogy = [fs];
46
53
  while (fs?.base) {
47
- console.log(1, fs.base);
48
54
  fs = fhirSchemas[fs.base] || fhirSchemas[nameDict[fs.base]];
49
55
  genealogy.push(fs);
50
56
  if (fs === undefined)
51
- throw new Error(`Failed to resolve FHIR Schema genealogy for ${canonicalUrl}`);
57
+ throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
52
58
  }
53
59
  return genealogy;
54
60
  };
@@ -57,6 +63,7 @@ export const registerFromManager = async (manager, logger, packageInfo) => {
57
63
  appendFs(fs) {
58
64
  const rfs = enrichFHIRSchema(fs);
59
65
  fhirSchemas[rfs.url] = rfs;
66
+ nameDict[rfs.name] = rfs.url;
60
67
  },
61
68
  resolveFs: (canonicalUrl) => fhirSchemas[canonicalUrl],
62
69
  resolveFsGenealogy: resolveFsGenealogy,
@@ -65,7 +72,9 @@ export const registerFromManager = async (manager, logger, packageInfo) => {
65
72
  resolveSd: (canonicalUrl) => structureDefinitions[canonicalUrl],
66
73
  allFs: () => Object.values(fhirSchemas),
67
74
  allVs: () => Object.values(valueSets),
75
+ resolveVs: (canonicalUrl) => valueSets[canonicalUrl],
68
76
  complexTypeDict: () => complexTypes,
77
+ resolveAny: (canonicalUrl) => any[canonicalUrl],
69
78
  };
70
79
  };
71
80
  export const registerFromPackageMetas = async (packageMetas, logger) => {
@@ -97,5 +106,8 @@ export const resolveFsElementGenealogy = (genealogy, path) => {
97
106
  };
98
107
  export function fsElementSnapshot(genealogy) {
99
108
  // FIXME: nested elements will break it
100
- return genealogy.reverse().reduce((snapshot, elem) => ({ ...snapshot, ...elem }), {});
109
+ const snapshot = genealogy.reverse().reduce((snapshot, elem) => ({ ...snapshot, ...elem }), {});
110
+ // NOTE: to avoid regeneration nested types
111
+ snapshot.elements = undefined;
112
+ return snapshot;
101
113
  }