@atomic-ehr/codegen 0.0.6 → 0.0.7-canary.20260213165156.a064b6a

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/index.js CHANGED
@@ -7,6 +7,7 @@ import Path5__default from 'path';
7
7
  import { CanonicalManager } from '@atomic-ehr/fhir-canonical-manager';
8
8
  import { fileURLToPath } from 'url';
9
9
  import * as fsPromises from 'fs/promises';
10
+ import { createHash } from 'crypto';
10
11
  import * as YAML from 'yaml';
11
12
  import YAML__default from 'yaml';
12
13
  import * as fhirschema from '@atomic-ehr/fhirschema';
@@ -106,7 +107,7 @@ var CodegenLogger = class _CodegenLogger {
106
107
  warn(message) {
107
108
  this.tryWriteToConsole(2 /* WARN */, this.formatMessage("!", message, pc.yellow));
108
109
  }
109
- dry_warn(message) {
110
+ dryWarn(message) {
110
111
  if (!this.dryWarnSet.has(message)) {
111
112
  this.warn(message);
112
113
  this.dryWarnSet.add(message);
@@ -258,6 +259,10 @@ var FileSystemWriter = class {
258
259
  if (this.currentFile) throw new Error("Can't open file when another file is open");
259
260
  if (fn.includes("/")) throw new Error(`Change file path separatly: ${fn}`);
260
261
  const relPath = Path5.normalize(`${this.currentDir}/${fn}`);
262
+ if (this.writtenFilesBuffer[relPath]) {
263
+ this.logger()?.warn(`File will be rewritten '${relPath}'`);
264
+ this.logger()?.debug(`File content: ${this.writtenFilesBuffer[relPath].tokens.join("")}`);
265
+ }
261
266
  try {
262
267
  const descriptor = this.onDiskOpenFile(relPath);
263
268
  this.logger()?.debug(`cat > '${relPath}'`);
@@ -402,8 +407,6 @@ var Writer = class extends FileSystemWriter {
402
407
  this.line(`]${endTokens?.filter(Boolean).join(" ") ?? ""}`);
403
408
  }
404
409
  };
405
-
406
- // src/typeschema/types.ts
407
410
  var extractNameFromCanonical = (canonical, dropFragment = true) => {
408
411
  let localName = canonical.split("/").pop();
409
412
  if (!localName) return void 0;
@@ -424,10 +427,11 @@ var packageMeta = (schema) => {
424
427
  };
425
428
  var packageMetaToFhir = (packageMeta2) => `${packageMeta2.name}#${packageMeta2.version}`;
426
429
  var packageMetaToNpm = (packageMeta2) => `${packageMeta2.name}@${packageMeta2.version}`;
430
+ var hashSchema = (schema) => {
431
+ const json = JSON.stringify(schema);
432
+ return createHash("sha256").update(json).digest("hex").slice(0, 16);
433
+ };
427
434
  var enrichFHIRSchema = (schema, packageMeta2) => {
428
- if (!packageMeta2) {
429
- packageMeta2 = { name: "undefined", version: "undefined" };
430
- }
431
435
  return {
432
436
  ...schema,
433
437
  package_meta: schema.package_meta || packageMeta2,
@@ -681,7 +685,7 @@ var CSharp = class extends Writer {
681
685
  }
682
686
  determineFieldType(fieldName, field, packageName) {
683
687
  let typeName = this.getBaseTypeName(field);
684
- if ("enum" in field && field.enum) {
688
+ if ("enum" in field && field.enum && !field.enum.isOpen) {
685
689
  typeName = this.registerAndGetEnumType(fieldName, field, packageName);
686
690
  }
687
691
  typeName = prefixReservedTypeName(typeName);
@@ -704,7 +708,7 @@ var CSharp = class extends Writer {
704
708
  const enumName = formatName(field.binding?.name ?? fieldName);
705
709
  const enumTypeName = `${enumName}Enum`;
706
710
  if (!this.enums[packageName]) this.enums[packageName] = {};
707
- if (field.enum) this.enums[packageName][enumTypeName] = field.enum;
711
+ if (field.enum) this.enums[packageName][enumTypeName] = field.enum.values;
708
712
  return enumTypeName;
709
713
  }
710
714
  includeHelperMethods() {
@@ -1480,8 +1484,8 @@ var Python = class extends Writer {
1480
1484
  }
1481
1485
  determineFieldType(field) {
1482
1486
  let fieldType = field ? this.getBaseFieldType(field) : "";
1483
- if ("enum" in field && field.enum) {
1484
- const s = field.enum.map((e) => `"${e}"`).join(", ");
1487
+ if ("enum" in field && field.enum && !field.enum.isOpen) {
1488
+ const s = field.enum.values.map((e) => `"${e}"`).join(", ");
1485
1489
  fieldType = `Literal[${s}]`;
1486
1490
  }
1487
1491
  if (field.array) {
@@ -1758,7 +1762,8 @@ function mkValueSetIdentifierByUrl(register, pkg, fullValueSetUrl) {
1758
1762
  url: valueSetUrl
1759
1763
  };
1760
1764
  }
1761
- function mkBindingIdentifier(fhirSchema, path, bindingName) {
1765
+ function mkBindingIdentifier(fhirSchema, path, element) {
1766
+ const bindingName = element.binding?.bindingName;
1762
1767
  const pathStr = path.join(".");
1763
1768
  const [pkg, name, url] = bindingName ? [{ name: "shared", version: "1.0.0" }, bindingName, `urn:fhir:binding:${bindingName}`] : [fhirSchema.package_meta, `${fhirSchema.name}.${pathStr}_binding`, `${fhirSchema.url}#${pathStr}_binding`];
1764
1769
  return {
@@ -1770,6 +1775,146 @@ function mkBindingIdentifier(fhirSchema, path, bindingName) {
1770
1775
  };
1771
1776
  }
1772
1777
 
1778
+ // src/typeschema/core/binding.ts
1779
+ function extractValueSetConceptsByUrl(register, pkg, valueSetUrl, logger) {
1780
+ const cleanUrl = dropVersionFromUrl(valueSetUrl) || valueSetUrl;
1781
+ const valueSet = register.resolveVs(pkg, cleanUrl);
1782
+ if (!valueSet) return void 0;
1783
+ return extractValueSetConcepts(register, valueSet);
1784
+ }
1785
+ function extractValueSetConcepts(register, valueSet, _logger) {
1786
+ if (valueSet.expansion?.contains) {
1787
+ return valueSet.expansion.contains.filter((item) => item.code !== void 0).map((item) => {
1788
+ assert3(item.code);
1789
+ return {
1790
+ code: item.code,
1791
+ display: item.display,
1792
+ system: item.system
1793
+ };
1794
+ });
1795
+ }
1796
+ const concepts = [];
1797
+ if (valueSet.compose?.include) {
1798
+ for (const include of valueSet.compose.include) {
1799
+ if (include.concept) {
1800
+ for (const concept of include.concept) {
1801
+ concepts.push({
1802
+ system: include.system,
1803
+ code: concept.code,
1804
+ display: concept.display
1805
+ });
1806
+ }
1807
+ } else if (include.system && !include.filter) {
1808
+ try {
1809
+ const codeSystem = register.resolveAny(include.system);
1810
+ if (codeSystem?.concept) {
1811
+ const extractConcepts = (conceptList, system) => {
1812
+ for (const concept of conceptList) {
1813
+ concepts.push({
1814
+ system,
1815
+ code: concept.code,
1816
+ display: concept.display
1817
+ });
1818
+ if (concept.concept) {
1819
+ extractConcepts(concept.concept, system);
1820
+ }
1821
+ }
1822
+ };
1823
+ extractConcepts(codeSystem.concept, include.system);
1824
+ }
1825
+ } catch {
1826
+ }
1827
+ }
1828
+ }
1829
+ }
1830
+ return concepts.length > 0 ? concepts : void 0;
1831
+ }
1832
+ var MAX_ENUM_LENGTH = 100;
1833
+ var BINDABLE_TYPES = /* @__PURE__ */ new Set([
1834
+ "code",
1835
+ "Coding",
1836
+ "CodeableConcept",
1837
+ "CodeableReference",
1838
+ "Quantity",
1839
+ "string",
1840
+ "uri",
1841
+ "Duration"
1842
+ ]);
1843
+ function buildEnum(register, fhirSchema, element, logger) {
1844
+ if (!element.binding) return void 0;
1845
+ const strength = element.binding.strength;
1846
+ const valueSetUrl = element.binding.valueSet;
1847
+ if (!valueSetUrl) return void 0;
1848
+ if (!BINDABLE_TYPES.has(element.type ?? "")) {
1849
+ logger?.dryWarn(`eld-11: Binding on non-bindable type '${element.type}' (valueSet: ${valueSetUrl})`);
1850
+ return void 0;
1851
+ }
1852
+ const shouldGenerateEnum = strength === "required" || strength === "extensible" || strength === "preferred";
1853
+ if (!shouldGenerateEnum) return void 0;
1854
+ const concepts = extractValueSetConceptsByUrl(register, fhirSchema.package_meta, valueSetUrl);
1855
+ if (!concepts || concepts.length === 0) return void 0;
1856
+ const codes = concepts.map((c) => c.code).filter((code) => code && typeof code === "string" && code.trim().length > 0);
1857
+ if (codes.length > MAX_ENUM_LENGTH) {
1858
+ logger?.dryWarn(
1859
+ `Value set ${valueSetUrl} has ${codes.length} which is more than ${MAX_ENUM_LENGTH} codes, which may cause issues with code generation.`
1860
+ );
1861
+ return void 0;
1862
+ }
1863
+ if (codes.length === 0) return void 0;
1864
+ return { isOpen: strength !== "required", values: codes };
1865
+ }
1866
+ function generateBindingSchema(register, fhirSchema, path, element, logger) {
1867
+ if (!element.binding?.valueSet) return void 0;
1868
+ const identifier = mkBindingIdentifier(fhirSchema, path, element);
1869
+ const valueSetIdentifier = mkValueSetIdentifierByUrl(
1870
+ register,
1871
+ fhirSchema.package_meta,
1872
+ element.binding.valueSet
1873
+ );
1874
+ const enumResult = buildEnum(register, fhirSchema, element, logger);
1875
+ return {
1876
+ identifier,
1877
+ valueset: valueSetIdentifier,
1878
+ strength: element.binding.strength,
1879
+ enum: enumResult,
1880
+ dependencies: [valueSetIdentifier]
1881
+ };
1882
+ }
1883
+ function collectBindingSchemas(register, fhirSchema, logger) {
1884
+ const processedPaths = /* @__PURE__ */ new Set();
1885
+ if (!fhirSchema.elements) return [];
1886
+ const bindings = [];
1887
+ function collectBindings(elements, parentPath) {
1888
+ for (const [key, element] of Object.entries(elements)) {
1889
+ const path = [...parentPath, key];
1890
+ const pathKey = path.join(".");
1891
+ const elemSnapshot = register.resolveElementSnapshot(fhirSchema, path);
1892
+ if (processedPaths.has(pathKey)) continue;
1893
+ processedPaths.add(pathKey);
1894
+ if (elemSnapshot.binding) {
1895
+ const binding = generateBindingSchema(register, fhirSchema, path, elemSnapshot, logger);
1896
+ if (binding) {
1897
+ bindings.push(binding);
1898
+ }
1899
+ }
1900
+ if (element.elements) {
1901
+ collectBindings(element.elements, path);
1902
+ }
1903
+ }
1904
+ }
1905
+ collectBindings(fhirSchema.elements, []);
1906
+ bindings.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
1907
+ const uniqueBindings = [];
1908
+ const seenUrls = /* @__PURE__ */ new Set();
1909
+ for (const binding of bindings) {
1910
+ if (!seenUrls.has(binding.identifier.url)) {
1911
+ seenUrls.add(binding.identifier.url);
1912
+ uniqueBindings.push(binding);
1913
+ }
1914
+ }
1915
+ return uniqueBindings;
1916
+ }
1917
+
1773
1918
  // src/typeschema/core/nested-types.ts
1774
1919
  function mkNestedIdentifier(register, fhirSchema, path, logger) {
1775
1920
  const nestedTypeOrigins = {};
@@ -1972,24 +2117,24 @@ function buildFieldType(register, fhirSchema, path, element, logger) {
1972
2117
  } else if (fhirSchema.derivation === "constraint") {
1973
2118
  return void 0;
1974
2119
  } else {
1975
- logger?.error(
1976
- `Can't recognize element type: <${fhirSchema.url}>.${path.join(".")} (pkg: '${packageMetaToFhir(fhirSchema.package_meta)}'): ${JSON.stringify(element, void 0, 2)}`
2120
+ logger?.dryWarn(
2121
+ `Can't recognize element type: <${fhirSchema.url}>.${path.join(".")} (pkg: '${packageMetaToFhir(fhirSchema.package_meta)}'): missing type info`
1977
2122
  );
1978
- throw new Error(`Unrecognized element type`);
2123
+ return void 0;
1979
2124
  }
1980
2125
  }
1981
2126
  var mkField = (register, fhirSchema, path, element, logger) => {
1982
2127
  let binding;
1983
- let enumValues;
2128
+ let enumResult;
1984
2129
  if (element.binding) {
1985
- binding = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName);
1986
- if (element.binding.strength === "required" && element.type === "code") {
1987
- enumValues = buildEnum(register, fhirSchema, element, logger);
2130
+ binding = mkBindingIdentifier(fhirSchema, path, element);
2131
+ if (BINDABLE_TYPES.has(element.type ?? "")) {
2132
+ enumResult = buildEnum(register, fhirSchema, element, logger);
1988
2133
  }
1989
2134
  }
1990
2135
  const fieldType = buildFieldType(register, fhirSchema, path, element, logger);
1991
2136
  if (!fieldType)
1992
- logger?.dry_warn(`Field type not found for '${fhirSchema.url}#${path.join(".")}' (${fhirSchema.derivation})`);
2137
+ logger?.dryWarn(`Field type not found for '${fhirSchema.url}#${path.join(".")}' (${fhirSchema.derivation})`);
1993
2138
  return {
1994
2139
  type: fieldType,
1995
2140
  required: isRequired(register, fhirSchema, path),
@@ -2002,13 +2147,18 @@ var mkField = (register, fhirSchema, path, element, logger) => {
2002
2147
  choices: element.choices,
2003
2148
  choiceOf: element.choiceOf,
2004
2149
  binding,
2005
- enum: enumValues
2150
+ enum: enumResult
2006
2151
  };
2007
2152
  };
2008
2153
  function isNestedElement(element) {
2009
2154
  const isBackbone = element.type === "BackboneElement";
2010
2155
  const isElement = element.type === "Element" && element.elements !== void 0 && Object.keys(element.elements).length > 0;
2011
- const elementsWithoutType = element.type === void 0 && element.choiceOf === void 0 && element.elements !== void 0 && Object.keys(element.elements).length > 0;
2156
+ const elementsWithoutType = (
2157
+ // FIXME: understand and make a decision.
2158
+ // Problem example: http://hl7.org/cda/stds/core/StructureDefinition/SubstanceAdministration -> consumable
2159
+ // Don't generate nested type for that field, but defetly expect it.
2160
+ element.type === void 0 && element.choiceOf === void 0 && element.elements !== void 0 && Object.keys(element.elements).length > 0
2161
+ );
2012
2162
  return isBackbone || isElement || elementsWithoutType;
2013
2163
  }
2014
2164
  function mkNestedField(register, fhirSchema, path, element, logger) {
@@ -2022,138 +2172,6 @@ function mkNestedField(register, fhirSchema, path, element, logger) {
2022
2172
  };
2023
2173
  }
2024
2174
 
2025
- // src/typeschema/core/binding.ts
2026
- function extractValueSetConceptsByUrl(register, pkg, valueSetUrl, logger) {
2027
- const cleanUrl = dropVersionFromUrl(valueSetUrl) || valueSetUrl;
2028
- const valueSet = register.resolveVs(pkg, cleanUrl);
2029
- if (!valueSet) return void 0;
2030
- return extractValueSetConcepts(register, valueSet);
2031
- }
2032
- function extractValueSetConcepts(register, valueSet, _logger) {
2033
- if (valueSet.expansion?.contains) {
2034
- return valueSet.expansion.contains.filter((item) => item.code !== void 0).map((item) => {
2035
- assert3(item.code);
2036
- return {
2037
- code: item.code,
2038
- display: item.display,
2039
- system: item.system
2040
- };
2041
- });
2042
- }
2043
- const concepts = [];
2044
- if (valueSet.compose?.include) {
2045
- for (const include of valueSet.compose.include) {
2046
- if (include.concept) {
2047
- for (const concept of include.concept) {
2048
- concepts.push({
2049
- system: include.system,
2050
- code: concept.code,
2051
- display: concept.display
2052
- });
2053
- }
2054
- } else if (include.system && !include.filter) {
2055
- try {
2056
- const codeSystem = register.resolveAny(include.system);
2057
- if (codeSystem?.concept) {
2058
- const extractConcepts = (conceptList, system) => {
2059
- for (const concept of conceptList) {
2060
- concepts.push({
2061
- system,
2062
- code: concept.code,
2063
- display: concept.display
2064
- });
2065
- if (concept.concept) {
2066
- extractConcepts(concept.concept, system);
2067
- }
2068
- }
2069
- };
2070
- extractConcepts(codeSystem.concept, include.system);
2071
- }
2072
- } catch {
2073
- }
2074
- }
2075
- }
2076
- }
2077
- return concepts.length > 0 ? concepts : void 0;
2078
- }
2079
- var MAX_ENUM_LENGTH = 100;
2080
- function buildEnum(register, fhirSchema, element, logger) {
2081
- if (!element.binding) return void 0;
2082
- const strength = element.binding.strength;
2083
- const valueSetUrl = element.binding.valueSet;
2084
- if (!valueSetUrl) return void 0;
2085
- const shouldGenerateEnum = strength === "required" || strength === "extensible" && (element.type === "code" || element.type === "Coding") || strength === "preferred" && (element.type === "code" || element.type === "Coding");
2086
- if (!shouldGenerateEnum) return void 0;
2087
- const concepts = extractValueSetConceptsByUrl(register, fhirSchema.package_meta, valueSetUrl);
2088
- if (!concepts || concepts.length === 0) return void 0;
2089
- const codes = concepts.map((c) => c.code).filter((code) => code && typeof code === "string" && code.trim().length > 0);
2090
- if (codes.length > MAX_ENUM_LENGTH) {
2091
- logger?.dry_warn(
2092
- `Value set ${valueSetUrl} has ${codes.length} which is more than ${MAX_ENUM_LENGTH} codes, which may cause issues with code generation.`
2093
- );
2094
- return void 0;
2095
- }
2096
- return codes.length > 0 ? codes : void 0;
2097
- }
2098
- function generateBindingSchema(register, fhirSchema, path, element, logger) {
2099
- if (!element.binding?.valueSet) return void 0;
2100
- const identifier = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName);
2101
- const fieldType = buildFieldType(register, fhirSchema, path, element, logger);
2102
- const valueSetIdentifier = mkValueSetIdentifierByUrl(
2103
- register,
2104
- fhirSchema.package_meta,
2105
- element.binding.valueSet
2106
- );
2107
- const dependencies = [];
2108
- if (fieldType) {
2109
- dependencies.push(fieldType);
2110
- }
2111
- dependencies.push(valueSetIdentifier);
2112
- const enumValues = buildEnum(register, fhirSchema, element, logger);
2113
- return {
2114
- identifier,
2115
- type: fieldType,
2116
- valueset: valueSetIdentifier,
2117
- strength: element.binding.strength,
2118
- enum: enumValues,
2119
- dependencies
2120
- };
2121
- }
2122
- function collectBindingSchemas(register, fhirSchema, logger) {
2123
- const processedPaths = /* @__PURE__ */ new Set();
2124
- if (!fhirSchema.elements) return [];
2125
- const bindings = [];
2126
- function collectBindings(elements, parentPath) {
2127
- for (const [key, element] of Object.entries(elements)) {
2128
- const path = [...parentPath, key];
2129
- const pathKey = path.join(".");
2130
- const elemSnapshot = register.resolveElementSnapshot(fhirSchema, path);
2131
- if (processedPaths.has(pathKey)) continue;
2132
- processedPaths.add(pathKey);
2133
- if (elemSnapshot.binding) {
2134
- const binding = generateBindingSchema(register, fhirSchema, path, elemSnapshot, logger);
2135
- if (binding) {
2136
- bindings.push(binding);
2137
- }
2138
- }
2139
- if (element.elements) {
2140
- collectBindings(element.elements, path);
2141
- }
2142
- }
2143
- }
2144
- collectBindings(fhirSchema.elements, []);
2145
- bindings.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
2146
- const uniqueBindings = [];
2147
- const seenUrls = /* @__PURE__ */ new Set();
2148
- for (const binding of bindings) {
2149
- if (!seenUrls.has(binding.identifier.url)) {
2150
- seenUrls.add(binding.identifier.url);
2151
- uniqueBindings.push(binding);
2152
- }
2153
- }
2154
- return uniqueBindings;
2155
- }
2156
-
2157
2175
  // src/typeschema/core/transformer.ts
2158
2176
  function mkFields(register, fhirSchema, parentPath, elements, logger) {
2159
2177
  if (!elements) return void 0;
@@ -2284,15 +2302,13 @@ function extractExtensionValueTypes(register, fhirSchema, extensionUrl, logger)
2284
2302
  const uniq = new Map(valueTypes.map((type) => [type.url, type]));
2285
2303
  return Array.from(uniq.values());
2286
2304
  }
2287
- function extractSubExtensions(register, fhirSchema, extensionUrl, logger) {
2288
- const extensionSchema = register.resolveFs(fhirSchema.package_meta, extensionUrl);
2289
- if (!extensionSchema?.elements) return void 0;
2305
+ var extractLegacySubExtensions = (register, extensionSchema, logger) => {
2290
2306
  const subExtensions = [];
2307
+ if (!extensionSchema.elements) return subExtensions;
2291
2308
  for (const [key, element] of Object.entries(extensionSchema.elements)) {
2292
2309
  if (!key.startsWith("extension:")) continue;
2293
2310
  const sliceName = key.split(":")[1];
2294
2311
  if (!sliceName) continue;
2295
- const sliceUrl = element.url ?? sliceName;
2296
2312
  let valueType;
2297
2313
  for (const [elemKey, elemValue] of Object.entries(element.elements ?? {})) {
2298
2314
  if (elemValue.choiceOf !== "value" && !elemKey.startsWith("value")) continue;
@@ -2301,48 +2317,57 @@ function extractSubExtensions(register, fhirSchema, extensionUrl, logger) {
2301
2317
  }
2302
2318
  subExtensions.push({
2303
2319
  name: sliceName,
2304
- url: sliceUrl,
2320
+ url: element.url ?? sliceName,
2305
2321
  valueType,
2306
2322
  min: element.min,
2307
2323
  max: element.max !== void 0 ? String(element.max) : void 0
2308
2324
  });
2309
2325
  }
2310
- const extensionElement = extensionSchema.elements.extension;
2326
+ return subExtensions;
2327
+ };
2328
+ var extractSlicingSubExtensions = (extensionSchema) => {
2329
+ const subExtensions = [];
2330
+ const extensionElement = extensionSchema.elements?.extension;
2311
2331
  const slices = extensionElement?.slicing?.slices;
2312
- if (slices && typeof slices === "object") {
2313
- for (const [sliceName, sliceData] of Object.entries(slices)) {
2314
- const slice = sliceData;
2315
- const schema = slice.schema;
2316
- if (!schema) continue;
2317
- const sliceUrl = slice.match?.url ?? sliceName;
2318
- let valueType;
2319
- const schemaElements = schema.elements ?? {};
2320
- for (const [elemKey, elemValue] of Object.entries(schemaElements)) {
2321
- const elem = elemValue;
2322
- if (elem.choiceOf !== "value" && !elemKey.startsWith("value")) continue;
2323
- if (elem.type) {
2324
- valueType = {
2325
- kind: "complex-type",
2326
- package: extensionSchema.package_meta.name,
2327
- version: extensionSchema.package_meta.version,
2328
- name: elem.type,
2329
- url: `http://hl7.org/fhir/StructureDefinition/${elem.type}`
2330
- };
2331
- break;
2332
- }
2332
+ if (!slices || typeof slices !== "object") return subExtensions;
2333
+ for (const [sliceName, sliceData] of Object.entries(slices)) {
2334
+ const slice = sliceData;
2335
+ const schema = slice.schema;
2336
+ if (!schema) continue;
2337
+ let valueType;
2338
+ for (const [elemKey, elemValue] of Object.entries(schema.elements ?? {})) {
2339
+ const elem = elemValue;
2340
+ if (elem.choiceOf !== "value" && !elemKey.startsWith("value")) continue;
2341
+ if (elem.type) {
2342
+ valueType = {
2343
+ kind: "complex-type",
2344
+ package: extensionSchema.package_meta.name,
2345
+ version: extensionSchema.package_meta.version,
2346
+ name: elem.type,
2347
+ url: `http://hl7.org/fhir/StructureDefinition/${elem.type}`
2348
+ };
2349
+ break;
2333
2350
  }
2334
- subExtensions.push({
2335
- name: sliceName,
2336
- url: sliceUrl,
2337
- valueType,
2338
- min: schema._required ? 1 : schema.min ?? 0,
2339
- // biome-ignore lint/style/noNestedTernary : okay here
2340
- max: schema.max !== void 0 ? String(schema.max) : schema.array ? "*" : "1"
2341
- });
2342
2351
  }
2352
+ subExtensions.push({
2353
+ name: sliceName,
2354
+ url: slice.match?.url ?? sliceName,
2355
+ valueType,
2356
+ min: schema._required ? 1 : schema.min ?? 0,
2357
+ // biome-ignore lint/style/noNestedTernary : okay here
2358
+ max: schema.max !== void 0 ? String(schema.max) : schema.array ? "*" : "1"
2359
+ });
2343
2360
  }
2361
+ return subExtensions;
2362
+ };
2363
+ var extractSubExtensions = (register, fhirSchema, extensionUrl, logger) => {
2364
+ const extensionSchema = register.resolveFs(fhirSchema.package_meta, extensionUrl);
2365
+ if (!extensionSchema?.elements) return void 0;
2366
+ const legacySubs = extractLegacySubExtensions(register, extensionSchema, logger);
2367
+ const slicingSubs = extractSlicingSubExtensions(extensionSchema);
2368
+ const subExtensions = [...legacySubs, ...slicingSubs];
2344
2369
  return subExtensions.length > 0 ? subExtensions : void 0;
2345
- }
2370
+ };
2346
2371
  function extractProfileExtensions(register, fhirSchema, logger) {
2347
2372
  const extensions = [];
2348
2373
  const addExtensionEntry = (path, name, schema) => {
@@ -2399,256 +2424,64 @@ async function transformFhirSchema(register, fhirSchema, logger) {
2399
2424
  return schemas;
2400
2425
  }
2401
2426
 
2402
- // src/fhir-types/hl7-fhir-r4-core/CodeSystem.ts
2403
- var isCodeSystem = (resource) => {
2404
- return resource !== null && typeof resource === "object" && resource.resourceType === "CodeSystem";
2405
- };
2406
-
2407
- // src/fhir-types/hl7-fhir-r4-core/ValueSet.ts
2408
- var isValueSet = (resource) => {
2409
- return resource !== null && typeof resource === "object" && resource.resourceType === "ValueSet";
2410
- };
2411
-
2412
- // src/typeschema/register.ts
2413
- var readPackageDependencies = async (manager, packageMeta2) => {
2414
- const packageJSON = await manager.packageJson(packageMeta2.name);
2415
- const dependencies = packageJSON.dependencies;
2416
- if (dependencies !== void 0) {
2417
- return Object.entries(dependencies).map(([name, version]) => {
2418
- return { name, version };
2419
- });
2420
- }
2421
- return [];
2422
- };
2423
- var mkEmptyPkgIndex = (pkg) => {
2424
- return {
2425
- pkg,
2426
- canonicalResolution: {},
2427
- fhirSchemas: {},
2428
- valueSets: {}
2429
- };
2430
- };
2431
- var mkPackageAwareResolver = async (manager, pkg, deep, acc, logger) => {
2432
- const pkgId = packageMetaToFhir(pkg);
2433
- logger?.info(`${" ".repeat(deep * 2)}+ ${pkgId}`);
2434
- if (acc[pkgId]) return acc[pkgId];
2435
- const index = mkEmptyPkgIndex(pkg);
2436
- for (const resource of await manager.search({ package: pkg })) {
2437
- const rawUrl = resource.url;
2438
- if (!rawUrl) continue;
2439
- if (!(isStructureDefinition(resource) || isValueSet(resource) || isCodeSystem(resource))) continue;
2440
- const url = rawUrl;
2441
- if (index.canonicalResolution[url]) logger?.dry_warn(`Duplicate canonical URL: ${url} at ${pkgId}.`);
2442
- index.canonicalResolution[url] = [{ deep, pkg, pkgId, resource }];
2443
- }
2444
- const deps = await readPackageDependencies(manager, pkg);
2445
- for (const depPkg of deps) {
2446
- const { canonicalResolution } = await mkPackageAwareResolver(manager, depPkg, deep + 1, acc, logger);
2447
- for (const [surl, resolutions] of Object.entries(canonicalResolution)) {
2448
- const url = surl;
2449
- index.canonicalResolution[url] = [...index.canonicalResolution[url] || [], ...resolutions];
2450
- }
2451
- }
2452
- for (const resolutionOptions of Object.values(index.canonicalResolution)) {
2453
- resolutionOptions.sort((a, b) => a.deep - b.deep);
2454
- }
2455
- acc[pkgId] = index;
2456
- return index;
2457
- };
2458
- var enrichResolver = (resolver, logger) => {
2459
- for (const { pkg, canonicalResolution } of Object.values(resolver)) {
2460
- const pkgId = packageMetaToFhir(pkg);
2461
- if (!resolver[pkgId]) throw new Error(`Package ${pkgId} not found`);
2462
- for (const [_url, options] of Object.entries(canonicalResolution)) {
2463
- const resolition = options[0];
2464
- if (!resolition) throw new Error(`Resource not found`);
2465
- const resource = resolition.resource;
2466
- const resourcePkg = resolition.pkg;
2467
- if (isStructureDefinition(resource)) {
2468
- const fs7 = fhirschema.translate(resource);
2469
- const rfs = enrichFHIRSchema(fs7, resourcePkg);
2470
- resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2471
- }
2472
- if (isValueSet(resource)) {
2473
- const rvs = enrichValueSet(resource, resourcePkg);
2474
- resolver[pkgId].valueSets[rvs.url] = rvs;
2475
- }
2476
- }
2477
- }
2478
- };
2479
- var packageAgnosticResolveCanonical = (resolver, url, _logger) => {
2480
- const options = Object.values(resolver).flatMap((pkg) => pkg.canonicalResolution[url]);
2481
- if (!options) throw new Error(`No canonical resolution found for ${url} in any package`);
2482
- return options[0]?.resource;
2483
- };
2484
- var registerFromManager = async (manager, { logger, fallbackPackageForNameResolution, focusedPackages }) => {
2485
- const packages = focusedPackages ?? await manager.packages();
2486
- const resolver = {};
2487
- for (const pkg of packages) {
2488
- await mkPackageAwareResolver(manager, pkg, 0, resolver, logger);
2489
- }
2490
- enrichResolver(resolver);
2491
- const resolveFs = (pkg, canonicalUrl) => {
2492
- return resolver[packageMetaToFhir(pkg)]?.fhirSchemas[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.fhirSchemas[canonicalUrl];
2493
- };
2494
- const resolveVs = (pkg, canonicalUrl) => {
2495
- return resolver[packageMetaToFhir(pkg)]?.valueSets[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.valueSets[canonicalUrl];
2496
- };
2497
- const ensureSpecializationCanonicalUrl = (name) => {
2498
- if (name.includes("|")) name = name.split("|")[0];
2499
- if (name.match(/^[a-zA-Z0-9]+$/)) {
2500
- return `http://hl7.org/fhir/StructureDefinition/${name}`;
2501
- }
2502
- return name;
2503
- };
2504
- const resolveFsGenealogy = (pkg, canonicalUrl) => {
2505
- let fs7 = resolveFs(pkg, canonicalUrl);
2506
- if (fs7 === void 0) throw new Error(`Failed to resolve FHIR Schema: '${canonicalUrl}'`);
2507
- const genealogy = [fs7];
2508
- while (fs7?.base) {
2509
- const pkg2 = fs7.package_meta;
2510
- const baseUrl = ensureSpecializationCanonicalUrl(fs7.base);
2511
- fs7 = resolveFs(pkg2, baseUrl);
2512
- if (fs7 === void 0)
2513
- throw new Error(
2514
- `Failed to resolve FHIR Schema base for '${canonicalUrl}'. Problem: '${baseUrl}' from '${packageMetaToFhir(pkg2)}'`
2515
- );
2516
- genealogy.push(fs7);
2517
- }
2518
- return genealogy;
2519
- };
2520
- const resolveFsSpecializations = (pkg, canonicalUrl) => {
2521
- return resolveFsGenealogy(pkg, canonicalUrl).filter((fs7) => fs7.derivation === "specialization");
2522
- };
2523
- const resolveElementSnapshot = (fhirSchema, path) => {
2524
- const geneology = resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url);
2525
- const elemGeneology = resolveFsElementGenealogy(geneology, path);
2526
- const elemSnapshot = fsElementSnapshot(elemGeneology);
2527
- return elemSnapshot;
2528
- };
2529
- const getAllElementKeys = (elems) => {
2530
- const keys = /* @__PURE__ */ new Set();
2531
- for (const [key, elem] of Object.entries(elems)) {
2532
- keys.add(key);
2533
- for (const choiceKey of elem?.choices || []) {
2534
- if (!elems[choiceKey]) {
2535
- keys.add(choiceKey);
2536
- }
2537
- }
2538
- }
2539
- return Array.from(keys);
2540
- };
2541
- let cachedResolutionTree;
2542
- return {
2543
- testAppendFs(fs7) {
2544
- const rfs = enrichFHIRSchema(fs7);
2545
- const pkgId = packageMetaToFhir(rfs.package_meta);
2546
- if (!resolver[pkgId]) resolver[pkgId] = mkEmptyPkgIndex(rfs.package_meta);
2547
- resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2548
- cachedResolutionTree = void 0;
2549
- },
2550
- resolveFs,
2551
- resolveFsGenealogy,
2552
- resolveFsSpecializations,
2553
- ensureSpecializationCanonicalUrl,
2554
- resolveSd: (pkg, canonicalUrl) => {
2555
- const res = resolver[packageMetaToFhir(pkg)]?.canonicalResolution[canonicalUrl]?.[0]?.resource;
2556
- if (isStructureDefinition(res)) return res;
2557
- return void 0;
2558
- },
2559
- allSd: () => Object.values(resolver).flatMap(
2560
- (pkgIndex) => Object.values(pkgIndex.canonicalResolution).flatMap(
2561
- (resolutions) => resolutions.map((r) => {
2562
- const sd = r.resource;
2563
- if (!sd.package_name) {
2564
- return {
2565
- ...sd,
2566
- package_name: pkgIndex.pkg.name,
2567
- package_version: pkgIndex.pkg.version
2568
- };
2569
- }
2570
- return sd;
2571
- })
2572
- )
2573
- ).filter((r) => isStructureDefinition(r)).sort((sd1, sd2) => sd1.url.localeCompare(sd2.url)),
2574
- patchSd: (fn) => {
2575
- Object.values(resolver).flatMap(
2576
- (pkgIndex) => Object.values(pkgIndex.canonicalResolution).forEach((resolutions) => {
2577
- resolutions.forEach((e) => {
2578
- if (isStructureDefinition(e.resource)) {
2579
- const sd = e.resource;
2580
- const newSd = fn(pkgIndex.pkg, sd);
2581
- if (sd.url !== newSd.url)
2582
- throw new Error(`Patch update StructureDefinition URL: ${sd.url} !== ${newSd.url}`);
2583
- e.resource = newSd;
2584
- }
2585
- });
2586
- })
2427
+ // src/typeschema/index.ts
2428
+ var deduplicateSchemas = (schemasWithSources, logger) => {
2429
+ const groups = {};
2430
+ for (const item of schemasWithSources) {
2431
+ const key = `${item.schema.identifier.url}|${item.schema.identifier.package}`;
2432
+ const hash = hashSchema(item.schema);
2433
+ groups[key] ??= {};
2434
+ groups[key][hash] ??= { typeSchema: item.schema, sources: [] };
2435
+ groups[key][hash].sources.push(item);
2436
+ }
2437
+ const schemas = [];
2438
+ const collisions = {};
2439
+ for (const versions of Object.values(groups)) {
2440
+ const sorted = Object.values(versions).sort((a, b) => b.sources.length - a.sources.length);
2441
+ const best = sorted[0];
2442
+ if (!best) continue;
2443
+ schemas.push(best.typeSchema);
2444
+ if (sorted.length > 1) {
2445
+ const pkg = best.typeSchema.identifier.package;
2446
+ const url = best.typeSchema.identifier.url;
2447
+ logger?.dryWarn(`'${url}' from '${pkg}'' has ${sorted.length} versions`);
2448
+ collisions[pkg] ??= {};
2449
+ collisions[pkg][url] = sorted.flatMap(
2450
+ (v) => v.sources.map((s) => ({
2451
+ typeSchema: v.typeSchema,
2452
+ sourcePackage: s.sourcePackage,
2453
+ sourceCanonical: s.sourceCanonical
2454
+ }))
2587
2455
  );
2588
- enrichResolver(resolver);
2589
- cachedResolutionTree = void 0;
2590
- },
2591
- allFs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.fhirSchemas)),
2592
- allVs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.valueSets)),
2593
- resolveVs,
2594
- resolveAny: (canonicalUrl) => packageAgnosticResolveCanonical(resolver, canonicalUrl),
2595
- resolveElementSnapshot,
2596
- getAllElementKeys,
2597
- resolver,
2598
- resolutionTree: () => {
2599
- if (cachedResolutionTree) return cachedResolutionTree;
2600
- const res = {};
2601
- for (const [_pkgId, pkgIndex] of Object.entries(resolver)) {
2602
- const pkgName = pkgIndex.pkg.name;
2603
- res[pkgName] = {};
2604
- for (const [surl, resolutions] of Object.entries(pkgIndex.canonicalResolution)) {
2605
- const url = surl;
2606
- res[pkgName][url] = [];
2607
- for (const resolution of resolutions) {
2608
- res[pkgName][url].push({ deep: resolution.deep, pkg: resolution.pkg });
2609
- }
2610
- }
2611
- }
2612
- cachedResolutionTree = res;
2613
- return res;
2614
- }
2615
- };
2616
- };
2617
- var resolveFsElementGenealogy = (genealogy, path) => {
2618
- const [top, ...rest] = path;
2619
- if (top === void 0) return [];
2620
- return genealogy.map((fs7) => {
2621
- if (!fs7.elements) return void 0;
2622
- let elem = fs7.elements?.[top];
2623
- for (const k of rest) {
2624
- elem = elem?.elements?.[k];
2625
2456
  }
2626
- return elem;
2627
- }).filter((elem) => elem !== void 0);
2457
+ }
2458
+ return { schemas, collisions };
2628
2459
  };
2629
- function fsElementSnapshot(genealogy) {
2630
- const revGenealogy = genealogy.reverse();
2631
- const snapshot = Object.assign({}, ...revGenealogy);
2632
- snapshot.elements = void 0;
2633
- return snapshot;
2634
- }
2635
-
2636
- // src/typeschema/index.ts
2637
2460
  var generateTypeSchemas = async (register, logger) => {
2638
- const fhirSchemas = [];
2461
+ const schemasWithSources = [];
2639
2462
  for (const fhirSchema of register.allFs()) {
2640
2463
  const pkgId = packageMetaToFhir(fhirSchema.package_meta);
2641
2464
  const skipCheck = shouldSkipCanonical(fhirSchema.package_meta, fhirSchema.url);
2642
2465
  if (skipCheck.shouldSkip) {
2643
- logger?.dry_warn(`Skip ${fhirSchema.url} from ${pkgId}. Reason: ${skipCheck.reason}`);
2466
+ logger?.dryWarn(`Skip ${fhirSchema.url} from ${pkgId}. Reason: ${skipCheck.reason}`);
2644
2467
  continue;
2645
2468
  }
2646
- fhirSchemas.push(...await transformFhirSchema(register, fhirSchema, logger));
2469
+ for (const schema of await transformFhirSchema(register, fhirSchema, logger)) {
2470
+ schemasWithSources.push({
2471
+ schema,
2472
+ sourcePackage: pkgId,
2473
+ sourceCanonical: fhirSchema.url
2474
+ });
2475
+ }
2647
2476
  }
2648
2477
  for (const vsSchema of register.allVs()) {
2649
- fhirSchemas.push(await transformValueSet(register, vsSchema));
2478
+ schemasWithSources.push({
2479
+ schema: await transformValueSet(register, vsSchema),
2480
+ sourcePackage: packageMetaToFhir(vsSchema.package_meta),
2481
+ sourceCanonical: vsSchema.url
2482
+ });
2650
2483
  }
2651
- return fhirSchemas;
2484
+ return deduplicateSchemas(schemasWithSources, logger);
2652
2485
  };
2653
2486
 
2654
2487
  // src/typeschema/ir/logic-promotion.ts
@@ -2829,38 +2662,316 @@ var treeShake = (tsIndex, treeShake2) => {
2829
2662
  for (const schema of schemas) {
2830
2663
  acc[JSON.stringify(schema.identifier)] = schema;
2831
2664
  }
2832
- const newSchemas = [];
2833
- for (const schema of schemas) {
2834
- if (isSpecializationTypeSchema(schema) || isProfileTypeSchema(schema)) {
2835
- if (!schema.dependencies) continue;
2836
- schema.dependencies.forEach((dep) => {
2837
- const depSchema = tsIndex.resolve(dep);
2838
- if (!depSchema)
2839
- throw new Error(
2840
- `Dependent schema ${JSON.stringify(dep)} not found for ${JSON.stringify(schema.identifier)}`
2841
- );
2842
- const id = JSON.stringify(depSchema.identifier);
2843
- if (!acc[id]) newSchemas.push(depSchema);
2844
- });
2845
- if (schema.nested) {
2846
- for (const nest of schema.nested) {
2847
- if (isNestedIdentifier(nest.identifier)) continue;
2848
- const id = JSON.stringify(nest.identifier);
2849
- if (!acc[id]) newSchemas.push(nest);
2665
+ const newSchemas = [];
2666
+ for (const schema of schemas) {
2667
+ if (isSpecializationTypeSchema(schema) || isProfileTypeSchema(schema)) {
2668
+ if (!schema.dependencies) continue;
2669
+ schema.dependencies.forEach((dep) => {
2670
+ const depSchema = tsIndex.resolve(dep);
2671
+ if (!depSchema)
2672
+ throw new Error(
2673
+ `Dependent schema ${JSON.stringify(dep)} not found for ${JSON.stringify(schema.identifier)}`
2674
+ );
2675
+ const id = JSON.stringify(depSchema.identifier);
2676
+ if (!acc[id]) newSchemas.push(depSchema);
2677
+ });
2678
+ if (schema.nested) {
2679
+ for (const nest of schema.nested) {
2680
+ if (isNestedIdentifier(nest.identifier)) continue;
2681
+ const id = JSON.stringify(nest.identifier);
2682
+ if (!acc[id]) newSchemas.push(nest);
2683
+ }
2684
+ }
2685
+ }
2686
+ }
2687
+ return collectDeps(newSchemas, acc);
2688
+ };
2689
+ const shaked = collectDeps(focusedSchemas, {});
2690
+ const shakedIndex = tsIndex.replaceSchemas(shaked);
2691
+ const treeShakeReport = { skippedPackages: [], packages: {} };
2692
+ const irReport = shakedIndex.irReport();
2693
+ irReport.treeShake = treeShakeReport;
2694
+ mutableFillReport(treeShakeReport, tsIndex, shakedIndex);
2695
+ return shakedIndex;
2696
+ };
2697
+
2698
+ // src/fhir-types/hl7-fhir-r4-core/CodeSystem.ts
2699
+ var isCodeSystem = (resource) => {
2700
+ return resource !== null && typeof resource === "object" && resource.resourceType === "CodeSystem";
2701
+ };
2702
+
2703
+ // src/fhir-types/hl7-fhir-r4-core/ValueSet.ts
2704
+ var isValueSet = (resource) => {
2705
+ return resource !== null && typeof resource === "object" && resource.resourceType === "ValueSet";
2706
+ };
2707
+
2708
+ // src/typeschema/register.ts
2709
+ var readPackageDependencies = async (manager, packageMeta2) => {
2710
+ const packageJSON = await manager.packageJson(packageMeta2.name);
2711
+ if (!packageJSON) return [];
2712
+ const dependencies = packageJSON.dependencies;
2713
+ if (dependencies !== void 0) {
2714
+ return Object.entries(dependencies).map(([name, version]) => {
2715
+ return { name, version };
2716
+ });
2717
+ }
2718
+ return [];
2719
+ };
2720
+ var mkEmptyPkgIndex = (pkg) => {
2721
+ return {
2722
+ pkg,
2723
+ canonicalResolution: {},
2724
+ fhirSchemas: {},
2725
+ valueSets: {}
2726
+ };
2727
+ };
2728
+ var mkPackageAwareResolver = async (manager, pkg, deep, acc, logger) => {
2729
+ const pkgId = packageMetaToFhir(pkg);
2730
+ logger?.info(`${" ".repeat(deep * 2)}+ ${pkgId}`);
2731
+ if (acc[pkgId]) return acc[pkgId];
2732
+ const index = mkEmptyPkgIndex(pkg);
2733
+ for (const resource of await manager.search({ package: pkg })) {
2734
+ const rawUrl = resource.url;
2735
+ if (!rawUrl) continue;
2736
+ if (!(isStructureDefinition(resource) || isValueSet(resource) || isCodeSystem(resource))) continue;
2737
+ const url = rawUrl;
2738
+ if (index.canonicalResolution[url]) logger?.dryWarn(`Duplicate canonical URL: ${url} at ${pkgId}.`);
2739
+ index.canonicalResolution[url] = [{ deep, pkg, pkgId, resource }];
2740
+ }
2741
+ const deps = await readPackageDependencies(manager, pkg);
2742
+ for (const depPkg of deps) {
2743
+ const { canonicalResolution } = await mkPackageAwareResolver(manager, depPkg, deep + 1, acc, logger);
2744
+ for (const [surl, resolutions] of Object.entries(canonicalResolution)) {
2745
+ const url = surl;
2746
+ index.canonicalResolution[url] = [...index.canonicalResolution[url] || [], ...resolutions];
2747
+ }
2748
+ }
2749
+ for (const resolutionOptions of Object.values(index.canonicalResolution)) {
2750
+ resolutionOptions.sort((a, b) => a.deep - b.deep);
2751
+ }
2752
+ acc[pkgId] = index;
2753
+ return index;
2754
+ };
2755
+ var enrichResolver = (resolver, logger) => {
2756
+ for (const { pkg, canonicalResolution } of Object.values(resolver)) {
2757
+ const pkgId = packageMetaToFhir(pkg);
2758
+ if (!resolver[pkgId]) throw new Error(`Package ${pkgId} not found`);
2759
+ for (const [_url, options] of Object.entries(canonicalResolution)) {
2760
+ const resolition = options[0];
2761
+ if (!resolition) throw new Error(`Resource not found`);
2762
+ const resource = resolition.resource;
2763
+ const resourcePkg = resolition.pkg;
2764
+ if (isStructureDefinition(resource)) {
2765
+ const fs7 = fhirschema.translate(resource);
2766
+ const rfs = enrichFHIRSchema(fs7, resourcePkg);
2767
+ resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2768
+ }
2769
+ if (isValueSet(resource)) {
2770
+ const rvs = enrichValueSet(resource, resourcePkg);
2771
+ resolver[pkgId].valueSets[rvs.url] = rvs;
2772
+ }
2773
+ }
2774
+ }
2775
+ };
2776
+ var packageAgnosticResolveCanonical = (resolver, url, _logger) => {
2777
+ const options = Object.values(resolver).flatMap((pkg) => pkg.canonicalResolution[url]);
2778
+ if (!options) throw new Error(`No canonical resolution found for ${url} in any package`);
2779
+ return options[0]?.resource;
2780
+ };
2781
+ var registerFromManager = async (manager, { logger, focusedPackages }) => {
2782
+ const packages = focusedPackages ?? await manager.packages();
2783
+ const resolver = {};
2784
+ for (const pkg of packages) {
2785
+ await mkPackageAwareResolver(manager, pkg, 0, resolver, logger);
2786
+ }
2787
+ enrichResolver(resolver);
2788
+ const resolveFs = (pkg, canonicalUrl) => {
2789
+ const pkgIndex = resolver[packageMetaToFhir(pkg)];
2790
+ if (pkgIndex) {
2791
+ const resolution = pkgIndex.canonicalResolution[canonicalUrl]?.[0];
2792
+ if (resolution) {
2793
+ return resolver[resolution.pkgId]?.fhirSchemas[canonicalUrl];
2794
+ }
2795
+ }
2796
+ for (const idx of Object.values(resolver)) {
2797
+ const fs7 = idx.fhirSchemas[canonicalUrl];
2798
+ if (fs7 && fs7.package_meta.name === pkg.name) return fs7;
2799
+ }
2800
+ for (const idx of Object.values(resolver)) {
2801
+ const fs7 = idx.fhirSchemas[canonicalUrl];
2802
+ if (fs7) return fs7;
2803
+ }
2804
+ return void 0;
2805
+ };
2806
+ const resolveVs = (pkg, canonicalUrl) => {
2807
+ const pkgIndex = resolver[packageMetaToFhir(pkg)];
2808
+ if (pkgIndex) {
2809
+ const resolution = pkgIndex.canonicalResolution[canonicalUrl]?.[0];
2810
+ if (resolution) {
2811
+ return resolver[resolution.pkgId]?.valueSets[canonicalUrl];
2812
+ }
2813
+ }
2814
+ for (const idx of Object.values(resolver)) {
2815
+ const vs = idx.valueSets[canonicalUrl];
2816
+ if (vs && vs.package_meta.name === pkg.name) return vs;
2817
+ }
2818
+ for (const idx of Object.values(resolver)) {
2819
+ const vs = idx.valueSets[canonicalUrl];
2820
+ if (vs) return vs;
2821
+ }
2822
+ return void 0;
2823
+ };
2824
+ const ensureSpecializationCanonicalUrl = (name) => {
2825
+ if (name.includes("|")) name = name.split("|")[0];
2826
+ if (name.match(/^[a-zA-Z0-9]+$/)) {
2827
+ return `http://hl7.org/fhir/StructureDefinition/${name}`;
2828
+ }
2829
+ return name;
2830
+ };
2831
+ const resolveFsGenealogy = (pkg, canonicalUrl) => {
2832
+ let fs7 = resolveFs(pkg, canonicalUrl);
2833
+ if (fs7 === void 0) throw new Error(`Failed to resolve FHIR Schema: '${canonicalUrl}'`);
2834
+ const genealogy = [fs7];
2835
+ while (fs7?.base) {
2836
+ const pkg2 = fs7.package_meta;
2837
+ const baseUrl = ensureSpecializationCanonicalUrl(fs7.base);
2838
+ fs7 = resolveFs(pkg2, baseUrl);
2839
+ if (fs7 === void 0)
2840
+ throw new Error(
2841
+ `Failed to resolve FHIR Schema base for '${canonicalUrl}'. Problem: '${baseUrl}' from '${packageMetaToFhir(pkg2)}'`
2842
+ );
2843
+ genealogy.push(fs7);
2844
+ }
2845
+ return genealogy;
2846
+ };
2847
+ const resolveFsSpecializations = (pkg, canonicalUrl) => {
2848
+ return resolveFsGenealogy(pkg, canonicalUrl).filter((fs7) => fs7.derivation === "specialization");
2849
+ };
2850
+ const resolveElementSnapshot = (fhirSchema, path) => {
2851
+ const geneology = resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url);
2852
+ const elemGeneology = resolveFsElementGenealogy(geneology, path);
2853
+ const elemSnapshot = fsElementSnapshot(elemGeneology);
2854
+ return elemSnapshot;
2855
+ };
2856
+ const getAllElementKeys = (elems) => {
2857
+ const keys = /* @__PURE__ */ new Set();
2858
+ for (const [key, elem] of Object.entries(elems)) {
2859
+ keys.add(key);
2860
+ for (const choiceKey of elem?.choices || []) {
2861
+ if (!elems[choiceKey]) {
2862
+ keys.add(choiceKey);
2863
+ }
2864
+ }
2865
+ }
2866
+ return Array.from(keys);
2867
+ };
2868
+ let cachedResolutionTree;
2869
+ return {
2870
+ testAppendFs(rfs) {
2871
+ const pkgId = packageMetaToFhir(rfs.package_meta);
2872
+ if (!resolver[pkgId]) resolver[pkgId] = mkEmptyPkgIndex(rfs.package_meta);
2873
+ resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2874
+ cachedResolutionTree = void 0;
2875
+ },
2876
+ resolveFs,
2877
+ resolveFsGenealogy,
2878
+ resolveFsSpecializations,
2879
+ ensureSpecializationCanonicalUrl,
2880
+ resolveSd: (pkg, canonicalUrl) => {
2881
+ const res = resolver[packageMetaToFhir(pkg)]?.canonicalResolution[canonicalUrl]?.[0]?.resource;
2882
+ if (isStructureDefinition(res)) return res;
2883
+ return void 0;
2884
+ },
2885
+ allSd: () => Object.values(resolver).flatMap(
2886
+ (pkgIndex) => Object.values(pkgIndex.canonicalResolution).flatMap(
2887
+ (resolutions) => resolutions.map((r) => {
2888
+ const sd = r.resource;
2889
+ if (!sd.package_name) {
2890
+ return {
2891
+ ...sd,
2892
+ package_name: pkgIndex.pkg.name,
2893
+ package_version: pkgIndex.pkg.version
2894
+ };
2895
+ }
2896
+ return sd;
2897
+ })
2898
+ )
2899
+ ).filter((r) => isStructureDefinition(r)).sort((sd1, sd2) => sd1.url.localeCompare(sd2.url)),
2900
+ patchSd: (fn) => {
2901
+ Object.values(resolver).flatMap(
2902
+ (pkgIndex) => Object.values(pkgIndex.canonicalResolution).forEach((resolutions) => {
2903
+ resolutions.forEach((e) => {
2904
+ if (isStructureDefinition(e.resource)) {
2905
+ const sd = e.resource;
2906
+ const newSd = fn(pkgIndex.pkg, sd);
2907
+ if (sd.url !== newSd.url)
2908
+ throw new Error(`Patch update StructureDefinition URL: ${sd.url} !== ${newSd.url}`);
2909
+ e.resource = newSd;
2910
+ }
2911
+ });
2912
+ })
2913
+ );
2914
+ enrichResolver(resolver);
2915
+ cachedResolutionTree = void 0;
2916
+ },
2917
+ allFs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.fhirSchemas)),
2918
+ allVs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.valueSets)),
2919
+ resolveVs,
2920
+ resolveAny: (canonicalUrl) => packageAgnosticResolveCanonical(resolver, canonicalUrl),
2921
+ resolveElementSnapshot,
2922
+ getAllElementKeys,
2923
+ resolver,
2924
+ resolutionTree: () => {
2925
+ if (cachedResolutionTree) return cachedResolutionTree;
2926
+ const res = {};
2927
+ for (const [_pkgId, pkgIndex] of Object.entries(resolver)) {
2928
+ const pkgName = pkgIndex.pkg.name;
2929
+ res[pkgName] = {};
2930
+ for (const [surl, resolutions] of Object.entries(pkgIndex.canonicalResolution)) {
2931
+ const url = surl;
2932
+ res[pkgName][url] = [];
2933
+ for (const resolution of resolutions) {
2934
+ res[pkgName][url].push({ deep: resolution.deep, pkg: resolution.pkg });
2850
2935
  }
2851
2936
  }
2852
2937
  }
2938
+ cachedResolutionTree = res;
2939
+ return res;
2853
2940
  }
2854
- return collectDeps(newSchemas, acc);
2855
2941
  };
2856
- const shaked = collectDeps(focusedSchemas, {});
2857
- const shakedIndex = tsIndex.replaceSchemas(shaked);
2858
- const treeShakeReport = { skippedPackages: [], packages: {} };
2859
- const irReport = shakedIndex.irReport();
2860
- irReport.treeShake = treeShakeReport;
2861
- mutableFillReport(treeShakeReport, tsIndex, shakedIndex);
2862
- return shakedIndex;
2863
2942
  };
2943
+ var registerFromPackageMetas = async (packageMetas, conf) => {
2944
+ const packageNames = packageMetas.map(packageMetaToNpm);
2945
+ conf?.logger?.step(`Loading FHIR packages: ${packageNames.join(", ")}`);
2946
+ const manager = CanonicalManager({
2947
+ packages: packageNames,
2948
+ workingDir: "tmp/fhir",
2949
+ registry: conf.registry || void 0
2950
+ });
2951
+ await manager.init();
2952
+ return await registerFromManager(manager, {
2953
+ ...conf,
2954
+ focusedPackages: packageMetas
2955
+ });
2956
+ };
2957
+ var resolveFsElementGenealogy = (genealogy, path) => {
2958
+ const [top, ...rest] = path;
2959
+ if (top === void 0) return [];
2960
+ return genealogy.map((fs7) => {
2961
+ if (!fs7.elements) return void 0;
2962
+ let elem = fs7.elements?.[top];
2963
+ for (const k of rest) {
2964
+ elem = elem?.elements?.[k];
2965
+ }
2966
+ return elem;
2967
+ }).filter((elem) => elem !== void 0);
2968
+ };
2969
+ function fsElementSnapshot(genealogy) {
2970
+ const revGenealogy = genealogy.reverse();
2971
+ const snapshot = Object.assign({}, ...revGenealogy);
2972
+ snapshot.elements = void 0;
2973
+ return snapshot;
2974
+ }
2864
2975
  var normalizeFileName = (str) => {
2865
2976
  const res = str.replace(/[^a-zA-Z0-9\-_.@#()]/g, "");
2866
2977
  if (res.length === 0) return "unknown";
@@ -2902,23 +3013,60 @@ var IntrospectionWriter = class extends FileSystemWriter {
2902
3013
  this.logger()?.info(`IntrospectionWriter: Type tree written to ${this.opts.typeTree}`);
2903
3014
  }
2904
3015
  if (this.opts.typeSchemas) {
2905
- const outputPath = this.opts.typeSchemas;
2906
- const typeSchemas = tsIndex.schemas;
2907
- if (Path5.extname(outputPath) === ".ndjson") {
2908
- this.writeNdjson(typeSchemas, outputPath, typeSchemaToJson);
3016
+ if (Path5.extname(this.opts.typeSchemas) === ".ndjson") {
3017
+ this.writeNdjson(tsIndex.schemas, this.opts.typeSchemas, typeSchemaToJson);
2909
3018
  } else {
2910
- this.writeJsonFiles(
2911
- typeSchemas.map((ts) => typeSchemaToJson(ts, true)),
2912
- outputPath
2913
- );
3019
+ const items = tsIndex.schemas.map((ts) => typeSchemaToJson(ts, true));
3020
+ const seenFilenames = /* @__PURE__ */ new Set();
3021
+ const dedupedItems = items.filter((item) => {
3022
+ if (seenFilenames.has(item.filename)) return false;
3023
+ seenFilenames.add(item.filename);
3024
+ return true;
3025
+ });
3026
+ this.cd(this.opts.typeSchemas, () => {
3027
+ for (const { filename, genContent } of dedupedItems) {
3028
+ const fileName = `${filename}.json`;
3029
+ this.cd(Path5.dirname(fileName), () => {
3030
+ this.cat(Path5.basename(fileName), () => {
3031
+ this.write(genContent());
3032
+ });
3033
+ });
3034
+ }
3035
+ for (const [pkg, canonicals] of Object.entries(tsIndex.irReport().collisions ?? {})) {
3036
+ this.cd(`${normalizeFileName(pkg)}`, () => {
3037
+ for (const [canonical, entries] of Object.entries(canonicals)) {
3038
+ if (entries.length <= 1) continue;
3039
+ const firstEntry = entries[0];
3040
+ assert3(firstEntry);
3041
+ const name = normalizeFileName(
3042
+ `${firstEntry.typeSchema.identifier.name}(${extractNameFromCanonical(canonical)})`
3043
+ );
3044
+ this.cd(Path5.join("collisions", name), () => {
3045
+ for (let i = 0; i < entries.length; i++) {
3046
+ const entry = entries[i];
3047
+ this.cat(`${i + 1}.json`, () => {
3048
+ this.write(JSON.stringify(entry, null, 2));
3049
+ });
3050
+ }
3051
+ });
3052
+ }
3053
+ });
3054
+ }
3055
+ });
2914
3056
  }
2915
3057
  this.logger()?.info(
2916
- `IntrospectionWriter: ${typeSchemas.length} TypeSchema written to ${this.opts.typeSchemas}`
3058
+ `IntrospectionWriter: ${tsIndex.schemas.length} TypeSchema written to ${this.opts.typeSchemas}`
2917
3059
  );
2918
3060
  }
2919
3061
  if (this.opts.fhirSchemas && tsIndex.register) {
2920
3062
  const outputPath = this.opts.fhirSchemas;
2921
- const fhirSchemas = tsIndex.register.allFs();
3063
+ const allFs = tsIndex.register.allFs();
3064
+ const seenUrls = /* @__PURE__ */ new Set();
3065
+ const fhirSchemas = allFs.filter((fs7) => {
3066
+ if (seenUrls.has(fs7.url)) return false;
3067
+ seenUrls.add(fs7.url);
3068
+ return true;
3069
+ });
2922
3070
  if (Path5.extname(outputPath) === ".ndjson") {
2923
3071
  this.writeNdjson(fhirSchemas, outputPath, fhirSchemaToJson);
2924
3072
  } else {
@@ -2931,7 +3079,13 @@ var IntrospectionWriter = class extends FileSystemWriter {
2931
3079
  }
2932
3080
  if (this.opts.structureDefinitions && tsIndex.register) {
2933
3081
  const outputPath = this.opts.structureDefinitions;
2934
- const structureDefinitions = tsIndex.register.allSd();
3082
+ const allSd = tsIndex.register.allSd();
3083
+ const seenUrls = /* @__PURE__ */ new Set();
3084
+ const structureDefinitions = allSd.filter((sd) => {
3085
+ if (seenUrls.has(sd.url)) return false;
3086
+ seenUrls.add(sd.url);
3087
+ return true;
3088
+ });
2935
3089
  if (Path5.extname(outputPath) === ".ndjson") {
2936
3090
  this.writeNdjson(structureDefinitions, outputPath, structureDefinitionToJson);
2937
3091
  } else {
@@ -2984,58 +3138,118 @@ var IntrospectionWriter = class extends FileSystemWriter {
2984
3138
  };
2985
3139
 
2986
3140
  // src/typeschema/ir/report.ts
2987
- var generateIrReportReadme = (report) => {
2988
- const lines = ["# IR Report", ""];
2989
- const allPackages = /* @__PURE__ */ new Set([
2990
- ...Object.keys(report.treeShake?.packages ?? {}),
2991
- ...Object.keys(report.logicalPromotion?.packages ?? {})
2992
- ]);
2993
- if (allPackages.size === 0) {
2994
- lines.push("No IR modifications applied.");
2995
- return lines.join("\n");
3141
+ var generateSkippedPackagesSection = (lines, skippedPackages) => {
3142
+ lines.push("## Skipped Packages", "");
3143
+ for (const pkg of skippedPackages) {
3144
+ lines.push(`- ${pkg}`);
2996
3145
  }
2997
- if (report.treeShake?.skippedPackages.length) {
2998
- lines.push("## Skipped Packages", "");
2999
- for (const pkg of report.treeShake.skippedPackages) {
3000
- lines.push(`- ${pkg}`);
3146
+ lines.push("");
3147
+ };
3148
+ var generatePackageSection = (lines, pkgName, treeShakePkg, promotedCanonicals) => {
3149
+ lines.push(`## Package: \`${pkgName}\``, "");
3150
+ if (promotedCanonicals?.length) {
3151
+ lines.push("### Promoted Logical Models", "");
3152
+ for (const canonical of promotedCanonicals) {
3153
+ lines.push(`- \`${canonical}\``);
3001
3154
  }
3002
3155
  lines.push("");
3003
3156
  }
3004
- for (const pkgName of [...allPackages].sort()) {
3005
- lines.push(`## Package: \`${pkgName}\``, "");
3006
- const treeShakePkg = report.treeShake?.packages[pkgName];
3007
- const logicalPromotionPkg = report.logicalPromotion?.packages[pkgName];
3008
- if (logicalPromotionPkg?.promotedCanonicals.length) {
3009
- lines.push("### Promoted Logical Models", "");
3010
- for (const canonical of logicalPromotionPkg.promotedCanonicals) {
3011
- lines.push(`- \`${canonical}\``);
3157
+ if (!treeShakePkg) return;
3158
+ const canonicalsWithChanges = Object.entries(treeShakePkg.canonicals).filter(
3159
+ ([_, data]) => data.skippedFields.length > 0
3160
+ );
3161
+ if (canonicalsWithChanges.length > 0) {
3162
+ lines.push("### Modified Canonicals", "");
3163
+ for (const [canonical, data] of canonicalsWithChanges) {
3164
+ lines.push(`#### \`${canonical}\``, "");
3165
+ lines.push("Skipped fields:", "");
3166
+ for (const field of data.skippedFields) {
3167
+ lines.push(`- \`${field}\``);
3012
3168
  }
3013
3169
  lines.push("");
3014
3170
  }
3015
- if (treeShakePkg) {
3016
- const canonicalsWithChanges = Object.entries(treeShakePkg.canonicals).filter(
3017
- ([_, data]) => data.skippedFields.length > 0
3018
- );
3019
- if (canonicalsWithChanges.length > 0) {
3020
- lines.push("### Modified Canonicals", "");
3021
- for (const [canonical, data] of canonicalsWithChanges) {
3022
- lines.push(`#### \`${canonical}\``, "");
3023
- lines.push("Skipped fields:", "");
3024
- for (const field of data.skippedFields) {
3025
- lines.push(`- \`${field}\``);
3026
- }
3027
- lines.push("");
3028
- }
3029
- }
3030
- if (treeShakePkg.skippedCanonicals.length > 0) {
3031
- lines.push("### Skipped Canonicals", "");
3032
- for (const canonical of treeShakePkg.skippedCanonicals) {
3033
- lines.push(`- \`${canonical}\``);
3034
- }
3035
- lines.push("");
3171
+ }
3172
+ if (treeShakePkg.skippedCanonicals.length > 0) {
3173
+ lines.push("### Skipped Canonicals", "");
3174
+ for (const canonical of treeShakePkg.skippedCanonicals) {
3175
+ lines.push(`- \`${canonical}\``);
3176
+ }
3177
+ lines.push("");
3178
+ }
3179
+ };
3180
+ var generateCollisionVersionLines = (entries) => {
3181
+ const uniqueSchemas = /* @__PURE__ */ new Map();
3182
+ for (const entry of entries) {
3183
+ const key = JSON.stringify(entry.typeSchema);
3184
+ if (!uniqueSchemas.has(key)) uniqueSchemas.set(key, []);
3185
+ uniqueSchemas.get(key)?.push(entry);
3186
+ }
3187
+ const versionLines = [];
3188
+ const sortedVersions = [...uniqueSchemas.values()].sort((a, b) => b.length - a.length);
3189
+ let version = 1;
3190
+ for (const schemaEntries of sortedVersions) {
3191
+ const sourceList = schemaEntries.map((e) => {
3192
+ const name = extractNameFromCanonical(e.sourceCanonical) ?? e.sourceCanonical;
3193
+ return `${name} (${e.sourcePackage})`;
3194
+ }).join(", ");
3195
+ versionLines.push(` - Version ${version++}: ${sourceList}`);
3196
+ }
3197
+ return versionLines;
3198
+ };
3199
+ var generateCollisionsSection = (lines, collisions) => {
3200
+ if (!collisions) return;
3201
+ lines.push("## Schema Collisions", "");
3202
+ lines.push("The following canonicals have multiple schema versions with different content.");
3203
+ lines.push("To inspect collision versions, export TypeSchemas using `.introspection({ typeSchemas: 'path' })`");
3204
+ lines.push("and check `<pkg>/collisions/<name>/1.json, 2.json, ...` files.", "");
3205
+ const collisionPackages = Object.keys(collisions).sort();
3206
+ for (const pkgName of collisionPackages) {
3207
+ const collisionsPkg = collisions[pkgName];
3208
+ if (!collisionsPkg) throw new Error(`Missing collisions for package ${pkgName}`);
3209
+ const sortedEntries = Object.entries(collisionsPkg).sort(([a], [b]) => {
3210
+ const nameA = a.split("/").pop() ?? a;
3211
+ const nameB = b.split("/").pop() ?? b;
3212
+ return nameA.localeCompare(nameB);
3213
+ });
3214
+ if (sortedEntries.length > 0) {
3215
+ lines.push(`### \`${pkgName}\``, "");
3216
+ for (const [canonical, entries] of sortedEntries) {
3217
+ const versionLines = generateCollisionVersionLines(entries);
3218
+ lines.push(`- \`${canonical}\` (${versionLines.length} versions)`);
3219
+ lines.push(...versionLines);
3036
3220
  }
3221
+ lines.push("");
3037
3222
  }
3038
3223
  }
3224
+ };
3225
+ var generateIrReportReadme = (report) => {
3226
+ const lines = ["# IR Report", ""];
3227
+ const irPackages = [
3228
+ .../* @__PURE__ */ new Set([
3229
+ ...Object.keys(report.treeShake?.packages ?? {}),
3230
+ ...Object.keys(report.logicalPromotion?.packages ?? {})
3231
+ ])
3232
+ ].sort();
3233
+ const hasIrChanges = irPackages.length > 0 || (report.treeShake?.skippedPackages.length ?? 0) > 0;
3234
+ const hasCollisions = Object.keys(report.collisions ?? {}).length > 0;
3235
+ if (!hasIrChanges && !hasCollisions) {
3236
+ lines.push("No IR modifications applied.");
3237
+ return lines.join("\n");
3238
+ }
3239
+ if (report.treeShake?.skippedPackages.length) {
3240
+ generateSkippedPackagesSection(lines, report.treeShake.skippedPackages);
3241
+ }
3242
+ for (const pkgName of irPackages) {
3243
+ generatePackageSection(
3244
+ lines,
3245
+ pkgName,
3246
+ report.treeShake?.packages[pkgName],
3247
+ report.logicalPromotion?.packages[pkgName]?.promotedCanonicals
3248
+ );
3249
+ }
3250
+ if (hasCollisions) {
3251
+ generateCollisionsSection(lines, report.collisions);
3252
+ }
3039
3253
  return lines.join("\n");
3040
3254
  };
3041
3255
 
@@ -3407,25 +3621,27 @@ var ViewModelFactory = class {
3407
3621
  hasFields: fields.length > 0,
3408
3622
  hasNestedComplexTypes: nestedComplexTypes.length > 0,
3409
3623
  hasNestedEnums: nestedEnums.length > 0,
3410
- fields: fields.filter(([_fieldName, fieldSchema]) => !!fieldSchema.type).sort((a, b) => a[0].localeCompare(b[0])).map(([fieldName, fieldSchema]) => {
3624
+ fields: fields.filter(
3625
+ (entry) => isNotChoiceDeclarationField(entry[1])
3626
+ ).sort((a, b) => a[0].localeCompare(b[0])).map(([fieldName, field]) => {
3411
3627
  return {
3412
3628
  owner: name,
3413
- schema: fieldSchema,
3629
+ schema: field,
3414
3630
  name: fieldName,
3415
3631
  saveName: this.nameGenerator.generateField(fieldName),
3416
- typeName: this.nameGenerator.generateFieldType(fieldSchema),
3417
- isArray: fieldSchema.array,
3418
- isRequired: fieldSchema.required,
3419
- isEnum: !!fieldSchema.enum,
3420
- isSizeConstrained: fieldSchema.min !== void 0 || fieldSchema.max !== void 0,
3421
- min: fieldSchema.min,
3422
- max: fieldSchema.max,
3423
- isResource: this._createIsResource(fieldSchema.type),
3424
- isComplexType: this._createIsComplexType(fieldSchema.type),
3425
- isPrimitive: this._createIsPrimitiveType(fieldSchema.type),
3426
- isCode: fieldSchema.type?.name === "code",
3427
- isIdentifier: fieldSchema.type?.name === "Identifier",
3428
- isReference: fieldSchema.type?.name === "Reference"
3632
+ typeName: this.nameGenerator.generateFieldType(field),
3633
+ isArray: field.array ?? false,
3634
+ isRequired: field.required ?? false,
3635
+ isEnum: !!field.enum && !field.enum.isOpen,
3636
+ isSizeConstrained: field.min !== void 0 || field.max !== void 0,
3637
+ min: field.min,
3638
+ max: field.max,
3639
+ isResource: this._createIsResource(field.type),
3640
+ isComplexType: this._createIsComplexType(field.type),
3641
+ isPrimitive: this._createIsPrimitiveType(field.type),
3642
+ isCode: field.type?.name === "code",
3643
+ isIdentifier: field.type?.name === "Identifier",
3644
+ isReference: field.type?.name === "Reference"
3429
3645
  };
3430
3646
  })
3431
3647
  };
@@ -3501,11 +3717,11 @@ var ViewModelFactory = class {
3501
3717
  _collectNestedEnums(fields) {
3502
3718
  const nestedEnumValues = {};
3503
3719
  fields.forEach(([fieldName, fieldSchema]) => {
3504
- if ("enum" in fieldSchema && fieldSchema.enum) {
3720
+ if ("enum" in fieldSchema && fieldSchema.enum && !fieldSchema.enum.isOpen) {
3505
3721
  const name = ("binding" in fieldSchema && fieldSchema.binding?.name) ?? fieldName;
3506
3722
  if (typeof name === "string") {
3507
3723
  nestedEnumValues[name] = nestedEnumValues[name] ?? /* @__PURE__ */ new Set();
3508
- fieldSchema.enum?.forEach(nestedEnumValues[name].add.bind(nestedEnumValues[name]));
3724
+ fieldSchema.enum.values.forEach(nestedEnumValues[name].add.bind(nestedEnumValues[name]));
3509
3725
  }
3510
3726
  }
3511
3727
  });
@@ -3734,13 +3950,22 @@ var tsFhirPackageDir = (name) => {
3734
3950
  var tsModuleName = (id) => {
3735
3951
  return uppercaseFirstLetter(normalizeTsName(id.name));
3736
3952
  };
3953
+ var tsProfileModuleName = (tsIndex, schema) => {
3954
+ const resourceSchema = tsIndex.findLastSpecialization(schema);
3955
+ const resourceName = uppercaseFirstLetter(normalizeTsName(resourceSchema.identifier.name));
3956
+ const profileName = extractNameFromCanonical(schema.identifier.url);
3957
+ if (profileName) {
3958
+ return `${resourceName}_${normalizeTsName(profileName)}`;
3959
+ }
3960
+ return `${resourceName}_${normalizeTsName(schema.identifier.name)}`;
3961
+ };
3737
3962
  var tsModuleFileName = (id) => {
3738
3963
  return `${tsModuleName(id)}.ts`;
3739
3964
  };
3965
+ var tsProfileModuleFileName = (tsIndex, schema) => {
3966
+ return `${tsProfileModuleName(tsIndex, schema)}.ts`;
3967
+ };
3740
3968
  var tsModulePath = (id) => {
3741
- if (isProfileIdentifier(id)) {
3742
- return `${tsFhirPackageDir(id.package)}/profiles/${tsModuleName(id)}`;
3743
- }
3744
3969
  return `${tsFhirPackageDir(id.package)}/${tsModuleName(id)}`;
3745
3970
  };
3746
3971
  var canonicalToName3 = (canonical, dropFragment = true) => {
@@ -3752,9 +3977,9 @@ var canonicalToName3 = (canonical, dropFragment = true) => {
3752
3977
  var tsResourceName = (id) => {
3753
3978
  if (id.kind === "nested") {
3754
3979
  const url = id.url;
3755
- const path = canonicalToName3(url, false);
3756
- if (!path) return "";
3757
- const [resourceName, fragment] = path.split("#");
3980
+ const localName = extractNameFromCanonical(url, false);
3981
+ if (!localName) return "";
3982
+ const [resourceName, fragment] = localName.split("#");
3758
3983
  const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
3759
3984
  return normalizeTsName([resourceName, name].join(""));
3760
3985
  }
@@ -3768,14 +3993,37 @@ var tsFieldName = (n) => {
3768
3993
  };
3769
3994
  var normalizeTsName = (n) => {
3770
3995
  if (tsKeywords.has(n)) n = `${n}_`;
3771
- return n.replace(/\[x\]/g, "_x_").replace(/[- :]/g, "_");
3996
+ return n.replace(/\[x\]/g, "_x_").replace(/[- :.]/g, "_");
3772
3997
  };
3773
3998
  var tsGet = (object, tsFieldName2) => {
3774
3999
  if (tsFieldName2.startsWith('"')) return `${object}[${tsFieldName2}]`;
3775
4000
  return `${object}.${tsFieldName2}`;
3776
4001
  };
3777
- var tsEnumType = (enumValues) => {
3778
- return `(${enumValues.map((e) => `"${e}"`).join(" | ")})`;
4002
+ var tsEnumType = (enumDef) => {
4003
+ const values = enumDef.values.map((e) => `"${e}"`).join(" | ");
4004
+ return enumDef.isOpen ? `(${values} | string)` : `(${values})`;
4005
+ };
4006
+ var rewriteFieldTypeDefs = {
4007
+ Coding: { code: () => "T" },
4008
+ // biome-ignore lint: that is exactly string what we want
4009
+ Reference: { reference: () => "`${T}/${string}`" },
4010
+ CodeableConcept: { coding: () => "Coding<T>" }
4011
+ };
4012
+ var resolveFieldTsType = (schemaName, tsName, field) => {
4013
+ const rewriteFieldType = rewriteFieldTypeDefs[schemaName]?.[tsName];
4014
+ if (rewriteFieldType) return rewriteFieldType();
4015
+ if (field.enum) {
4016
+ if (field.type.name === "Coding") return `Coding<${tsEnumType(field.enum)}>`;
4017
+ if (field.type.name === "CodeableConcept") return `CodeableConcept<${tsEnumType(field.enum)}>`;
4018
+ return tsEnumType(field.enum);
4019
+ }
4020
+ if (field.reference && field.reference.length > 0) {
4021
+ const references = field.reference.map((ref) => `"${ref.name}"`).join(" | ");
4022
+ return `Reference<${references}>`;
4023
+ }
4024
+ if (isPrimitiveIdentifier(field.type)) return resolvePrimitiveType(field.type.name);
4025
+ if (isNestedIdentifier(field.type)) return tsResourceName(field.type);
4026
+ return field.type.name;
3779
4027
  };
3780
4028
  var tsTypeFromIdentifier = (id) => {
3781
4029
  if (isNestedIdentifier(id)) return tsResourceName(id);
@@ -3784,8 +4032,12 @@ var tsTypeFromIdentifier = (id) => {
3784
4032
  if (primitiveType !== void 0) return primitiveType;
3785
4033
  return id.name;
3786
4034
  };
3787
- var tsProfileClassName = (id) => {
3788
- return `${uppercaseFirstLetter(normalizeTsName(id.name))}Profile`;
4035
+ var tsProfileClassName = (schema) => {
4036
+ const profileName = extractNameFromCanonical(schema.identifier.url);
4037
+ if (profileName) {
4038
+ return `${normalizeTsName(profileName)}Profile`;
4039
+ }
4040
+ return `${normalizeTsName(schema.identifier.name)}Profile`;
3789
4041
  };
3790
4042
  var tsSliceInputTypeName = (profileName, fieldName, sliceName) => {
3791
4043
  return `${uppercaseFirstLetter(profileName)}_${uppercaseFirstLetter(normalizeTsName(fieldName))}_${uppercaseFirstLetter(normalizeTsName(sliceName))}SliceInput`;
@@ -3821,21 +4073,33 @@ var TypeScript = class extends Writer {
3821
4073
  tsImportType(tsPackageName, ...entities) {
3822
4074
  this.lineSM(`import type { ${entities.join(", ")} } from "${tsPackageName}"`);
3823
4075
  }
3824
- generateProfileIndexFile(profiles) {
3825
- if (profiles.length === 0) return;
4076
+ generateProfileIndexFile(tsIndex, initialProfiles) {
4077
+ if (initialProfiles.length === 0) return;
3826
4078
  this.cd("profiles", () => {
3827
4079
  this.cat("index.ts", () => {
3828
- const seen = /* @__PURE__ */ new Set();
3829
- const uniqueProfiles = profiles.filter((profile) => {
3830
- const className = tsProfileClassName(profile.identifier);
3831
- if (seen.has(className)) return false;
3832
- seen.add(className);
3833
- return true;
4080
+ const profiles = initialProfiles.map((profile) => {
4081
+ const className = tsProfileClassName(profile);
4082
+ const resourceName = tsResourceName(profile.identifier);
4083
+ const overrides = this.detectFieldOverrides(tsIndex, profile);
4084
+ let typeExport;
4085
+ if (overrides.size > 0) typeExport = resourceName;
4086
+ return [profile, className, typeExport];
3834
4087
  });
3835
- if (uniqueProfiles.length === 0) return;
3836
- for (const profile of uniqueProfiles) {
3837
- const className = tsProfileClassName(profile.identifier);
3838
- this.lineSM(`export { ${className} } from "./${tsModuleName(profile.identifier)}"`);
4088
+ if (profiles.length === 0) return;
4089
+ const classExports = /* @__PURE__ */ new Map();
4090
+ const typeExports = /* @__PURE__ */ new Map();
4091
+ for (const [profile, className, typeName] of profiles) {
4092
+ const moduleName = tsProfileModuleName(tsIndex, profile);
4093
+ if (!classExports.has(className)) {
4094
+ classExports.set(className, `export { ${className} } from "./${moduleName}"`);
4095
+ }
4096
+ if (typeName && !typeExports.has(typeName)) {
4097
+ typeExports.set(typeName, `export type { ${typeName} } from "./${moduleName}"`);
4098
+ }
4099
+ }
4100
+ const allExports = [...classExports.values(), ...typeExports.values()].sort();
4101
+ for (const exp of allExports) {
4102
+ this.lineSM(exp);
3839
4103
  }
3840
4104
  });
3841
4105
  });
@@ -3935,8 +4199,9 @@ var TypeScript = class extends Writer {
3935
4199
  }
3936
4200
  generateType(tsIndex, schema) {
3937
4201
  let name;
3938
- if (schema.identifier.name === "Reference") {
3939
- name = "Reference<T extends string = string>";
4202
+ const genericTypes = ["Reference", "Coding", "CodeableConcept"];
4203
+ if (genericTypes.includes(schema.identifier.name)) {
4204
+ name = `${schema.identifier.name}<T extends string = string>`;
3940
4205
  } else if (schema.identifier.kind === "nested") {
3941
4206
  name = tsResourceName(schema.identifier);
3942
4207
  } else {
@@ -3963,23 +4228,10 @@ var TypeScript = class extends Writer {
3963
4228
  const fields = Object.entries(schema.fields).sort((a, b) => a[0].localeCompare(b[0]));
3964
4229
  for (const [fieldName, field] of fields) {
3965
4230
  if (isChoiceDeclarationField(field)) continue;
4231
+ if (!field.type) continue;
3966
4232
  this.debugComment(fieldName, ":", field);
3967
4233
  const tsName = tsFieldName(fieldName);
3968
- let tsType;
3969
- if (field.enum) {
3970
- tsType = tsEnumType(field.enum);
3971
- } else if (schema.identifier.name === "Reference" && tsName === "reference") {
3972
- tsType = "`${T}/${string}`";
3973
- } else if (field.reference && field.reference.length > 0) {
3974
- const references = field.reference.map((ref) => `"${ref.name}"`).join(" | ");
3975
- tsType = `Reference<${references}>`;
3976
- } else if (isPrimitiveIdentifier(field.type)) {
3977
- tsType = resolvePrimitiveType(field.type.name);
3978
- } else if (isNestedIdentifier(field.type)) {
3979
- tsType = tsResourceName(field.type);
3980
- } else {
3981
- tsType = field.type.name;
3982
- }
4234
+ const tsType = resolveFieldTsType(schema.identifier.name, tsName, field);
3983
4235
  const optionalSymbol = field.required ? "" : "?";
3984
4236
  const arraySymbol = field.array ? "[]" : "";
3985
4237
  this.lineSM(`${tsName}${optionalSymbol}: ${tsType}${arraySymbol}`);
@@ -4021,10 +4273,16 @@ var TypeScript = class extends Writer {
4021
4273
  if (!isNotChoiceDeclarationField(field)) {
4022
4274
  throw new Error(`Choice declaration fields not supported for '${fieldName}'`);
4023
4275
  }
4276
+ let tsType;
4024
4277
  if (field.enum) {
4025
- return tsEnumType(field.enum);
4026
- }
4027
- if (field.reference && field.reference.length > 0) {
4278
+ if (field.type?.name === "Coding") {
4279
+ tsType = `Coding<${tsEnumType(field.enum)}>`;
4280
+ } else if (field.type?.name === "CodeableConcept") {
4281
+ tsType = `CodeableConcept<${tsEnumType(field.enum)}>`;
4282
+ } else {
4283
+ tsType = tsEnumType(field.enum);
4284
+ }
4285
+ } else if (field.reference && field.reference.length > 0) {
4028
4286
  const specialization = tsIndex.findLastSpecialization(flatProfile);
4029
4287
  if (!isSpecializationTypeSchema(specialization))
4030
4288
  throw new Error(`Invalid specialization for ${flatProfile.identifier}`);
@@ -4041,20 +4299,20 @@ var TypeScript = class extends Writer {
4041
4299
  }).join(" | ");
4042
4300
  if (sRefs.length === 1 && sRefs[0] === "Resource" && references !== '"Resource"') {
4043
4301
  const cleanRefs = references.replace(/\/\*[^*]*\*\//g, "").trim();
4044
- return `Reference<"Resource" /* ${cleanRefs} */ >`;
4302
+ tsType = `Reference<"Resource" /* ${cleanRefs} */ >`;
4303
+ } else {
4304
+ tsType = `Reference<${references}>`;
4045
4305
  }
4046
- return `Reference<${references}>`;
4047
- }
4048
- if (isNestedIdentifier(field.type)) {
4049
- return tsResourceName(field.type);
4050
- }
4051
- if (isPrimitiveIdentifier(field.type)) {
4052
- return resolvePrimitiveType(field.type.name);
4053
- }
4054
- if (field.type === void 0) {
4306
+ } else if (isPrimitiveIdentifier(field.type)) {
4307
+ tsType = resolvePrimitiveType(field.type.name);
4308
+ } else if (isNestedIdentifier(field.type)) {
4309
+ tsType = tsResourceName(field.type);
4310
+ } else if (field.type === void 0) {
4055
4311
  throw new Error(`Undefined type for '${fieldName}' field at ${typeSchemaInfo(flatProfile)}`);
4312
+ } else {
4313
+ tsType = field.type.name;
4056
4314
  }
4057
- return field.type.name;
4315
+ return tsType;
4058
4316
  }
4059
4317
  generateProfileType(tsIndex, flatProfile) {
4060
4318
  this.debugComment("flatProfile", flatProfile);
@@ -4358,104 +4616,95 @@ var TypeScript = class extends Writer {
4358
4616
  this.lineSM(`import { ${imports.join(", ")} } from "../../profile-helpers"`);
4359
4617
  }
4360
4618
  }
4361
- generateProfileImports(tsIndex, flatProfile) {
4362
- const usedTypes = /* @__PURE__ */ new Map();
4363
- const getModulePath = (typeId) => {
4364
- if (isNestedIdentifier(typeId)) {
4365
- const url = typeId.url;
4366
- const path = canonicalToName3(url, true);
4367
- if (path) {
4368
- return `../../${tsFhirPackageDir(typeId.package)}/${pascalCase(path)}`;
4369
- }
4370
- }
4371
- return `../../${tsModulePath(typeId)}`;
4372
- };
4373
- const addType = (typeId) => {
4374
- if (typeId.kind === "primitive-type") return;
4375
- const tsName = tsResourceName(typeId);
4376
- if (!usedTypes.has(tsName)) {
4377
- usedTypes.set(tsName, {
4378
- importPath: getModulePath(typeId),
4379
- tsName
4380
- });
4381
- }
4382
- };
4383
- addType(flatProfile.base);
4384
- const fields = flatProfile.fields ?? {};
4385
- for (const [_fieldName, field] of Object.entries(fields)) {
4619
+ collectTypesFromSlices(flatProfile, addType) {
4620
+ for (const field of Object.values(flatProfile.fields ?? {})) {
4386
4621
  if (!isNotChoiceDeclarationField(field) || !field.slicing?.slices || !field.type) continue;
4387
- for (const [_sliceName, slice] of Object.entries(field.slicing.slices)) {
4388
- const match = slice.match ?? {};
4389
- if (Object.keys(match).length === 0) continue;
4390
- addType(field.type);
4622
+ for (const slice of Object.values(field.slicing.slices)) {
4623
+ if (Object.keys(slice.match ?? {}).length > 0) {
4624
+ addType(field.type);
4625
+ }
4391
4626
  }
4392
4627
  }
4393
- const extensions = flatProfile.extensions ?? [];
4628
+ }
4629
+ collectTypesFromExtensions(tsIndex, flatProfile, addType) {
4394
4630
  let needsExtensionType = false;
4395
- for (const ext of extensions) {
4631
+ for (const ext of flatProfile.extensions ?? []) {
4396
4632
  if (ext.isComplex && ext.subExtensions) {
4397
4633
  needsExtensionType = true;
4398
4634
  for (const sub of ext.subExtensions) {
4399
- if (sub.valueType) {
4400
- const resolvedType = tsIndex.resolveByUrl(
4401
- flatProfile.identifier.package,
4402
- sub.valueType.url
4403
- );
4404
- if (resolvedType) {
4405
- addType(resolvedType.identifier);
4406
- } else {
4407
- addType(sub.valueType);
4408
- }
4409
- }
4635
+ if (!sub.valueType) continue;
4636
+ const resolvedType = tsIndex.resolveByUrl(
4637
+ flatProfile.identifier.package,
4638
+ sub.valueType.url
4639
+ );
4640
+ addType(resolvedType?.identifier ?? sub.valueType);
4410
4641
  }
4411
4642
  } else if (ext.valueTypes && ext.valueTypes.length === 1) {
4412
4643
  needsExtensionType = true;
4413
- const valueType = ext.valueTypes[0];
4414
- if (valueType) {
4415
- addType(valueType);
4644
+ if (ext.valueTypes[0]) {
4645
+ const resolvedType = tsIndex.resolveByUrl(
4646
+ flatProfile.identifier.package,
4647
+ ext.valueTypes[0].url
4648
+ );
4649
+ addType(resolvedType?.identifier ?? ext.valueTypes[0]);
4416
4650
  }
4417
4651
  } else {
4418
4652
  needsExtensionType = true;
4419
4653
  }
4420
4654
  }
4421
- if (needsExtensionType) {
4422
- const extensionUrl = "http://hl7.org/fhir/StructureDefinition/Extension";
4423
- const extensionSchema = tsIndex.resolveByUrl(flatProfile.identifier.package, extensionUrl);
4424
- if (extensionSchema) {
4425
- addType(extensionSchema.identifier);
4426
- }
4427
- }
4655
+ return needsExtensionType;
4656
+ }
4657
+ collectTypesFromFieldOverrides(tsIndex, flatProfile, addType) {
4428
4658
  const referenceUrl = "http://hl7.org/fhir/StructureDefinition/Reference";
4429
4659
  const referenceSchema = tsIndex.resolveByUrl(flatProfile.identifier.package, referenceUrl);
4430
4660
  const specialization = tsIndex.findLastSpecialization(flatProfile);
4431
- if (isSpecializationTypeSchema(specialization)) {
4432
- for (const [fieldName, pField] of Object.entries(flatProfile.fields ?? {})) {
4433
- if (!isNotChoiceDeclarationField(pField)) continue;
4434
- const sField = specialization.fields?.[fieldName];
4435
- if (!sField || isChoiceDeclarationField(sField)) continue;
4436
- if (pField.reference && sField.reference && pField.reference.length < sField.reference.length) {
4437
- if (referenceSchema) {
4438
- addType(referenceSchema.identifier);
4439
- }
4440
- } else if (pField.required && !sField.required) {
4441
- if (pField.type) {
4442
- addType(pField.type);
4443
- }
4444
- }
4661
+ if (!isSpecializationTypeSchema(specialization)) return;
4662
+ for (const [fieldName, pField] of Object.entries(flatProfile.fields ?? {})) {
4663
+ if (!isNotChoiceDeclarationField(pField)) continue;
4664
+ const sField = specialization.fields?.[fieldName];
4665
+ if (!sField || isChoiceDeclarationField(sField)) continue;
4666
+ if (pField.reference && sField.reference && pField.reference.length < sField.reference.length) {
4667
+ if (referenceSchema) addType(referenceSchema.identifier);
4668
+ } else if (pField.required && !sField.required && pField.type) {
4669
+ addType(pField.type);
4670
+ }
4671
+ }
4672
+ }
4673
+ generateProfileImports(tsIndex, flatProfile) {
4674
+ const usedTypes = /* @__PURE__ */ new Map();
4675
+ const getModulePath = (typeId) => {
4676
+ if (isNestedIdentifier(typeId)) {
4677
+ const path = canonicalToName3(typeId.url, true);
4678
+ if (path) return `../../${tsFhirPackageDir(typeId.package)}/${pascalCase(path)}`;
4679
+ }
4680
+ return `../../${tsModulePath(typeId)}`;
4681
+ };
4682
+ const addType = (typeId) => {
4683
+ if (typeId.kind === "primitive-type") return;
4684
+ const tsName = tsResourceName(typeId);
4685
+ if (!usedTypes.has(tsName)) {
4686
+ usedTypes.set(tsName, { importPath: getModulePath(typeId), tsName });
4445
4687
  }
4688
+ };
4689
+ addType(flatProfile.base);
4690
+ this.collectTypesFromSlices(flatProfile, addType);
4691
+ const needsExtensionType = this.collectTypesFromExtensions(tsIndex, flatProfile, addType);
4692
+ this.collectTypesFromFieldOverrides(tsIndex, flatProfile, addType);
4693
+ if (needsExtensionType) {
4694
+ const extensionUrl = "http://hl7.org/fhir/StructureDefinition/Extension";
4695
+ const extensionSchema = tsIndex.resolveByUrl(flatProfile.identifier.package, extensionUrl);
4696
+ if (extensionSchema) addType(extensionSchema.identifier);
4446
4697
  }
4447
4698
  const sortedImports = Array.from(usedTypes.values()).sort((a, b) => a.tsName.localeCompare(b.tsName));
4448
4699
  for (const { importPath, tsName } of sortedImports) {
4449
4700
  this.tsImportType(importPath, tsName);
4450
4701
  }
4451
- if (sortedImports.length > 0) {
4452
- this.line();
4453
- }
4702
+ if (sortedImports.length > 0) this.line();
4454
4703
  }
4455
4704
  generateProfileClass(tsIndex, flatProfile) {
4456
4705
  const tsBaseResourceName = tsTypeFromIdentifier(flatProfile.base);
4457
4706
  const tsProfileName = tsResourceName(flatProfile.identifier);
4458
- const profileClassName = tsProfileClassName(flatProfile.identifier);
4707
+ const profileClassName = tsProfileClassName(flatProfile);
4459
4708
  const polymorphicBaseNames = /* @__PURE__ */ new Set([
4460
4709
  "value",
4461
4710
  "effective",
@@ -4887,7 +5136,7 @@ var TypeScript = class extends Writer {
4887
5136
  generateResourceModule(tsIndex, schema) {
4888
5137
  if (isProfileTypeSchema(schema)) {
4889
5138
  this.cd("profiles", () => {
4890
- this.cat(`${tsModuleFileName(schema.identifier)}`, () => {
5139
+ this.cat(`${tsProfileModuleFileName(tsIndex, schema)}`, () => {
4891
5140
  this.generateDisclaimer();
4892
5141
  const flatProfile = tsIndex.flatProfile(schema);
4893
5142
  this.generateProfileImports(tsIndex, flatProfile);
@@ -4937,7 +5186,7 @@ var TypeScript = class extends Writer {
4937
5186
  for (const schema of packageSchemas) {
4938
5187
  this.generateResourceModule(tsIndex, schema);
4939
5188
  }
4940
- this.generateProfileIndexFile(packageSchemas.filter(isProfileTypeSchema));
5189
+ this.generateProfileIndexFile(tsIndex, packageSchemas.filter(isProfileTypeSchema));
4941
5190
  this.generateFhirPackageIndexFile(packageSchemas);
4942
5191
  });
4943
5192
  }
@@ -4994,7 +5243,8 @@ var APIBuilder = class {
4994
5243
  treeShake: void 0,
4995
5244
  promoteLogical: void 0,
4996
5245
  registry: void 0,
4997
- logLevel: parseLogLevel("INFO")
5246
+ logLevel: parseLogLevel("INFO"),
5247
+ dropCanonicalManagerCache: false
4998
5248
  };
4999
5249
  const opts = {
5000
5250
  ...defaultOpts,
@@ -5016,7 +5266,8 @@ var APIBuilder = class {
5016
5266
  this.manager = userOpts.manager ?? CanonicalManager({
5017
5267
  packages: [],
5018
5268
  workingDir: ".codegen-cache/canonical-manager-cache",
5019
- registry: userOpts.registry
5269
+ registry: userOpts.registry,
5270
+ dropCache: userOpts.dropCanonicalManagerCache
5020
5271
  });
5021
5272
  this.logger = userOpts.logger ?? createLogger({ prefix: "API", level: opts.logLevel });
5022
5273
  this.options = opts;
@@ -5030,14 +5281,6 @@ var APIBuilder = class {
5030
5281
  this.managerInput.npmPackages.push(packageRef);
5031
5282
  return this;
5032
5283
  }
5033
- /**
5034
- * Set a custom FHIR package registry URL
5035
- * @param url The registry URL (default: https://fs.get-ig.org/pkgs/)
5036
- */
5037
- registry(url) {
5038
- this.options.registry = url;
5039
- return this;
5040
- }
5041
5284
  localStructureDefinitions(config) {
5042
5285
  this.logger.info(`Registering local StructureDefinitions for ${config.package.name}@${config.package.version}`);
5043
5286
  this.managerInput.localSDs.push({
@@ -5241,10 +5484,11 @@ var APIBuilder = class {
5241
5484
  focusedPackages: packageMetas
5242
5485
  });
5243
5486
  }
5244
- const typeSchemas = await generateTypeSchemas(register, this.logger);
5487
+ const { schemas: typeSchemas, collisions } = await generateTypeSchemas(register, this.logger);
5245
5488
  const tsIndexOpts = {
5246
5489
  register,
5247
- logger: this.logger
5490
+ logger: this.logger,
5491
+ irReport: Object.keys(collisions).length > 0 ? { collisions } : {}
5248
5492
  };
5249
5493
  let tsIndex = mkTypeSchemaIndex(typeSchemas, tsIndexOpts);
5250
5494
  if (this.options.treeShake) tsIndex = treeShake(tsIndex, this.options.treeShake);
@@ -5298,6 +5542,6 @@ var APIBuilder = class {
5298
5542
  }
5299
5543
  };
5300
5544
 
5301
- export { APIBuilder, LogLevel, prettyReport };
5545
+ export { APIBuilder, LogLevel, prettyReport, registerFromPackageMetas };
5302
5546
  //# sourceMappingURL=index.js.map
5303
5547
  //# sourceMappingURL=index.js.map