@atomic-ehr/codegen 0.0.6 → 0.0.7-canary.20260224101452.ccac84d

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;
@@ -2188,21 +2206,6 @@ function extractFieldDependencies(fields) {
2188
2206
  }
2189
2207
  return deps;
2190
2208
  }
2191
- function isExtensionSchema(fhirSchema, _identifier) {
2192
- if (fhirSchema.base === "Extension" || fhirSchema.base === "http://hl7.org/fhir/StructureDefinition/Extension") {
2193
- return true;
2194
- }
2195
- if (fhirSchema.url?.includes("/extension/") || fhirSchema.url?.includes("-extension")) {
2196
- return true;
2197
- }
2198
- if (fhirSchema.name?.toLowerCase().includes("extension")) {
2199
- return true;
2200
- }
2201
- if (fhirSchema.type === "Extension") {
2202
- return true;
2203
- }
2204
- return false;
2205
- }
2206
2209
  async function transformValueSet(register, valueSet, logger) {
2207
2210
  if (!valueSet.url) throw new Error("ValueSet URL is required");
2208
2211
  const identifier = mkValueSetIdentifierByUrl(register, valueSet.package_meta, valueSet.url);
@@ -2284,15 +2287,13 @@ function extractExtensionValueTypes(register, fhirSchema, extensionUrl, logger)
2284
2287
  const uniq = new Map(valueTypes.map((type) => [type.url, type]));
2285
2288
  return Array.from(uniq.values());
2286
2289
  }
2287
- function extractSubExtensions(register, fhirSchema, extensionUrl, logger) {
2288
- const extensionSchema = register.resolveFs(fhirSchema.package_meta, extensionUrl);
2289
- if (!extensionSchema?.elements) return void 0;
2290
+ var extractLegacySubExtensions = (register, extensionSchema, logger) => {
2290
2291
  const subExtensions = [];
2292
+ if (!extensionSchema.elements) return subExtensions;
2291
2293
  for (const [key, element] of Object.entries(extensionSchema.elements)) {
2292
2294
  if (!key.startsWith("extension:")) continue;
2293
2295
  const sliceName = key.split(":")[1];
2294
2296
  if (!sliceName) continue;
2295
- const sliceUrl = element.url ?? sliceName;
2296
2297
  let valueType;
2297
2298
  for (const [elemKey, elemValue] of Object.entries(element.elements ?? {})) {
2298
2299
  if (elemValue.choiceOf !== "value" && !elemKey.startsWith("value")) continue;
@@ -2301,48 +2302,57 @@ function extractSubExtensions(register, fhirSchema, extensionUrl, logger) {
2301
2302
  }
2302
2303
  subExtensions.push({
2303
2304
  name: sliceName,
2304
- url: sliceUrl,
2305
+ url: element.url ?? sliceName,
2305
2306
  valueType,
2306
2307
  min: element.min,
2307
2308
  max: element.max !== void 0 ? String(element.max) : void 0
2308
2309
  });
2309
2310
  }
2310
- const extensionElement = extensionSchema.elements.extension;
2311
+ return subExtensions;
2312
+ };
2313
+ var extractSlicingSubExtensions = (extensionSchema) => {
2314
+ const subExtensions = [];
2315
+ const extensionElement = extensionSchema.elements?.extension;
2311
2316
  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
- }
2317
+ if (!slices || typeof slices !== "object") return subExtensions;
2318
+ for (const [sliceName, sliceData] of Object.entries(slices)) {
2319
+ const slice = sliceData;
2320
+ const schema = slice.schema;
2321
+ if (!schema) continue;
2322
+ let valueType;
2323
+ for (const [elemKey, elemValue] of Object.entries(schema.elements ?? {})) {
2324
+ const elem = elemValue;
2325
+ if (elem.choiceOf !== "value" && !elemKey.startsWith("value")) continue;
2326
+ if (elem.type) {
2327
+ valueType = {
2328
+ kind: "complex-type",
2329
+ package: extensionSchema.package_meta.name,
2330
+ version: extensionSchema.package_meta.version,
2331
+ name: elem.type,
2332
+ url: `http://hl7.org/fhir/StructureDefinition/${elem.type}`
2333
+ };
2334
+ break;
2333
2335
  }
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
2336
  }
2337
+ subExtensions.push({
2338
+ name: sliceName,
2339
+ url: slice.match?.url ?? sliceName,
2340
+ valueType,
2341
+ min: schema._required ? 1 : schema.min ?? 0,
2342
+ // biome-ignore lint/style/noNestedTernary : okay here
2343
+ max: schema.max !== void 0 ? String(schema.max) : schema.array ? "*" : "1"
2344
+ });
2343
2345
  }
2346
+ return subExtensions;
2347
+ };
2348
+ var extractSubExtensions = (register, fhirSchema, extensionUrl, logger) => {
2349
+ const extensionSchema = register.resolveFs(fhirSchema.package_meta, extensionUrl);
2350
+ if (!extensionSchema?.elements) return void 0;
2351
+ const legacySubs = extractLegacySubExtensions(register, extensionSchema, logger);
2352
+ const slicingSubs = extractSlicingSubExtensions(extensionSchema);
2353
+ const subExtensions = [...legacySubs, ...slicingSubs];
2344
2354
  return subExtensions.length > 0 ? subExtensions : void 0;
2345
- }
2355
+ };
2346
2356
  function extractProfileExtensions(register, fhirSchema, logger) {
2347
2357
  const extensions = [];
2348
2358
  const addExtensionEntry = (path, name, schema) => {
@@ -2387,268 +2397,67 @@ function extractProfileExtensions(register, fhirSchema, logger) {
2387
2397
  return extensions;
2388
2398
  }
2389
2399
  async function transformFhirSchema(register, fhirSchema, logger) {
2390
- const schemas = transformFhirSchemaResource(register, fhirSchema, logger);
2391
- if (isExtensionSchema(fhirSchema, mkIdentifier(fhirSchema))) {
2392
- const schema = schemas[0];
2393
- if (!schema) throw new Error(`Expected schema to be defined`);
2394
- schema.metadata = {
2395
- isExtension: true
2396
- // Mark as extension for file organization
2397
- };
2398
- }
2399
- return schemas;
2400
+ return transformFhirSchemaResource(register, fhirSchema, logger);
2400
2401
  }
2401
2402
 
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
- })
2403
+ // src/typeschema/index.ts
2404
+ var deduplicateSchemas = (schemasWithSources, logger) => {
2405
+ const groups = {};
2406
+ for (const item of schemasWithSources) {
2407
+ const key = `${item.schema.identifier.url}|${item.schema.identifier.package}`;
2408
+ const hash = hashSchema(item.schema);
2409
+ groups[key] ??= {};
2410
+ groups[key][hash] ??= { typeSchema: item.schema, sources: [] };
2411
+ groups[key][hash].sources.push(item);
2412
+ }
2413
+ const schemas = [];
2414
+ const collisions = {};
2415
+ for (const versions of Object.values(groups)) {
2416
+ const sorted = Object.values(versions).sort((a, b) => b.sources.length - a.sources.length);
2417
+ const best = sorted[0];
2418
+ if (!best) continue;
2419
+ schemas.push(best.typeSchema);
2420
+ if (sorted.length > 1) {
2421
+ const pkg = best.typeSchema.identifier.package;
2422
+ const url = best.typeSchema.identifier.url;
2423
+ logger?.dryWarn(`'${url}' from '${pkg}'' has ${sorted.length} versions`);
2424
+ collisions[pkg] ??= {};
2425
+ collisions[pkg][url] = sorted.flatMap(
2426
+ (v) => v.sources.map((s) => ({
2427
+ typeSchema: v.typeSchema,
2428
+ sourcePackage: s.sourcePackage,
2429
+ sourceCanonical: s.sourceCanonical
2430
+ }))
2587
2431
  );
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
2432
  }
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
- }
2626
- return elem;
2627
- }).filter((elem) => elem !== void 0);
2433
+ }
2434
+ return { schemas, collisions };
2628
2435
  };
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
2436
  var generateTypeSchemas = async (register, logger) => {
2638
- const fhirSchemas = [];
2437
+ const schemasWithSources = [];
2639
2438
  for (const fhirSchema of register.allFs()) {
2640
2439
  const pkgId = packageMetaToFhir(fhirSchema.package_meta);
2641
2440
  const skipCheck = shouldSkipCanonical(fhirSchema.package_meta, fhirSchema.url);
2642
2441
  if (skipCheck.shouldSkip) {
2643
- logger?.dry_warn(`Skip ${fhirSchema.url} from ${pkgId}. Reason: ${skipCheck.reason}`);
2442
+ logger?.dryWarn(`Skip ${fhirSchema.url} from ${pkgId}. Reason: ${skipCheck.reason}`);
2644
2443
  continue;
2645
2444
  }
2646
- fhirSchemas.push(...await transformFhirSchema(register, fhirSchema, logger));
2445
+ for (const schema of await transformFhirSchema(register, fhirSchema, logger)) {
2446
+ schemasWithSources.push({
2447
+ schema,
2448
+ sourcePackage: pkgId,
2449
+ sourceCanonical: fhirSchema.url
2450
+ });
2451
+ }
2647
2452
  }
2648
2453
  for (const vsSchema of register.allVs()) {
2649
- fhirSchemas.push(await transformValueSet(register, vsSchema));
2454
+ schemasWithSources.push({
2455
+ schema: await transformValueSet(register, vsSchema),
2456
+ sourcePackage: packageMetaToFhir(vsSchema.package_meta),
2457
+ sourceCanonical: vsSchema.url
2458
+ });
2650
2459
  }
2651
- return fhirSchemas;
2460
+ return deduplicateSchemas(schemasWithSources, logger);
2652
2461
  };
2653
2462
 
2654
2463
  // src/typeschema/ir/logic-promotion.ts
@@ -2829,38 +2638,316 @@ var treeShake = (tsIndex, treeShake2) => {
2829
2638
  for (const schema of schemas) {
2830
2639
  acc[JSON.stringify(schema.identifier)] = schema;
2831
2640
  }
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);
2641
+ const newSchemas = [];
2642
+ for (const schema of schemas) {
2643
+ if (isSpecializationTypeSchema(schema) || isProfileTypeSchema(schema)) {
2644
+ if (!schema.dependencies) continue;
2645
+ schema.dependencies.forEach((dep) => {
2646
+ const depSchema = tsIndex.resolve(dep);
2647
+ if (!depSchema)
2648
+ throw new Error(
2649
+ `Dependent schema ${JSON.stringify(dep)} not found for ${JSON.stringify(schema.identifier)}`
2650
+ );
2651
+ const id = JSON.stringify(depSchema.identifier);
2652
+ if (!acc[id]) newSchemas.push(depSchema);
2653
+ });
2654
+ if (schema.nested) {
2655
+ for (const nest of schema.nested) {
2656
+ if (isNestedIdentifier(nest.identifier)) continue;
2657
+ const id = JSON.stringify(nest.identifier);
2658
+ if (!acc[id]) newSchemas.push(nest);
2659
+ }
2660
+ }
2661
+ }
2662
+ }
2663
+ return collectDeps(newSchemas, acc);
2664
+ };
2665
+ const shaked = collectDeps(focusedSchemas, {});
2666
+ const shakedIndex = tsIndex.replaceSchemas(shaked);
2667
+ const treeShakeReport = { skippedPackages: [], packages: {} };
2668
+ const irReport = shakedIndex.irReport();
2669
+ irReport.treeShake = treeShakeReport;
2670
+ mutableFillReport(treeShakeReport, tsIndex, shakedIndex);
2671
+ return shakedIndex;
2672
+ };
2673
+
2674
+ // src/fhir-types/hl7-fhir-r4-core/CodeSystem.ts
2675
+ var isCodeSystem = (resource) => {
2676
+ return resource !== null && typeof resource === "object" && resource.resourceType === "CodeSystem";
2677
+ };
2678
+
2679
+ // src/fhir-types/hl7-fhir-r4-core/ValueSet.ts
2680
+ var isValueSet = (resource) => {
2681
+ return resource !== null && typeof resource === "object" && resource.resourceType === "ValueSet";
2682
+ };
2683
+
2684
+ // src/typeschema/register.ts
2685
+ var readPackageDependencies = async (manager, packageMeta2) => {
2686
+ const packageJSON = await manager.packageJson(packageMeta2.name);
2687
+ if (!packageJSON) return [];
2688
+ const dependencies = packageJSON.dependencies;
2689
+ if (dependencies !== void 0) {
2690
+ return Object.entries(dependencies).map(([name, version]) => {
2691
+ return { name, version };
2692
+ });
2693
+ }
2694
+ return [];
2695
+ };
2696
+ var mkEmptyPkgIndex = (pkg) => {
2697
+ return {
2698
+ pkg,
2699
+ canonicalResolution: {},
2700
+ fhirSchemas: {},
2701
+ valueSets: {}
2702
+ };
2703
+ };
2704
+ var mkPackageAwareResolver = async (manager, pkg, deep, acc, logger) => {
2705
+ const pkgId = packageMetaToFhir(pkg);
2706
+ logger?.info(`${" ".repeat(deep * 2)}+ ${pkgId}`);
2707
+ if (acc[pkgId]) return acc[pkgId];
2708
+ const index = mkEmptyPkgIndex(pkg);
2709
+ for (const resource of await manager.search({ package: pkg })) {
2710
+ const rawUrl = resource.url;
2711
+ if (!rawUrl) continue;
2712
+ if (!(isStructureDefinition(resource) || isValueSet(resource) || isCodeSystem(resource))) continue;
2713
+ const url = rawUrl;
2714
+ if (index.canonicalResolution[url]) logger?.dryWarn(`Duplicate canonical URL: ${url} at ${pkgId}.`);
2715
+ index.canonicalResolution[url] = [{ deep, pkg, pkgId, resource }];
2716
+ }
2717
+ const deps = await readPackageDependencies(manager, pkg);
2718
+ for (const depPkg of deps) {
2719
+ const { canonicalResolution } = await mkPackageAwareResolver(manager, depPkg, deep + 1, acc, logger);
2720
+ for (const [surl, resolutions] of Object.entries(canonicalResolution)) {
2721
+ const url = surl;
2722
+ index.canonicalResolution[url] = [...index.canonicalResolution[url] || [], ...resolutions];
2723
+ }
2724
+ }
2725
+ for (const resolutionOptions of Object.values(index.canonicalResolution)) {
2726
+ resolutionOptions.sort((a, b) => a.deep - b.deep);
2727
+ }
2728
+ acc[pkgId] = index;
2729
+ return index;
2730
+ };
2731
+ var enrichResolver = (resolver, logger) => {
2732
+ for (const { pkg, canonicalResolution } of Object.values(resolver)) {
2733
+ const pkgId = packageMetaToFhir(pkg);
2734
+ if (!resolver[pkgId]) throw new Error(`Package ${pkgId} not found`);
2735
+ for (const [_url, options] of Object.entries(canonicalResolution)) {
2736
+ const resolition = options[0];
2737
+ if (!resolition) throw new Error(`Resource not found`);
2738
+ const resource = resolition.resource;
2739
+ const resourcePkg = resolition.pkg;
2740
+ if (isStructureDefinition(resource)) {
2741
+ const fs7 = fhirschema.translate(resource);
2742
+ const rfs = enrichFHIRSchema(fs7, resourcePkg);
2743
+ resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2744
+ }
2745
+ if (isValueSet(resource)) {
2746
+ const rvs = enrichValueSet(resource, resourcePkg);
2747
+ resolver[pkgId].valueSets[rvs.url] = rvs;
2748
+ }
2749
+ }
2750
+ }
2751
+ };
2752
+ var packageAgnosticResolveCanonical = (resolver, url, _logger) => {
2753
+ const options = Object.values(resolver).flatMap((pkg) => pkg.canonicalResolution[url]);
2754
+ if (!options) throw new Error(`No canonical resolution found for ${url} in any package`);
2755
+ return options[0]?.resource;
2756
+ };
2757
+ var registerFromManager = async (manager, { logger, focusedPackages }) => {
2758
+ const packages = focusedPackages ?? await manager.packages();
2759
+ const resolver = {};
2760
+ for (const pkg of packages) {
2761
+ await mkPackageAwareResolver(manager, pkg, 0, resolver, logger);
2762
+ }
2763
+ enrichResolver(resolver);
2764
+ const resolveFs = (pkg, canonicalUrl) => {
2765
+ const pkgIndex = resolver[packageMetaToFhir(pkg)];
2766
+ if (pkgIndex) {
2767
+ const resolution = pkgIndex.canonicalResolution[canonicalUrl]?.[0];
2768
+ if (resolution) {
2769
+ return resolver[resolution.pkgId]?.fhirSchemas[canonicalUrl];
2770
+ }
2771
+ }
2772
+ for (const idx of Object.values(resolver)) {
2773
+ const fs7 = idx.fhirSchemas[canonicalUrl];
2774
+ if (fs7 && fs7.package_meta.name === pkg.name) return fs7;
2775
+ }
2776
+ for (const idx of Object.values(resolver)) {
2777
+ const fs7 = idx.fhirSchemas[canonicalUrl];
2778
+ if (fs7) return fs7;
2779
+ }
2780
+ return void 0;
2781
+ };
2782
+ const resolveVs = (pkg, canonicalUrl) => {
2783
+ const pkgIndex = resolver[packageMetaToFhir(pkg)];
2784
+ if (pkgIndex) {
2785
+ const resolution = pkgIndex.canonicalResolution[canonicalUrl]?.[0];
2786
+ if (resolution) {
2787
+ return resolver[resolution.pkgId]?.valueSets[canonicalUrl];
2788
+ }
2789
+ }
2790
+ for (const idx of Object.values(resolver)) {
2791
+ const vs = idx.valueSets[canonicalUrl];
2792
+ if (vs && vs.package_meta.name === pkg.name) return vs;
2793
+ }
2794
+ for (const idx of Object.values(resolver)) {
2795
+ const vs = idx.valueSets[canonicalUrl];
2796
+ if (vs) return vs;
2797
+ }
2798
+ return void 0;
2799
+ };
2800
+ const ensureSpecializationCanonicalUrl = (name) => {
2801
+ if (name.includes("|")) name = name.split("|")[0];
2802
+ if (name.match(/^[a-zA-Z0-9]+$/)) {
2803
+ return `http://hl7.org/fhir/StructureDefinition/${name}`;
2804
+ }
2805
+ return name;
2806
+ };
2807
+ const resolveFsGenealogy = (pkg, canonicalUrl) => {
2808
+ let fs7 = resolveFs(pkg, canonicalUrl);
2809
+ if (fs7 === void 0) throw new Error(`Failed to resolve FHIR Schema: '${canonicalUrl}'`);
2810
+ const genealogy = [fs7];
2811
+ while (fs7?.base) {
2812
+ const pkg2 = fs7.package_meta;
2813
+ const baseUrl = ensureSpecializationCanonicalUrl(fs7.base);
2814
+ fs7 = resolveFs(pkg2, baseUrl);
2815
+ if (fs7 === void 0)
2816
+ throw new Error(
2817
+ `Failed to resolve FHIR Schema base for '${canonicalUrl}'. Problem: '${baseUrl}' from '${packageMetaToFhir(pkg2)}'`
2818
+ );
2819
+ genealogy.push(fs7);
2820
+ }
2821
+ return genealogy;
2822
+ };
2823
+ const resolveFsSpecializations = (pkg, canonicalUrl) => {
2824
+ return resolveFsGenealogy(pkg, canonicalUrl).filter((fs7) => fs7.derivation === "specialization");
2825
+ };
2826
+ const resolveElementSnapshot = (fhirSchema, path) => {
2827
+ const geneology = resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url);
2828
+ const elemGeneology = resolveFsElementGenealogy(geneology, path);
2829
+ const elemSnapshot = fsElementSnapshot(elemGeneology);
2830
+ return elemSnapshot;
2831
+ };
2832
+ const getAllElementKeys = (elems) => {
2833
+ const keys = /* @__PURE__ */ new Set();
2834
+ for (const [key, elem] of Object.entries(elems)) {
2835
+ keys.add(key);
2836
+ for (const choiceKey of elem?.choices || []) {
2837
+ if (!elems[choiceKey]) {
2838
+ keys.add(choiceKey);
2839
+ }
2840
+ }
2841
+ }
2842
+ return Array.from(keys);
2843
+ };
2844
+ let cachedResolutionTree;
2845
+ return {
2846
+ testAppendFs(rfs) {
2847
+ const pkgId = packageMetaToFhir(rfs.package_meta);
2848
+ if (!resolver[pkgId]) resolver[pkgId] = mkEmptyPkgIndex(rfs.package_meta);
2849
+ resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2850
+ cachedResolutionTree = void 0;
2851
+ },
2852
+ resolveFs,
2853
+ resolveFsGenealogy,
2854
+ resolveFsSpecializations,
2855
+ ensureSpecializationCanonicalUrl,
2856
+ resolveSd: (pkg, canonicalUrl) => {
2857
+ const res = resolver[packageMetaToFhir(pkg)]?.canonicalResolution[canonicalUrl]?.[0]?.resource;
2858
+ if (isStructureDefinition(res)) return res;
2859
+ return void 0;
2860
+ },
2861
+ allSd: () => Object.values(resolver).flatMap(
2862
+ (pkgIndex) => Object.values(pkgIndex.canonicalResolution).flatMap(
2863
+ (resolutions) => resolutions.map((r) => {
2864
+ const sd = r.resource;
2865
+ if (!sd.package_name) {
2866
+ return {
2867
+ ...sd,
2868
+ package_name: pkgIndex.pkg.name,
2869
+ package_version: pkgIndex.pkg.version
2870
+ };
2871
+ }
2872
+ return sd;
2873
+ })
2874
+ )
2875
+ ).filter((r) => isStructureDefinition(r)).sort((sd1, sd2) => sd1.url.localeCompare(sd2.url)),
2876
+ patchSd: (fn) => {
2877
+ Object.values(resolver).flatMap(
2878
+ (pkgIndex) => Object.values(pkgIndex.canonicalResolution).forEach((resolutions) => {
2879
+ resolutions.forEach((e) => {
2880
+ if (isStructureDefinition(e.resource)) {
2881
+ const sd = e.resource;
2882
+ const newSd = fn(pkgIndex.pkg, sd);
2883
+ if (sd.url !== newSd.url)
2884
+ throw new Error(`Patch update StructureDefinition URL: ${sd.url} !== ${newSd.url}`);
2885
+ e.resource = newSd;
2886
+ }
2887
+ });
2888
+ })
2889
+ );
2890
+ enrichResolver(resolver);
2891
+ cachedResolutionTree = void 0;
2892
+ },
2893
+ allFs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.fhirSchemas)),
2894
+ allVs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.valueSets)),
2895
+ resolveVs,
2896
+ resolveAny: (canonicalUrl) => packageAgnosticResolveCanonical(resolver, canonicalUrl),
2897
+ resolveElementSnapshot,
2898
+ getAllElementKeys,
2899
+ resolver,
2900
+ resolutionTree: () => {
2901
+ if (cachedResolutionTree) return cachedResolutionTree;
2902
+ const res = {};
2903
+ for (const [_pkgId, pkgIndex] of Object.entries(resolver)) {
2904
+ const pkgName = pkgIndex.pkg.name;
2905
+ res[pkgName] = {};
2906
+ for (const [surl, resolutions] of Object.entries(pkgIndex.canonicalResolution)) {
2907
+ const url = surl;
2908
+ res[pkgName][url] = [];
2909
+ for (const resolution of resolutions) {
2910
+ res[pkgName][url].push({ deep: resolution.deep, pkg: resolution.pkg });
2850
2911
  }
2851
2912
  }
2852
2913
  }
2914
+ cachedResolutionTree = res;
2915
+ return res;
2853
2916
  }
2854
- return collectDeps(newSchemas, acc);
2855
2917
  };
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
2918
  };
2919
+ var registerFromPackageMetas = async (packageMetas, conf) => {
2920
+ const packageNames = packageMetas.map(packageMetaToNpm);
2921
+ conf?.logger?.step(`Loading FHIR packages: ${packageNames.join(", ")}`);
2922
+ const manager = CanonicalManager({
2923
+ packages: packageNames,
2924
+ workingDir: "tmp/fhir",
2925
+ registry: conf.registry || void 0
2926
+ });
2927
+ await manager.init();
2928
+ return await registerFromManager(manager, {
2929
+ ...conf,
2930
+ focusedPackages: packageMetas
2931
+ });
2932
+ };
2933
+ var resolveFsElementGenealogy = (genealogy, path) => {
2934
+ const [top, ...rest] = path;
2935
+ if (top === void 0) return [];
2936
+ return genealogy.map((fs7) => {
2937
+ if (!fs7.elements) return void 0;
2938
+ let elem = fs7.elements?.[top];
2939
+ for (const k of rest) {
2940
+ elem = elem?.elements?.[k];
2941
+ }
2942
+ return elem;
2943
+ }).filter((elem) => elem !== void 0);
2944
+ };
2945
+ function fsElementSnapshot(genealogy) {
2946
+ const revGenealogy = genealogy.reverse();
2947
+ const snapshot = Object.assign({}, ...revGenealogy);
2948
+ snapshot.elements = void 0;
2949
+ return snapshot;
2950
+ }
2864
2951
  var normalizeFileName = (str) => {
2865
2952
  const res = str.replace(/[^a-zA-Z0-9\-_.@#()]/g, "");
2866
2953
  if (res.length === 0) return "unknown";
@@ -2902,23 +2989,60 @@ var IntrospectionWriter = class extends FileSystemWriter {
2902
2989
  this.logger()?.info(`IntrospectionWriter: Type tree written to ${this.opts.typeTree}`);
2903
2990
  }
2904
2991
  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);
2992
+ if (Path5.extname(this.opts.typeSchemas) === ".ndjson") {
2993
+ this.writeNdjson(tsIndex.schemas, this.opts.typeSchemas, typeSchemaToJson);
2909
2994
  } else {
2910
- this.writeJsonFiles(
2911
- typeSchemas.map((ts) => typeSchemaToJson(ts, true)),
2912
- outputPath
2913
- );
2995
+ const items = tsIndex.schemas.map((ts) => typeSchemaToJson(ts, true));
2996
+ const seenFilenames = /* @__PURE__ */ new Set();
2997
+ const dedupedItems = items.filter((item) => {
2998
+ if (seenFilenames.has(item.filename)) return false;
2999
+ seenFilenames.add(item.filename);
3000
+ return true;
3001
+ });
3002
+ this.cd(this.opts.typeSchemas, () => {
3003
+ for (const { filename, genContent } of dedupedItems) {
3004
+ const fileName = `${filename}.json`;
3005
+ this.cd(Path5.dirname(fileName), () => {
3006
+ this.cat(Path5.basename(fileName), () => {
3007
+ this.write(genContent());
3008
+ });
3009
+ });
3010
+ }
3011
+ for (const [pkg, canonicals] of Object.entries(tsIndex.irReport().collisions ?? {})) {
3012
+ this.cd(`${normalizeFileName(pkg)}`, () => {
3013
+ for (const [canonical, entries] of Object.entries(canonicals)) {
3014
+ if (entries.length <= 1) continue;
3015
+ const firstEntry = entries[0];
3016
+ assert3(firstEntry);
3017
+ const name = normalizeFileName(
3018
+ `${firstEntry.typeSchema.identifier.name}(${extractNameFromCanonical(canonical)})`
3019
+ );
3020
+ this.cd(Path5.join("collisions", name), () => {
3021
+ for (let i = 0; i < entries.length; i++) {
3022
+ const entry = entries[i];
3023
+ this.cat(`${i + 1}.json`, () => {
3024
+ this.write(JSON.stringify(entry, null, 2));
3025
+ });
3026
+ }
3027
+ });
3028
+ }
3029
+ });
3030
+ }
3031
+ });
2914
3032
  }
2915
3033
  this.logger()?.info(
2916
- `IntrospectionWriter: ${typeSchemas.length} TypeSchema written to ${this.opts.typeSchemas}`
3034
+ `IntrospectionWriter: ${tsIndex.schemas.length} TypeSchema written to ${this.opts.typeSchemas}`
2917
3035
  );
2918
3036
  }
2919
3037
  if (this.opts.fhirSchemas && tsIndex.register) {
2920
3038
  const outputPath = this.opts.fhirSchemas;
2921
- const fhirSchemas = tsIndex.register.allFs();
3039
+ const allFs = tsIndex.register.allFs();
3040
+ const seenUrls = /* @__PURE__ */ new Set();
3041
+ const fhirSchemas = allFs.filter((fs7) => {
3042
+ if (seenUrls.has(fs7.url)) return false;
3043
+ seenUrls.add(fs7.url);
3044
+ return true;
3045
+ });
2922
3046
  if (Path5.extname(outputPath) === ".ndjson") {
2923
3047
  this.writeNdjson(fhirSchemas, outputPath, fhirSchemaToJson);
2924
3048
  } else {
@@ -2931,7 +3055,13 @@ var IntrospectionWriter = class extends FileSystemWriter {
2931
3055
  }
2932
3056
  if (this.opts.structureDefinitions && tsIndex.register) {
2933
3057
  const outputPath = this.opts.structureDefinitions;
2934
- const structureDefinitions = tsIndex.register.allSd();
3058
+ const allSd = tsIndex.register.allSd();
3059
+ const seenUrls = /* @__PURE__ */ new Set();
3060
+ const structureDefinitions = allSd.filter((sd) => {
3061
+ if (seenUrls.has(sd.url)) return false;
3062
+ seenUrls.add(sd.url);
3063
+ return true;
3064
+ });
2935
3065
  if (Path5.extname(outputPath) === ".ndjson") {
2936
3066
  this.writeNdjson(structureDefinitions, outputPath, structureDefinitionToJson);
2937
3067
  } else {
@@ -2984,58 +3114,118 @@ var IntrospectionWriter = class extends FileSystemWriter {
2984
3114
  };
2985
3115
 
2986
3116
  // 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");
3117
+ var generateSkippedPackagesSection = (lines, skippedPackages) => {
3118
+ lines.push("## Skipped Packages", "");
3119
+ for (const pkg of skippedPackages) {
3120
+ lines.push(`- ${pkg}`);
2996
3121
  }
2997
- if (report.treeShake?.skippedPackages.length) {
2998
- lines.push("## Skipped Packages", "");
2999
- for (const pkg of report.treeShake.skippedPackages) {
3000
- lines.push(`- ${pkg}`);
3122
+ lines.push("");
3123
+ };
3124
+ var generatePackageSection = (lines, pkgName, treeShakePkg, promotedCanonicals) => {
3125
+ lines.push(`## Package: \`${pkgName}\``, "");
3126
+ if (promotedCanonicals?.length) {
3127
+ lines.push("### Promoted Logical Models", "");
3128
+ for (const canonical of promotedCanonicals) {
3129
+ lines.push(`- \`${canonical}\``);
3001
3130
  }
3002
3131
  lines.push("");
3003
3132
  }
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}\``);
3133
+ if (!treeShakePkg) return;
3134
+ const canonicalsWithChanges = Object.entries(treeShakePkg.canonicals).filter(
3135
+ ([_, data]) => data.skippedFields.length > 0
3136
+ );
3137
+ if (canonicalsWithChanges.length > 0) {
3138
+ lines.push("### Modified Canonicals", "");
3139
+ for (const [canonical, data] of canonicalsWithChanges) {
3140
+ lines.push(`#### \`${canonical}\``, "");
3141
+ lines.push("Skipped fields:", "");
3142
+ for (const field of data.skippedFields) {
3143
+ lines.push(`- \`${field}\``);
3012
3144
  }
3013
3145
  lines.push("");
3014
3146
  }
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("");
3147
+ }
3148
+ if (treeShakePkg.skippedCanonicals.length > 0) {
3149
+ lines.push("### Skipped Canonicals", "");
3150
+ for (const canonical of treeShakePkg.skippedCanonicals) {
3151
+ lines.push(`- \`${canonical}\``);
3152
+ }
3153
+ lines.push("");
3154
+ }
3155
+ };
3156
+ var generateCollisionVersionLines = (entries) => {
3157
+ const uniqueSchemas = /* @__PURE__ */ new Map();
3158
+ for (const entry of entries) {
3159
+ const key = JSON.stringify(entry.typeSchema);
3160
+ if (!uniqueSchemas.has(key)) uniqueSchemas.set(key, []);
3161
+ uniqueSchemas.get(key)?.push(entry);
3162
+ }
3163
+ const versionLines = [];
3164
+ const sortedVersions = [...uniqueSchemas.values()].sort((a, b) => b.length - a.length);
3165
+ let version = 1;
3166
+ for (const schemaEntries of sortedVersions) {
3167
+ const sourceList = schemaEntries.map((e) => {
3168
+ const name = extractNameFromCanonical(e.sourceCanonical) ?? e.sourceCanonical;
3169
+ return `${name} (${e.sourcePackage})`;
3170
+ }).join(", ");
3171
+ versionLines.push(` - Version ${version++}: ${sourceList}`);
3172
+ }
3173
+ return versionLines;
3174
+ };
3175
+ var generateCollisionsSection = (lines, collisions) => {
3176
+ if (!collisions) return;
3177
+ lines.push("## Schema Collisions", "");
3178
+ lines.push("The following canonicals have multiple schema versions with different content.");
3179
+ lines.push("To inspect collision versions, export TypeSchemas using `.introspection({ typeSchemas: 'path' })`");
3180
+ lines.push("and check `<pkg>/collisions/<name>/1.json, 2.json, ...` files.", "");
3181
+ const collisionPackages = Object.keys(collisions).sort();
3182
+ for (const pkgName of collisionPackages) {
3183
+ const collisionsPkg = collisions[pkgName];
3184
+ if (!collisionsPkg) throw new Error(`Missing collisions for package ${pkgName}`);
3185
+ const sortedEntries = Object.entries(collisionsPkg).sort(([a], [b]) => {
3186
+ const nameA = a.split("/").pop() ?? a;
3187
+ const nameB = b.split("/").pop() ?? b;
3188
+ return nameA.localeCompare(nameB);
3189
+ });
3190
+ if (sortedEntries.length > 0) {
3191
+ lines.push(`### \`${pkgName}\``, "");
3192
+ for (const [canonical, entries] of sortedEntries) {
3193
+ const versionLines = generateCollisionVersionLines(entries);
3194
+ lines.push(`- \`${canonical}\` (${versionLines.length} versions)`);
3195
+ lines.push(...versionLines);
3036
3196
  }
3197
+ lines.push("");
3037
3198
  }
3038
3199
  }
3200
+ };
3201
+ var generateIrReportReadme = (report) => {
3202
+ const lines = ["# IR Report", ""];
3203
+ const irPackages = [
3204
+ .../* @__PURE__ */ new Set([
3205
+ ...Object.keys(report.treeShake?.packages ?? {}),
3206
+ ...Object.keys(report.logicalPromotion?.packages ?? {})
3207
+ ])
3208
+ ].sort();
3209
+ const hasIrChanges = irPackages.length > 0 || (report.treeShake?.skippedPackages.length ?? 0) > 0;
3210
+ const hasCollisions = Object.keys(report.collisions ?? {}).length > 0;
3211
+ if (!hasIrChanges && !hasCollisions) {
3212
+ lines.push("No IR modifications applied.");
3213
+ return lines.join("\n");
3214
+ }
3215
+ if (report.treeShake?.skippedPackages.length) {
3216
+ generateSkippedPackagesSection(lines, report.treeShake.skippedPackages);
3217
+ }
3218
+ for (const pkgName of irPackages) {
3219
+ generatePackageSection(
3220
+ lines,
3221
+ pkgName,
3222
+ report.treeShake?.packages[pkgName],
3223
+ report.logicalPromotion?.packages[pkgName]?.promotedCanonicals
3224
+ );
3225
+ }
3226
+ if (hasCollisions) {
3227
+ generateCollisionsSection(lines, report.collisions);
3228
+ }
3039
3229
  return lines.join("\n");
3040
3230
  };
3041
3231
 
@@ -3407,25 +3597,27 @@ var ViewModelFactory = class {
3407
3597
  hasFields: fields.length > 0,
3408
3598
  hasNestedComplexTypes: nestedComplexTypes.length > 0,
3409
3599
  hasNestedEnums: nestedEnums.length > 0,
3410
- fields: fields.filter(([_fieldName, fieldSchema]) => !!fieldSchema.type).sort((a, b) => a[0].localeCompare(b[0])).map(([fieldName, fieldSchema]) => {
3600
+ fields: fields.filter(
3601
+ (entry) => isNotChoiceDeclarationField(entry[1])
3602
+ ).sort((a, b) => a[0].localeCompare(b[0])).map(([fieldName, field]) => {
3411
3603
  return {
3412
3604
  owner: name,
3413
- schema: fieldSchema,
3605
+ schema: field,
3414
3606
  name: fieldName,
3415
3607
  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"
3608
+ typeName: this.nameGenerator.generateFieldType(field),
3609
+ isArray: field.array ?? false,
3610
+ isRequired: field.required ?? false,
3611
+ isEnum: !!field.enum && !field.enum.isOpen,
3612
+ isSizeConstrained: field.min !== void 0 || field.max !== void 0,
3613
+ min: field.min,
3614
+ max: field.max,
3615
+ isResource: this._createIsResource(field.type),
3616
+ isComplexType: this._createIsComplexType(field.type),
3617
+ isPrimitive: this._createIsPrimitiveType(field.type),
3618
+ isCode: field.type?.name === "code",
3619
+ isIdentifier: field.type?.name === "Identifier",
3620
+ isReference: field.type?.name === "Reference"
3429
3621
  };
3430
3622
  })
3431
3623
  };
@@ -3501,11 +3693,11 @@ var ViewModelFactory = class {
3501
3693
  _collectNestedEnums(fields) {
3502
3694
  const nestedEnumValues = {};
3503
3695
  fields.forEach(([fieldName, fieldSchema]) => {
3504
- if ("enum" in fieldSchema && fieldSchema.enum) {
3696
+ if ("enum" in fieldSchema && fieldSchema.enum && !fieldSchema.enum.isOpen) {
3505
3697
  const name = ("binding" in fieldSchema && fieldSchema.binding?.name) ?? fieldName;
3506
3698
  if (typeof name === "string") {
3507
3699
  nestedEnumValues[name] = nestedEnumValues[name] ?? /* @__PURE__ */ new Set();
3508
- fieldSchema.enum?.forEach(nestedEnumValues[name].add.bind(nestedEnumValues[name]));
3700
+ fieldSchema.enum.values.forEach(nestedEnumValues[name].add.bind(nestedEnumValues[name]));
3509
3701
  }
3510
3702
  }
3511
3703
  });
@@ -3734,13 +3926,22 @@ var tsFhirPackageDir = (name) => {
3734
3926
  var tsModuleName = (id) => {
3735
3927
  return uppercaseFirstLetter(normalizeTsName(id.name));
3736
3928
  };
3929
+ var tsProfileModuleName = (tsIndex, schema) => {
3930
+ const resourceSchema = tsIndex.findLastSpecialization(schema);
3931
+ const resourceName = uppercaseFirstLetter(normalizeTsName(resourceSchema.identifier.name));
3932
+ const profileName = extractNameFromCanonical(schema.identifier.url);
3933
+ if (profileName) {
3934
+ return `${resourceName}_${normalizeTsName(profileName)}`;
3935
+ }
3936
+ return `${resourceName}_${normalizeTsName(schema.identifier.name)}`;
3937
+ };
3737
3938
  var tsModuleFileName = (id) => {
3738
3939
  return `${tsModuleName(id)}.ts`;
3739
3940
  };
3941
+ var tsProfileModuleFileName = (tsIndex, schema) => {
3942
+ return `${tsProfileModuleName(tsIndex, schema)}.ts`;
3943
+ };
3740
3944
  var tsModulePath = (id) => {
3741
- if (isProfileIdentifier(id)) {
3742
- return `${tsFhirPackageDir(id.package)}/profiles/${tsModuleName(id)}`;
3743
- }
3744
3945
  return `${tsFhirPackageDir(id.package)}/${tsModuleName(id)}`;
3745
3946
  };
3746
3947
  var canonicalToName3 = (canonical, dropFragment = true) => {
@@ -3752,9 +3953,9 @@ var canonicalToName3 = (canonical, dropFragment = true) => {
3752
3953
  var tsResourceName = (id) => {
3753
3954
  if (id.kind === "nested") {
3754
3955
  const url = id.url;
3755
- const path = canonicalToName3(url, false);
3756
- if (!path) return "";
3757
- const [resourceName, fragment] = path.split("#");
3956
+ const localName = extractNameFromCanonical(url, false);
3957
+ if (!localName) return "";
3958
+ const [resourceName, fragment] = localName.split("#");
3758
3959
  const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
3759
3960
  return normalizeTsName([resourceName, name].join(""));
3760
3961
  }
@@ -3768,14 +3969,37 @@ var tsFieldName = (n) => {
3768
3969
  };
3769
3970
  var normalizeTsName = (n) => {
3770
3971
  if (tsKeywords.has(n)) n = `${n}_`;
3771
- return n.replace(/\[x\]/g, "_x_").replace(/[- :]/g, "_");
3972
+ return n.replace(/\[x\]/g, "_x_").replace(/[- :.]/g, "_");
3772
3973
  };
3773
3974
  var tsGet = (object, tsFieldName2) => {
3774
3975
  if (tsFieldName2.startsWith('"')) return `${object}[${tsFieldName2}]`;
3775
3976
  return `${object}.${tsFieldName2}`;
3776
3977
  };
3777
- var tsEnumType = (enumValues) => {
3778
- return `(${enumValues.map((e) => `"${e}"`).join(" | ")})`;
3978
+ var tsEnumType = (enumDef) => {
3979
+ const values = enumDef.values.map((e) => `"${e}"`).join(" | ");
3980
+ return enumDef.isOpen ? `(${values} | string)` : `(${values})`;
3981
+ };
3982
+ var rewriteFieldTypeDefs = {
3983
+ Coding: { code: () => "T" },
3984
+ // biome-ignore lint: that is exactly string what we want
3985
+ Reference: { reference: () => "`${T}/${string}`" },
3986
+ CodeableConcept: { coding: () => "Coding<T>" }
3987
+ };
3988
+ var resolveFieldTsType = (schemaName, tsName, field) => {
3989
+ const rewriteFieldType = rewriteFieldTypeDefs[schemaName]?.[tsName];
3990
+ if (rewriteFieldType) return rewriteFieldType();
3991
+ if (field.enum) {
3992
+ if (field.type.name === "Coding") return `Coding<${tsEnumType(field.enum)}>`;
3993
+ if (field.type.name === "CodeableConcept") return `CodeableConcept<${tsEnumType(field.enum)}>`;
3994
+ return tsEnumType(field.enum);
3995
+ }
3996
+ if (field.reference && field.reference.length > 0) {
3997
+ const references = field.reference.map((ref) => `"${ref.name}"`).join(" | ");
3998
+ return `Reference<${references}>`;
3999
+ }
4000
+ if (isPrimitiveIdentifier(field.type)) return resolvePrimitiveType(field.type.name);
4001
+ if (isNestedIdentifier(field.type)) return tsResourceName(field.type);
4002
+ return field.type.name;
3779
4003
  };
3780
4004
  var tsTypeFromIdentifier = (id) => {
3781
4005
  if (isNestedIdentifier(id)) return tsResourceName(id);
@@ -3784,8 +4008,12 @@ var tsTypeFromIdentifier = (id) => {
3784
4008
  if (primitiveType !== void 0) return primitiveType;
3785
4009
  return id.name;
3786
4010
  };
3787
- var tsProfileClassName = (id) => {
3788
- return `${uppercaseFirstLetter(normalizeTsName(id.name))}Profile`;
4011
+ var tsProfileClassName = (schema) => {
4012
+ const profileName = extractNameFromCanonical(schema.identifier.url);
4013
+ if (profileName) {
4014
+ return `${normalizeTsName(profileName)}Profile`;
4015
+ }
4016
+ return `${normalizeTsName(schema.identifier.name)}Profile`;
3789
4017
  };
3790
4018
  var tsSliceInputTypeName = (profileName, fieldName, sliceName) => {
3791
4019
  return `${uppercaseFirstLetter(profileName)}_${uppercaseFirstLetter(normalizeTsName(fieldName))}_${uppercaseFirstLetter(normalizeTsName(sliceName))}SliceInput`;
@@ -3821,21 +4049,33 @@ var TypeScript = class extends Writer {
3821
4049
  tsImportType(tsPackageName, ...entities) {
3822
4050
  this.lineSM(`import type { ${entities.join(", ")} } from "${tsPackageName}"`);
3823
4051
  }
3824
- generateProfileIndexFile(profiles) {
3825
- if (profiles.length === 0) return;
4052
+ generateProfileIndexFile(tsIndex, initialProfiles) {
4053
+ if (initialProfiles.length === 0) return;
3826
4054
  this.cd("profiles", () => {
3827
4055
  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;
4056
+ const profiles = initialProfiles.map((profile) => {
4057
+ const className = tsProfileClassName(profile);
4058
+ const resourceName = tsResourceName(profile.identifier);
4059
+ const overrides = this.detectFieldOverrides(tsIndex, profile);
4060
+ let typeExport;
4061
+ if (overrides.size > 0) typeExport = resourceName;
4062
+ return [profile, className, typeExport];
3834
4063
  });
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)}"`);
4064
+ if (profiles.length === 0) return;
4065
+ const classExports = /* @__PURE__ */ new Map();
4066
+ const typeExports = /* @__PURE__ */ new Map();
4067
+ for (const [profile, className, typeName] of profiles) {
4068
+ const moduleName = tsProfileModuleName(tsIndex, profile);
4069
+ if (!classExports.has(className)) {
4070
+ classExports.set(className, `export { ${className} } from "./${moduleName}"`);
4071
+ }
4072
+ if (typeName && !typeExports.has(typeName)) {
4073
+ typeExports.set(typeName, `export type { ${typeName} } from "./${moduleName}"`);
4074
+ }
4075
+ }
4076
+ const allExports = [...classExports.values(), ...typeExports.values()].sort();
4077
+ for (const exp of allExports) {
4078
+ this.lineSM(exp);
3839
4079
  }
3840
4080
  });
3841
4081
  });
@@ -3929,14 +4169,16 @@ var TypeScript = class extends Writer {
3929
4169
  this.line();
3930
4170
  }
3931
4171
  }
3932
- addFieldExtension(fieldName) {
4172
+ addFieldExtension(fieldName, isArray) {
3933
4173
  const extFieldName = tsFieldName(`_${fieldName}`);
3934
- this.lineSM(`${extFieldName}?: Element`);
4174
+ const typeExpr = isArray ? "(Element | null)[]" : "Element";
4175
+ this.lineSM(`${extFieldName}?: ${typeExpr}`);
3935
4176
  }
3936
4177
  generateType(tsIndex, schema) {
3937
4178
  let name;
3938
- if (schema.identifier.name === "Reference") {
3939
- name = "Reference<T extends string = string>";
4179
+ const genericTypes = ["Reference", "Coding", "CodeableConcept"];
4180
+ if (genericTypes.includes(schema.identifier.name)) {
4181
+ name = `${schema.identifier.name}<T extends string = string>`;
3940
4182
  } else if (schema.identifier.kind === "nested") {
3941
4183
  name = tsResourceName(schema.identifier);
3942
4184
  } else {
@@ -3963,29 +4205,16 @@ var TypeScript = class extends Writer {
3963
4205
  const fields = Object.entries(schema.fields).sort((a, b) => a[0].localeCompare(b[0]));
3964
4206
  for (const [fieldName, field] of fields) {
3965
4207
  if (isChoiceDeclarationField(field)) continue;
4208
+ if (!field.type) continue;
3966
4209
  this.debugComment(fieldName, ":", field);
3967
4210
  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
- }
4211
+ const tsType = resolveFieldTsType(schema.identifier.name, tsName, field);
3983
4212
  const optionalSymbol = field.required ? "" : "?";
3984
4213
  const arraySymbol = field.array ? "[]" : "";
3985
4214
  this.lineSM(`${tsName}${optionalSymbol}: ${tsType}${arraySymbol}`);
3986
4215
  if (this.withPrimitiveTypeExtension(schema)) {
3987
4216
  if (isPrimitiveIdentifier(field.type)) {
3988
- this.addFieldExtension(fieldName);
4217
+ this.addFieldExtension(fieldName, field.array ?? false);
3989
4218
  }
3990
4219
  }
3991
4220
  }
@@ -4021,10 +4250,16 @@ var TypeScript = class extends Writer {
4021
4250
  if (!isNotChoiceDeclarationField(field)) {
4022
4251
  throw new Error(`Choice declaration fields not supported for '${fieldName}'`);
4023
4252
  }
4253
+ let tsType;
4024
4254
  if (field.enum) {
4025
- return tsEnumType(field.enum);
4026
- }
4027
- if (field.reference && field.reference.length > 0) {
4255
+ if (field.type?.name === "Coding") {
4256
+ tsType = `Coding<${tsEnumType(field.enum)}>`;
4257
+ } else if (field.type?.name === "CodeableConcept") {
4258
+ tsType = `CodeableConcept<${tsEnumType(field.enum)}>`;
4259
+ } else {
4260
+ tsType = tsEnumType(field.enum);
4261
+ }
4262
+ } else if (field.reference && field.reference.length > 0) {
4028
4263
  const specialization = tsIndex.findLastSpecialization(flatProfile);
4029
4264
  if (!isSpecializationTypeSchema(specialization))
4030
4265
  throw new Error(`Invalid specialization for ${flatProfile.identifier}`);
@@ -4041,20 +4276,20 @@ var TypeScript = class extends Writer {
4041
4276
  }).join(" | ");
4042
4277
  if (sRefs.length === 1 && sRefs[0] === "Resource" && references !== '"Resource"') {
4043
4278
  const cleanRefs = references.replace(/\/\*[^*]*\*\//g, "").trim();
4044
- return `Reference<"Resource" /* ${cleanRefs} */ >`;
4279
+ tsType = `Reference<"Resource" /* ${cleanRefs} */ >`;
4280
+ } else {
4281
+ tsType = `Reference<${references}>`;
4045
4282
  }
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) {
4283
+ } else if (isPrimitiveIdentifier(field.type)) {
4284
+ tsType = resolvePrimitiveType(field.type.name);
4285
+ } else if (isNestedIdentifier(field.type)) {
4286
+ tsType = tsResourceName(field.type);
4287
+ } else if (field.type === void 0) {
4055
4288
  throw new Error(`Undefined type for '${fieldName}' field at ${typeSchemaInfo(flatProfile)}`);
4289
+ } else {
4290
+ tsType = field.type.name;
4056
4291
  }
4057
- return field.type.name;
4292
+ return tsType;
4058
4293
  }
4059
4294
  generateProfileType(tsIndex, flatProfile) {
4060
4295
  this.debugComment("flatProfile", flatProfile);
@@ -4358,104 +4593,95 @@ var TypeScript = class extends Writer {
4358
4593
  this.lineSM(`import { ${imports.join(", ")} } from "../../profile-helpers"`);
4359
4594
  }
4360
4595
  }
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)) {
4596
+ collectTypesFromSlices(flatProfile, addType) {
4597
+ for (const field of Object.values(flatProfile.fields ?? {})) {
4386
4598
  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);
4599
+ for (const slice of Object.values(field.slicing.slices)) {
4600
+ if (Object.keys(slice.match ?? {}).length > 0) {
4601
+ addType(field.type);
4602
+ }
4391
4603
  }
4392
4604
  }
4393
- const extensions = flatProfile.extensions ?? [];
4605
+ }
4606
+ collectTypesFromExtensions(tsIndex, flatProfile, addType) {
4394
4607
  let needsExtensionType = false;
4395
- for (const ext of extensions) {
4608
+ for (const ext of flatProfile.extensions ?? []) {
4396
4609
  if (ext.isComplex && ext.subExtensions) {
4397
4610
  needsExtensionType = true;
4398
4611
  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
- }
4612
+ if (!sub.valueType) continue;
4613
+ const resolvedType = tsIndex.resolveByUrl(
4614
+ flatProfile.identifier.package,
4615
+ sub.valueType.url
4616
+ );
4617
+ addType(resolvedType?.identifier ?? sub.valueType);
4410
4618
  }
4411
4619
  } else if (ext.valueTypes && ext.valueTypes.length === 1) {
4412
4620
  needsExtensionType = true;
4413
- const valueType = ext.valueTypes[0];
4414
- if (valueType) {
4415
- addType(valueType);
4621
+ if (ext.valueTypes[0]) {
4622
+ const resolvedType = tsIndex.resolveByUrl(
4623
+ flatProfile.identifier.package,
4624
+ ext.valueTypes[0].url
4625
+ );
4626
+ addType(resolvedType?.identifier ?? ext.valueTypes[0]);
4416
4627
  }
4417
4628
  } else {
4418
4629
  needsExtensionType = true;
4419
4630
  }
4420
4631
  }
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
- }
4632
+ return needsExtensionType;
4633
+ }
4634
+ collectTypesFromFieldOverrides(tsIndex, flatProfile, addType) {
4428
4635
  const referenceUrl = "http://hl7.org/fhir/StructureDefinition/Reference";
4429
4636
  const referenceSchema = tsIndex.resolveByUrl(flatProfile.identifier.package, referenceUrl);
4430
4637
  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
- }
4638
+ if (!isSpecializationTypeSchema(specialization)) return;
4639
+ for (const [fieldName, pField] of Object.entries(flatProfile.fields ?? {})) {
4640
+ if (!isNotChoiceDeclarationField(pField)) continue;
4641
+ const sField = specialization.fields?.[fieldName];
4642
+ if (!sField || isChoiceDeclarationField(sField)) continue;
4643
+ if (pField.reference && sField.reference && pField.reference.length < sField.reference.length) {
4644
+ if (referenceSchema) addType(referenceSchema.identifier);
4645
+ } else if (pField.required && !sField.required && pField.type) {
4646
+ addType(pField.type);
4647
+ }
4648
+ }
4649
+ }
4650
+ generateProfileImports(tsIndex, flatProfile) {
4651
+ const usedTypes = /* @__PURE__ */ new Map();
4652
+ const getModulePath = (typeId) => {
4653
+ if (isNestedIdentifier(typeId)) {
4654
+ const path = canonicalToName3(typeId.url, true);
4655
+ if (path) return `../../${tsFhirPackageDir(typeId.package)}/${pascalCase(path)}`;
4656
+ }
4657
+ return `../../${tsModulePath(typeId)}`;
4658
+ };
4659
+ const addType = (typeId) => {
4660
+ if (typeId.kind === "primitive-type") return;
4661
+ const tsName = tsResourceName(typeId);
4662
+ if (!usedTypes.has(tsName)) {
4663
+ usedTypes.set(tsName, { importPath: getModulePath(typeId), tsName });
4445
4664
  }
4665
+ };
4666
+ addType(flatProfile.base);
4667
+ this.collectTypesFromSlices(flatProfile, addType);
4668
+ const needsExtensionType = this.collectTypesFromExtensions(tsIndex, flatProfile, addType);
4669
+ this.collectTypesFromFieldOverrides(tsIndex, flatProfile, addType);
4670
+ if (needsExtensionType) {
4671
+ const extensionUrl = "http://hl7.org/fhir/StructureDefinition/Extension";
4672
+ const extensionSchema = tsIndex.resolveByUrl(flatProfile.identifier.package, extensionUrl);
4673
+ if (extensionSchema) addType(extensionSchema.identifier);
4446
4674
  }
4447
4675
  const sortedImports = Array.from(usedTypes.values()).sort((a, b) => a.tsName.localeCompare(b.tsName));
4448
4676
  for (const { importPath, tsName } of sortedImports) {
4449
4677
  this.tsImportType(importPath, tsName);
4450
4678
  }
4451
- if (sortedImports.length > 0) {
4452
- this.line();
4453
- }
4679
+ if (sortedImports.length > 0) this.line();
4454
4680
  }
4455
4681
  generateProfileClass(tsIndex, flatProfile) {
4456
4682
  const tsBaseResourceName = tsTypeFromIdentifier(flatProfile.base);
4457
4683
  const tsProfileName = tsResourceName(flatProfile.identifier);
4458
- const profileClassName = tsProfileClassName(flatProfile.identifier);
4684
+ const profileClassName = tsProfileClassName(flatProfile);
4459
4685
  const polymorphicBaseNames = /* @__PURE__ */ new Set([
4460
4686
  "value",
4461
4687
  "effective",
@@ -4887,7 +5113,7 @@ var TypeScript = class extends Writer {
4887
5113
  generateResourceModule(tsIndex, schema) {
4888
5114
  if (isProfileTypeSchema(schema)) {
4889
5115
  this.cd("profiles", () => {
4890
- this.cat(`${tsModuleFileName(schema.identifier)}`, () => {
5116
+ this.cat(`${tsProfileModuleFileName(tsIndex, schema)}`, () => {
4891
5117
  this.generateDisclaimer();
4892
5118
  const flatProfile = tsIndex.flatProfile(schema);
4893
5119
  this.generateProfileImports(tsIndex, flatProfile);
@@ -4937,7 +5163,7 @@ var TypeScript = class extends Writer {
4937
5163
  for (const schema of packageSchemas) {
4938
5164
  this.generateResourceModule(tsIndex, schema);
4939
5165
  }
4940
- this.generateProfileIndexFile(packageSchemas.filter(isProfileTypeSchema));
5166
+ this.generateProfileIndexFile(tsIndex, packageSchemas.filter(isProfileTypeSchema));
4941
5167
  this.generateFhirPackageIndexFile(packageSchemas);
4942
5168
  });
4943
5169
  }
@@ -4994,7 +5220,8 @@ var APIBuilder = class {
4994
5220
  treeShake: void 0,
4995
5221
  promoteLogical: void 0,
4996
5222
  registry: void 0,
4997
- logLevel: parseLogLevel("INFO")
5223
+ logLevel: parseLogLevel("INFO"),
5224
+ dropCanonicalManagerCache: false
4998
5225
  };
4999
5226
  const opts = {
5000
5227
  ...defaultOpts,
@@ -5016,7 +5243,8 @@ var APIBuilder = class {
5016
5243
  this.manager = userOpts.manager ?? CanonicalManager({
5017
5244
  packages: [],
5018
5245
  workingDir: ".codegen-cache/canonical-manager-cache",
5019
- registry: userOpts.registry
5246
+ registry: userOpts.registry,
5247
+ dropCache: userOpts.dropCanonicalManagerCache
5020
5248
  });
5021
5249
  this.logger = userOpts.logger ?? createLogger({ prefix: "API", level: opts.logLevel });
5022
5250
  this.options = opts;
@@ -5030,14 +5258,6 @@ var APIBuilder = class {
5030
5258
  this.managerInput.npmPackages.push(packageRef);
5031
5259
  return this;
5032
5260
  }
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
5261
  localStructureDefinitions(config) {
5042
5262
  this.logger.info(`Registering local StructureDefinitions for ${config.package.name}@${config.package.version}`);
5043
5263
  this.managerInput.localSDs.push({
@@ -5241,10 +5461,11 @@ var APIBuilder = class {
5241
5461
  focusedPackages: packageMetas
5242
5462
  });
5243
5463
  }
5244
- const typeSchemas = await generateTypeSchemas(register, this.logger);
5464
+ const { schemas: typeSchemas, collisions } = await generateTypeSchemas(register, this.logger);
5245
5465
  const tsIndexOpts = {
5246
5466
  register,
5247
- logger: this.logger
5467
+ logger: this.logger,
5468
+ irReport: Object.keys(collisions).length > 0 ? { collisions } : {}
5248
5469
  };
5249
5470
  let tsIndex = mkTypeSchemaIndex(typeSchemas, tsIndexOpts);
5250
5471
  if (this.options.treeShake) tsIndex = treeShake(tsIndex, this.options.treeShake);
@@ -5298,6 +5519,6 @@ var APIBuilder = class {
5298
5519
  }
5299
5520
  };
5300
5521
 
5301
- export { APIBuilder, LogLevel, prettyReport };
5522
+ export { APIBuilder, LogLevel, prettyReport, registerFromPackageMetas };
5302
5523
  //# sourceMappingURL=index.js.map
5303
5524
  //# sourceMappingURL=index.js.map