@atomic-ehr/codegen 0.0.1-canary.20251007094146.5297616 → 0.0.1-canary.20251007114955.88a8afc

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
@@ -1596,7 +1596,7 @@ function mkBindingIdentifier(fhirSchema, path, bindingName) {
1596
1596
  }
1597
1597
 
1598
1598
  // src/typeschema/profile/processor.ts
1599
- async function transformProfile(register, fhirSchema) {
1599
+ async function transformProfile(register, fhirSchema, logger) {
1600
1600
  const identifier = mkIdentifier(fhirSchema);
1601
1601
  if (identifier.kind !== "profile") {
1602
1602
  throw new Error(`Expected profile, got ${identifier.kind} for ${fhirSchema.name}`);
@@ -1628,7 +1628,7 @@ async function transformProfile(register, fhirSchema) {
1628
1628
  profileSchema.metadata = metadata;
1629
1629
  }
1630
1630
  if (fhirSchema.elements) {
1631
- const fields = await mkFields(register, fhirSchema, [], fhirSchema.elements);
1631
+ const fields = await mkFields(register, fhirSchema, [], fhirSchema.elements, logger);
1632
1632
  if (fields && Object.keys(fields).length > 0) {
1633
1633
  profileSchema.fields = fields;
1634
1634
  }
@@ -1825,13 +1825,13 @@ function buildFieldType(register, fhirSchema, element) {
1825
1825
  }
1826
1826
  return void 0;
1827
1827
  }
1828
- var mkField = (register, fhirSchema, path, element) => {
1828
+ var mkField = (register, fhirSchema, path, element, logger) => {
1829
1829
  let binding;
1830
1830
  let enumValues;
1831
1831
  if (element.binding) {
1832
1832
  binding = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName);
1833
1833
  if (element.binding.strength === "required" && element.type === "code") {
1834
- enumValues = buildEnum(register, element);
1834
+ enumValues = buildEnum(register, element, logger);
1835
1835
  }
1836
1836
  }
1837
1837
  return {
@@ -1864,13 +1864,13 @@ function mkNestedField(register, fhirSchema, path, element) {
1864
1864
  }
1865
1865
 
1866
1866
  // src/typeschema/core/binding.ts
1867
- function extractValueSetConceptsByUrl(register, valueSetUrl) {
1867
+ function extractValueSetConceptsByUrl(register, valueSetUrl, logger) {
1868
1868
  const cleanUrl = dropVersionFromUrl(valueSetUrl) || valueSetUrl;
1869
1869
  const valueSet = register.resolveVs(cleanUrl);
1870
1870
  if (!valueSet) return void 0;
1871
1871
  return extractValueSetConcepts(register, valueSet);
1872
1872
  }
1873
- function extractValueSetConcepts(register, valueSet) {
1873
+ function extractValueSetConcepts(register, valueSet, _logger) {
1874
1874
  if (valueSet.expansion?.contains) return valueSet.expansion.contains;
1875
1875
  const concepts = [];
1876
1876
  if (valueSet.compose?.include) {
@@ -1909,7 +1909,7 @@ function extractValueSetConcepts(register, valueSet) {
1909
1909
  return concepts.length > 0 ? concepts : void 0;
1910
1910
  }
1911
1911
  var MAX_ENUM_LENGTH = 100;
1912
- function buildEnum(register, element) {
1912
+ function buildEnum(register, element, logger) {
1913
1913
  if (!element.binding) return void 0;
1914
1914
  const strength = element.binding.strength;
1915
1915
  const valueSetUrl = element.binding.valueSet;
@@ -1920,14 +1920,14 @@ function buildEnum(register, element) {
1920
1920
  if (!concepts || concepts.length === 0) return void 0;
1921
1921
  const codes = concepts.map((c) => c.code).filter((code) => code && typeof code === "string" && code.trim().length > 0);
1922
1922
  if (codes.length > MAX_ENUM_LENGTH) {
1923
- console.warn(
1923
+ logger?.dry_warn(
1924
1924
  `Value set ${valueSetUrl} has ${codes.length} which is more than ${MAX_ENUM_LENGTH} codes, which may cause issues with code generation.`
1925
1925
  );
1926
1926
  return void 0;
1927
1927
  }
1928
1928
  return codes.length > 0 ? codes : void 0;
1929
1929
  }
1930
- function generateBindingSchema(register, fhirSchema, path, element) {
1930
+ function generateBindingSchema(register, fhirSchema, path, element, logger) {
1931
1931
  if (!element.binding?.valueSet) return void 0;
1932
1932
  const identifier = mkBindingIdentifier(fhirSchema, path, element.binding.bindingName);
1933
1933
  const fieldType = buildFieldType(register, fhirSchema, element);
@@ -1937,7 +1937,7 @@ function generateBindingSchema(register, fhirSchema, path, element) {
1937
1937
  dependencies.push(fieldType);
1938
1938
  }
1939
1939
  dependencies.push(valueSetIdentifier);
1940
- const enumValues = buildEnum(register, element);
1940
+ const enumValues = buildEnum(register, element, logger);
1941
1941
  return {
1942
1942
  identifier,
1943
1943
  type: fieldType,
@@ -1947,7 +1947,7 @@ function generateBindingSchema(register, fhirSchema, path, element) {
1947
1947
  dependencies
1948
1948
  };
1949
1949
  }
1950
- function collectBindingSchemas(register, fhirSchema) {
1950
+ function collectBindingSchemas(register, fhirSchema, logger) {
1951
1951
  const processedPaths = /* @__PURE__ */ new Set();
1952
1952
  if (!fhirSchema.elements) return [];
1953
1953
  const bindings = [];
@@ -1958,7 +1958,7 @@ function collectBindingSchemas(register, fhirSchema) {
1958
1958
  if (processedPaths.has(pathKey)) continue;
1959
1959
  processedPaths.add(pathKey);
1960
1960
  if (element.binding) {
1961
- const binding = generateBindingSchema(register, fhirSchema, path, element);
1961
+ const binding = generateBindingSchema(register, fhirSchema, path, element, logger);
1962
1962
  if (binding) {
1963
1963
  bindings.push(binding);
1964
1964
  }
@@ -1995,19 +1995,19 @@ function collectNestedElements(fhirSchema, parentPath, elements) {
1995
1995
  }
1996
1996
  return nested;
1997
1997
  }
1998
- function transformNestedElements(fhirSchema, parentPath, elements, register) {
1998
+ function transformNestedElements(fhirSchema, parentPath, elements, register, logger) {
1999
1999
  const fields = {};
2000
2000
  for (const [key, element] of Object.entries(elements)) {
2001
2001
  const path = [...parentPath, key];
2002
2002
  if (isNestedElement(element)) {
2003
2003
  fields[key] = mkNestedField(register, fhirSchema, path, element);
2004
2004
  } else {
2005
- fields[key] = mkField(register, fhirSchema, path, element);
2005
+ fields[key] = mkField(register, fhirSchema, path, element, logger);
2006
2006
  }
2007
2007
  }
2008
2008
  return fields;
2009
2009
  }
2010
- function mkNestedTypes(register, fhirSchema) {
2010
+ function mkNestedTypes(register, fhirSchema, logger) {
2011
2011
  if (!fhirSchema.elements) return void 0;
2012
2012
  const nestedElements = collectNestedElements(fhirSchema, [], fhirSchema.elements);
2013
2013
  const actualNested = nestedElements.filter(
@@ -2034,7 +2034,7 @@ function mkNestedTypes(register, fhirSchema) {
2034
2034
  url: `http://hl7.org/fhir/StructureDefinition/${element.type}`
2035
2035
  };
2036
2036
  }
2037
- const fields = transformNestedElements(fhirSchema, path, element.elements, register);
2037
+ const fields = transformNestedElements(fhirSchema, path, element.elements, register, logger);
2038
2038
  const nestedType = {
2039
2039
  identifier,
2040
2040
  base,
@@ -2064,7 +2064,7 @@ function extractNestedDependencies(nestedTypes) {
2064
2064
  }
2065
2065
 
2066
2066
  // src/typeschema/core/transformer.ts
2067
- function mkFields(register, fhirSchema, parentPath, elements) {
2067
+ function mkFields(register, fhirSchema, parentPath, elements, logger) {
2068
2068
  if (!elements) return void 0;
2069
2069
  const geneology = register.resolveFsGenealogy(fhirSchema.url);
2070
2070
  const elems = {};
@@ -2089,7 +2089,7 @@ function mkFields(register, fhirSchema, parentPath, elements) {
2089
2089
  if (isNestedElement(elemSnapshot)) {
2090
2090
  fields[key] = mkNestedField(register, fhirSchema, path, elemSnapshot);
2091
2091
  } else {
2092
- fields[key] = mkField(register, fhirSchema, path, elemSnapshot);
2092
+ fields[key] = mkField(register, fhirSchema, path, elemSnapshot, logger);
2093
2093
  }
2094
2094
  }
2095
2095
  return fields;
@@ -2134,7 +2134,7 @@ function isExtensionSchema(fhirSchema, _identifier) {
2134
2134
  }
2135
2135
  return false;
2136
2136
  }
2137
- async function transformValueSet(register, valueSet) {
2137
+ async function transformValueSet(register, valueSet, logger) {
2138
2138
  if (!valueSet.url) throw new Error("ValueSet URL is required");
2139
2139
  const identifier = mkValueSetIdentifierByUrl(register, valueSet.url);
2140
2140
  const concept = extractValueSetConceptsByUrl(register, valueSet.url);
@@ -2145,7 +2145,7 @@ async function transformValueSet(register, valueSet) {
2145
2145
  compose: !concept ? valueSet.compose : void 0
2146
2146
  };
2147
2147
  }
2148
- async function transformExtension(fhirSchema, register, _packageInfo) {
2148
+ async function transformExtension(fhirSchema, register, logger) {
2149
2149
  try {
2150
2150
  const identifier = mkIdentifier(fhirSchema);
2151
2151
  let base;
@@ -2182,13 +2182,13 @@ async function transformExtension(fhirSchema, register, _packageInfo) {
2182
2182
  extensionSchema.dependencies.push(base);
2183
2183
  }
2184
2184
  if (fhirSchema.elements) {
2185
- const fields = mkFields(register, fhirSchema, [], fhirSchema.elements);
2185
+ const fields = mkFields(register, fhirSchema, [], fhirSchema.elements, logger);
2186
2186
  if (fields && Object.keys(fields).length > 0) {
2187
2187
  extensionSchema.fields = fields;
2188
2188
  extensionSchema.dependencies.push(...extractFieldDependencies(fields));
2189
2189
  }
2190
2190
  }
2191
- const nestedTypes = mkNestedTypes(register, fhirSchema);
2191
+ const nestedTypes = mkNestedTypes(register, fhirSchema, logger);
2192
2192
  if (nestedTypes && nestedTypes.length > 0) {
2193
2193
  extensionSchema.nested = nestedTypes;
2194
2194
  extensionSchema.dependencies.push(...extractNestedDependencies(nestedTypes));
@@ -2215,7 +2215,7 @@ function extractDependencies(identifier, base, fields, nestedTypes) {
2215
2215
  const result = Object.values(uniqDeps).filter((e) => !(e.kind === "nested" && localNestedTypeUrls.has(e.url))).sort((a, b) => a.url.localeCompare(b.url));
2216
2216
  return result.length > 0 ? result : void 0;
2217
2217
  }
2218
- function transformFhirSchemaResource(register, fhirSchema) {
2218
+ function transformFhirSchemaResource(register, fhirSchema, logger) {
2219
2219
  const identifier = mkIdentifier(fhirSchema);
2220
2220
  let base;
2221
2221
  if (fhirSchema.base && fhirSchema.type !== "Element") {
@@ -2225,8 +2225,8 @@ function transformFhirSchemaResource(register, fhirSchema) {
2225
2225
  }
2226
2226
  base = mkIdentifier(baseFs);
2227
2227
  }
2228
- const fields = mkFields(register, fhirSchema, [], fhirSchema.elements);
2229
- const nested = mkNestedTypes(register, fhirSchema);
2228
+ const fields = mkFields(register, fhirSchema, [], fhirSchema.elements, logger);
2229
+ const nested = mkNestedTypes(register, fhirSchema, logger);
2230
2230
  const dependencies = extractDependencies(identifier, base, fields, nested);
2231
2231
  const typeSchema = {
2232
2232
  identifier,
@@ -2236,27 +2236,27 @@ function transformFhirSchemaResource(register, fhirSchema) {
2236
2236
  description: fhirSchema.description,
2237
2237
  dependencies
2238
2238
  };
2239
- const bindingSchemas = collectBindingSchemas(register, fhirSchema);
2239
+ const bindingSchemas = collectBindingSchemas(register, fhirSchema, logger);
2240
2240
  return [typeSchema, ...bindingSchemas];
2241
2241
  }
2242
- async function transformFhirSchema(register, fhirSchema) {
2242
+ async function transformFhirSchema(register, fhirSchema, logger) {
2243
2243
  const results = [];
2244
2244
  const identifier = mkIdentifier(fhirSchema);
2245
2245
  if (identifier.kind === "profile") {
2246
- const profileSchema = await transformProfile(register, fhirSchema);
2246
+ const profileSchema = await transformProfile(register, fhirSchema, logger);
2247
2247
  results.push(profileSchema);
2248
- const bindingSchemas = collectBindingSchemas(register, fhirSchema);
2248
+ const bindingSchemas = collectBindingSchemas(register, fhirSchema, logger);
2249
2249
  results.push(...bindingSchemas);
2250
2250
  return results;
2251
2251
  }
2252
2252
  if (isExtensionSchema(fhirSchema)) {
2253
- const extensionSchema = await transformExtension(fhirSchema, register, fhirSchema.package_meta);
2253
+ const extensionSchema = await transformExtension(fhirSchema, register, logger);
2254
2254
  if (extensionSchema) {
2255
2255
  results.push(extensionSchema);
2256
2256
  }
2257
2257
  return results;
2258
2258
  }
2259
- return transformFhirSchemaResource(register, fhirSchema);
2259
+ return transformFhirSchemaResource(register, fhirSchema, logger);
2260
2260
  }
2261
2261
  var TypeSchemaCache = class {
2262
2262
  cache = /* @__PURE__ */ new Map();
@@ -2478,6 +2478,7 @@ var TypeSchemaCache = class {
2478
2478
  };
2479
2479
  var CodegenLogger = class _CodegenLogger {
2480
2480
  options;
2481
+ dryWarnSet = /* @__PURE__ */ new Set();
2481
2482
  constructor(options = {}) {
2482
2483
  this.options = {
2483
2484
  timestamp: false,
@@ -2512,13 +2513,19 @@ var CodegenLogger = class _CodegenLogger {
2512
2513
  * Warning message with warning sign
2513
2514
  */
2514
2515
  warn(message) {
2515
- console.warn(this.formatMessage("\u26A0\uFE0F", message, pc.yellow));
2516
+ console.warn(this.formatMessage("!", message, pc.yellow));
2517
+ }
2518
+ dry_warn(message) {
2519
+ if (!this.dryWarnSet.has(message)) {
2520
+ this.warn(message);
2521
+ this.dryWarnSet.add(message);
2522
+ }
2516
2523
  }
2517
2524
  /**
2518
2525
  * Info message with info icon
2519
2526
  */
2520
2527
  info(message) {
2521
- console.log(this.formatMessage("\u2139\uFE0F", message, pc.blue));
2528
+ console.log(this.formatMessage("i", message, pc.blue));
2522
2529
  }
2523
2530
  /**
2524
2531
  * Debug message (only shows in verbose mode)
@@ -2599,12 +2606,12 @@ var TypeSchemaGenerator = class {
2599
2606
  }
2600
2607
  async registerFromPackageMetas(packageMetas) {
2601
2608
  const packageNames = packageMetas.map((meta) => `${meta.name}${meta.version}`);
2602
- this.logger.step(`Loading FHIR packages: ${packageNames.join(", ")}`);
2609
+ this.logger?.step(`Loading FHIR packages: ${packageNames.join(", ")}`);
2603
2610
  await this.manager.init();
2604
2611
  return registerFromManager(this.manager);
2605
2612
  }
2606
2613
  generateFhirSchemas(structureDefinitions) {
2607
- this.logger.progress(`Converting ${structureDefinitions.length} StructureDefinitions to FHIRSchemas`);
2614
+ this.logger?.progress(`Converting ${structureDefinitions.length} StructureDefinitions to FHIRSchemas`);
2608
2615
  const filteredStructureDefinitions = this.applyStructureDefinitionTreeshaking(structureDefinitions);
2609
2616
  const fhirSchemas = [];
2610
2617
  let convertedCount = 0;
@@ -2614,56 +2621,56 @@ var TypeSchemaGenerator = class {
2614
2621
  const fhirSchema = fhirschema.translate(sd);
2615
2622
  fhirSchemas.push(fhirSchema);
2616
2623
  convertedCount++;
2617
- this.logger.debug(`Converted StructureDefinition: ${sd.name || sd.id} (${sd.resourceType})`);
2624
+ this.logger?.debug(`Converted StructureDefinition: ${sd.name || sd.id} (${sd.resourceType})`);
2618
2625
  } catch (error) {
2619
2626
  failedCount++;
2620
- this.logger.warn(
2627
+ this.logger?.warn(
2621
2628
  `Failed to convert StructureDefinition ${sd.name || sd.id}: ${error instanceof Error ? error.message : String(error)}`
2622
2629
  );
2623
2630
  }
2624
2631
  }
2625
- this.logger.success(
2632
+ this.logger?.success(
2626
2633
  `FHIR Schema conversion completed: ${convertedCount}/${filteredStructureDefinitions.length} successful, ${failedCount} failed`
2627
2634
  );
2628
2635
  return fhirSchemas;
2629
2636
  }
2630
- async generateValueSetSchemas(valueSets) {
2637
+ async generateValueSetSchemas(valueSets, logger) {
2631
2638
  if (valueSets.length > 0) {
2632
- this.logger.debug(`${valueSets.length} ValueSets available for enum extraction`);
2639
+ this.logger?.debug(`${valueSets.length} ValueSets available for enum extraction`);
2633
2640
  }
2634
- const register = await registerFromManager(this.manager);
2641
+ const register = await registerFromManager(this.manager, logger);
2635
2642
  const valueSetSchemas = [];
2636
2643
  if (valueSets.length > 0) {
2637
- this.logger.progress(`Converting ${valueSets.length} ValueSets to TypeSchema`);
2644
+ this.logger?.progress(`Converting ${valueSets.length} ValueSets to TypeSchema`);
2638
2645
  let valueSetConvertedCount = 0;
2639
2646
  let valueSetFailedCount = 0;
2640
2647
  for (const vs of valueSets) {
2641
2648
  try {
2642
- const valueSetSchema = await transformValueSet(register, vs);
2649
+ const valueSetSchema = await transformValueSet(register, vs, logger);
2643
2650
  if (valueSetSchema) {
2644
2651
  valueSetSchemas.push(valueSetSchema);
2645
2652
  valueSetConvertedCount++;
2646
- this.logger.debug(`Converted ValueSet: ${vs.name || vs.id}`);
2653
+ this.logger?.debug(`Converted ValueSet: ${vs.name || vs.id}`);
2647
2654
  }
2648
2655
  } catch (error) {
2649
2656
  valueSetFailedCount++;
2650
- this.logger.warn(
2657
+ this.logger?.warn(
2651
2658
  `Failed to convert ValueSet ${vs.name || vs.id}: ${error instanceof Error ? error.message : String(error)}`
2652
2659
  );
2653
2660
  }
2654
2661
  }
2655
- this.logger.success(
2662
+ this.logger?.success(
2656
2663
  `ValueSet conversion completed: ${valueSetConvertedCount}/${valueSets.length} successful, ${valueSetFailedCount} failed`
2657
2664
  );
2658
2665
  }
2659
2666
  return valueSetSchemas;
2660
2667
  }
2661
- async generateFromPackage(packageName, packageVersion) {
2668
+ async generateFromPackage(packageName, packageVersion, logger) {
2662
2669
  await this.initializeCache();
2663
2670
  if (this.cache && !(this.cacheConfig?.forceRegenerate ?? false)) {
2664
2671
  const cachedSchemas = this.cache.getByPackage(packageName);
2665
2672
  if (cachedSchemas.length > 0) {
2666
- this.logger.info(
2673
+ this.logger?.info(
2667
2674
  `Using cached TypeSchemas for package: ${packageName} (${cachedSchemas.length} schemas)`
2668
2675
  );
2669
2676
  return cachedSchemas;
@@ -2674,10 +2681,9 @@ var TypeSchemaGenerator = class {
2674
2681
  version: packageVersion || "latest"
2675
2682
  };
2676
2683
  const register = await this.registerFromPackageMetas([packageInfo]);
2677
- const valueSets = await this.generateValueSetSchemas(register.allVs());
2678
- const fhirSchemas = (await Promise.all(register.allFs().map(async (fs2) => await transformFhirSchema(register, fs2)))).flat();
2684
+ const valueSets = await this.generateValueSetSchemas(register.allVs(), logger);
2685
+ const fhirSchemas = (await Promise.all(register.allFs().map(async (fs2) => await transformFhirSchema(register, fs2, logger)))).flat();
2679
2686
  const allSchemas = [...fhirSchemas, ...valueSets];
2680
- console.debug(111);
2681
2687
  if (this.cache) {
2682
2688
  for (const schema of allSchemas) {
2683
2689
  await this.cache.set(schema);
@@ -2694,7 +2700,7 @@ var TypeSchemaGenerator = class {
2694
2700
  if (!treeshakeList || treeshakeList.length === 0) {
2695
2701
  return structureDefinitions;
2696
2702
  }
2697
- this.logger.info(`Applying treeshaking filter for ResourceTypes: ${treeshakeList.join(", ")}`);
2703
+ this.logger?.info(`Applying treeshaking filter for ResourceTypes: ${treeshakeList.join(", ")}`);
2698
2704
  const allStructureDefinitions = /* @__PURE__ */ new Map();
2699
2705
  const realDependencies = /* @__PURE__ */ new Map();
2700
2706
  const referenceTargets = /* @__PURE__ */ new Map();
@@ -2718,7 +2724,7 @@ var TypeSchemaGenerator = class {
2718
2724
  if (allStructureDefinitions.has(resourceType)) {
2719
2725
  structureDefinitionsToKeep.add(resourceType);
2720
2726
  } else {
2721
- this.logger.warn(`ResourceType '${resourceType}' not found in structure definitions`);
2727
+ this.logger?.warn(`ResourceType '${resourceType}' not found in structure definitions`);
2722
2728
  }
2723
2729
  }
2724
2730
  const addRealDependenciesRecursively = (name, visited = /* @__PURE__ */ new Set()) => {
@@ -2754,9 +2760,9 @@ var TypeSchemaGenerator = class {
2754
2760
  }
2755
2761
  }
2756
2762
  if (excludedReferenceTargets.size > 0) {
2757
- this.logger.info(`Excluded reference-only targets: ${Array.from(excludedReferenceTargets).join(", ")}`);
2763
+ this.logger?.info(`Excluded reference-only targets: ${Array.from(excludedReferenceTargets).join(", ")}`);
2758
2764
  }
2759
- this.logger.success(
2765
+ this.logger?.success(
2760
2766
  `Treeshaking completed: kept ${filteredStructureDefinitions.length}/${structureDefinitions.length} structure definitions`
2761
2767
  );
2762
2768
  return filteredStructureDefinitions;
@@ -3045,10 +3051,10 @@ var TypeSchemaParser = class {
3045
3051
  };
3046
3052
 
3047
3053
  // src/typeschema/index.ts
3048
- var generateTypeSchemas = async (register) => {
3054
+ var generateTypeSchemas = async (register, logger) => {
3049
3055
  const fhirSchemas = [];
3050
3056
  for (const fhirSchema of register.allFs()) {
3051
- fhirSchemas.push(...await transformFhirSchema(register, fhirSchema));
3057
+ fhirSchemas.push(...await transformFhirSchema(register, fhirSchema, logger));
3052
3058
  }
3053
3059
  for (const vsSchema of register.allVs()) {
3054
3060
  fhirSchemas.push(await transformValueSet(register, vsSchema));
@@ -5094,6 +5100,13 @@ var capitalCase = (s) => {
5094
5100
  var pascalCase = (s) => {
5095
5101
  return words(s).map(capitalCase).join("");
5096
5102
  };
5103
+ var uppercaseFirstLetter = (str) => {
5104
+ if (!str || str.length === 0) return str;
5105
+ return str.charAt(0).toUpperCase() + str.slice(1);
5106
+ };
5107
+ var uppercaseFirstLetterOfEach = (strings) => {
5108
+ return strings.map((str) => uppercaseFirstLetter(str));
5109
+ };
5097
5110
  var FileSystemWriter = class {
5098
5111
  opts;
5099
5112
  currentDir;
@@ -5119,7 +5132,7 @@ var FileSystemWriter = class {
5119
5132
  if (fn.includes("/")) throw new Error(`Change file path separatly: ${fn}`);
5120
5133
  const fullFn = `${this.currentDir}/${fn}`;
5121
5134
  try {
5122
- this.currentFileDescriptor = fs.openSync(fn, "w");
5135
+ this.currentFileDescriptor = fs.openSync(fullFn, "w");
5123
5136
  this.writtenFilesSet.add(fn);
5124
5137
  this.logger()?.debug(`cat > '${fullFn}'`);
5125
5138
  gen();
@@ -5180,6 +5193,17 @@ var Writer = class extends FileSystemWriter {
5180
5193
  this.comment(...tokens);
5181
5194
  }
5182
5195
  }
5196
+ disclaimer() {
5197
+ return [
5198
+ "WARNING: This file is autogenerated by FHIR Schema Codegen.",
5199
+ "https://github.com/fhir-schema/fhir-schema-codegen",
5200
+ "Any manual changes made to this file may be overwritten."
5201
+ ];
5202
+ }
5203
+ generateDisclaimer() {
5204
+ this.disclaimer().forEach((e) => this.comment(e));
5205
+ this.line();
5206
+ }
5183
5207
  curlyBlock(tokens, gencontent, endTokens) {
5184
5208
  this.line(`${tokens.filter(Boolean).join(" ")} {`);
5185
5209
  this.indent();
@@ -5196,9 +5220,7 @@ var Writer = class extends FileSystemWriter {
5196
5220
  }
5197
5221
  };
5198
5222
 
5199
- // src/api/writer-generator/typescript.ts
5200
- var collectComplexTypes = (tss) => tss.filter((t) => t.identifier.kind === "complex-type");
5201
- var collectResources = (tss) => tss.filter((t) => t.identifier.kind === "resource");
5223
+ // src/typeschema/utils.ts
5202
5224
  var groupByPackages = (typeSchemas) => {
5203
5225
  const grouped = {};
5204
5226
  for (const ts of typeSchemas) {
@@ -5213,9 +5235,85 @@ var groupByPackages = (typeSchemas) => {
5213
5235
  }
5214
5236
  return grouped;
5215
5237
  };
5216
- var fileNameStem = (id) => {
5238
+ var collectComplexTypes = (tss) => tss.filter((t) => t.identifier.kind === "complex-type");
5239
+ var collectResources = (tss) => tss.filter((t) => t.identifier.kind === "resource");
5240
+ var notChoiceDeclaration = (field) => {
5241
+ if (field.choices) return void 0;
5242
+ if (field.choiceOf) return field;
5243
+ return field;
5244
+ };
5245
+ var resourceRelatives = (schemas) => {
5246
+ const regularSchemas = collectResources(schemas);
5247
+ const directPairs = [];
5248
+ for (const schema of regularSchemas) {
5249
+ if (schema.base) {
5250
+ directPairs.push({ parent: schema.base, child: schema.identifier });
5251
+ }
5252
+ }
5253
+ const allPairs = [...directPairs];
5254
+ const findTransitiveRelatives = (parentRef) => {
5255
+ const directChildren = directPairs.filter((pair) => pair.parent.name === parentRef.name).map((pair) => pair.child);
5256
+ const transitiveChildren = [];
5257
+ for (const child of directChildren) {
5258
+ transitiveChildren.push(...findTransitiveRelatives(child));
5259
+ }
5260
+ return [...directChildren, ...transitiveChildren];
5261
+ };
5262
+ for (const pair of directPairs) {
5263
+ const transitiveChildren = findTransitiveRelatives(pair.child);
5264
+ for (const transitiveChild of transitiveChildren) {
5265
+ if (!directPairs.some((dp) => dp.parent.name === pair.parent.name && dp.child.name === transitiveChild.name)) {
5266
+ allPairs.push({ parent: pair.parent, child: transitiveChild });
5267
+ }
5268
+ }
5269
+ }
5270
+ return allPairs;
5271
+ };
5272
+ var resourceChildren = (relatives, id) => {
5273
+ return relatives.filter((relative2) => relative2.parent.name === id.name).map((relative2) => relative2.child);
5274
+ };
5275
+
5276
+ // src/api/writer-generator/typescript.ts
5277
+ var primitiveType2tsType = {
5278
+ boolean: "boolean",
5279
+ instant: "string",
5280
+ time: "string",
5281
+ date: "string",
5282
+ dateTime: "string",
5283
+ decimal: "number",
5284
+ integer: "number",
5285
+ unsignedInt: "number",
5286
+ positiveInt: "number",
5287
+ integer64: "number",
5288
+ base64Binary: "string",
5289
+ uri: "string",
5290
+ url: "string",
5291
+ canonical: "string",
5292
+ oid: "string",
5293
+ uuid: "string",
5294
+ string: "string",
5295
+ code: "string",
5296
+ markdown: "string",
5297
+ id: "string",
5298
+ xhtml: "string"
5299
+ };
5300
+ var canonicalToName = (canonical, dropFragment = true) => {
5301
+ if (!canonical) return void 0;
5302
+ let localName = canonical.split("/").pop();
5303
+ if (dropFragment && localName?.includes("#")) {
5304
+ localName = localName.split("#")[0];
5305
+ }
5306
+ if (/^\d/.test(localName ?? "")) {
5307
+ localName = `number_${localName}`;
5308
+ }
5309
+ return localName?.replace(/[- ]/g, "_");
5310
+ };
5311
+ var tsBaseFileName = (id) => {
5217
5312
  return pascalCase(id.name);
5218
5313
  };
5314
+ var tsFileName = (id) => {
5315
+ return `${tsBaseFileName(id)}.ts`;
5316
+ };
5219
5317
  var normalizeName = (n) => {
5220
5318
  if (n === "extends") {
5221
5319
  return "extends_";
@@ -5225,43 +5323,155 @@ var normalizeName = (n) => {
5225
5323
  var resourceName = (id) => {
5226
5324
  return normalizeName(id.name);
5227
5325
  };
5326
+ var deriveNestedSchemaName = (url) => {
5327
+ const path = canonicalToName(url, false);
5328
+ if (!path) {
5329
+ return "";
5330
+ }
5331
+ const [resourceName2, fragment] = path.split("#");
5332
+ const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
5333
+ return [resourceName2, name].join("");
5334
+ };
5228
5335
  var TypeScript = class extends Writer {
5229
- tsImportFrom(tsPackage, ...entities) {
5230
- this.lineSM(`import { ${entities.join(", ")} } from '${tsPackage}'`);
5336
+ resourceRelatives = [];
5337
+ tsImport(tsPackageName, ...entities) {
5338
+ this.lineSM(`import { ${entities.join(", ")} } from '${tsPackageName}'`);
5231
5339
  }
5232
- generatePackageIndexFile(schemas) {
5340
+ generateFhirPackageIndexFile(schemas) {
5233
5341
  this.cat("index.ts", () => {
5234
5342
  let exports = schemas.map((schema) => ({
5235
5343
  identifier: schema.identifier,
5236
- fileName: fileNameStem(schema.identifier),
5237
- name: resourceName(schema.identifier)
5238
- })).sort((a, b) => a.name.localeCompare(b.name));
5239
- exports = Array.from(new Map(exports.map((exp) => [exp.name.toLowerCase(), exp])).values()).sort(
5240
- (a, b) => a.name.localeCompare(b.name)
5344
+ tsPackageName: tsBaseFileName(schema.identifier),
5345
+ resourceName: resourceName(schema.identifier)
5346
+ })).sort((a, b) => a.resourceName.localeCompare(b.resourceName));
5347
+ exports = Array.from(new Map(exports.map((exp) => [exp.resourceName.toLowerCase(), exp])).values()).sort(
5348
+ (a, b) => a.resourceName.localeCompare(b.resourceName)
5241
5349
  );
5242
5350
  for (const exp of exports) {
5243
5351
  this.debugComment(exp.identifier);
5244
- this.tsImportFrom(`./${exp.fileName}`, exp.name);
5352
+ this.tsImport(`./${exp.tsPackageName}`, exp.resourceName);
5245
5353
  }
5246
- this.lineSM(`export { ${exports.map((e) => e.name).join(", ")} }`);
5354
+ this.lineSM(`export { ${exports.map((e) => e.resourceName).join(", ")} }`);
5247
5355
  this.line("");
5248
5356
  this.curlyBlock(["export type ResourceTypeMap = "], () => {
5249
5357
  this.lineSM("User: Record<string, any>");
5250
5358
  exports.forEach((exp) => {
5251
5359
  this.debugComment(exp.identifier);
5252
- this.lineSM(`${exp.name}: ${exp.name}`);
5360
+ this.lineSM(`${exp.resourceName}: ${exp.resourceName}`);
5253
5361
  });
5254
5362
  });
5255
5363
  this.lineSM("export type ResourceType = keyof ResourceTypeMap");
5256
5364
  this.squareBlock(["export const resourceList: readonly ResourceType[] = "], () => {
5257
5365
  exports.forEach((exp) => {
5258
5366
  this.debugComment(exp.identifier);
5259
- this.line(`'${exp.name}', `);
5367
+ this.line(`'${exp.resourceName}', `);
5260
5368
  });
5261
5369
  });
5262
5370
  });
5263
5371
  }
5372
+ generateDependenciesImports(schema) {
5373
+ if (schema.dependencies) {
5374
+ const deps = [
5375
+ ...schema.dependencies.filter((dep) => ["complex-type", "resource", "logical"].includes(dep.kind)).map((dep) => ({
5376
+ tsPackage: `../${kebabCase(dep.package)}/${pascalCase(dep.name)}`,
5377
+ name: uppercaseFirstLetter(dep.name)
5378
+ })),
5379
+ ...schema.dependencies.filter((dep) => ["nested"].includes(dep.kind)).map((dep) => ({
5380
+ tsPackage: `../${kebabCase(dep.package)}/${pascalCase(canonicalToName(dep.url) ?? "")}`,
5381
+ name: deriveNestedSchemaName(dep.url)
5382
+ }))
5383
+ ].sort((a, b) => a.name.localeCompare(b.name));
5384
+ for (const dep of deps) {
5385
+ this.tsImport(dep.tsPackage, dep.name);
5386
+ }
5387
+ }
5388
+ }
5389
+ addFieldExtension(fieldName, field) {
5390
+ if (field.type.kind === "primitive-type") {
5391
+ this.lineSM(`_${normalizeName(fieldName)}?: Element`);
5392
+ }
5393
+ }
5394
+ generateType(schema) {
5395
+ var name;
5396
+ if (schema.identifier.name === "Reference") {
5397
+ name = "Reference<T extends string = string>";
5398
+ } else if (schema.identifier.kind === "nested") {
5399
+ name = normalizeName(deriveNestedSchemaName(schema.identifier.url));
5400
+ } else {
5401
+ name = normalizeName(schema.identifier.name);
5402
+ }
5403
+ const parent = canonicalToName(schema.base?.url);
5404
+ const extendsClause = parent && `extends ${parent}`;
5405
+ this.debugComment(schema.identifier);
5406
+ this.curlyBlock(["export", "interface", name, extendsClause], () => {
5407
+ if (!schema.fields) {
5408
+ return;
5409
+ }
5410
+ if (schema.identifier.kind === "resource") {
5411
+ const possibleResourceTypes = [schema.identifier];
5412
+ possibleResourceTypes.push(...resourceChildren(this.resourceRelatives, schema.identifier));
5413
+ this.lineSM(`resourceType: ${possibleResourceTypes.map((e) => `'${e.name}'`).join(" | ")}`);
5414
+ this.line();
5415
+ }
5416
+ const fields = Object.entries(schema.fields).sort((a, b) => a[0].localeCompare(b[0]));
5417
+ for (const [fieldName, anyField] of fields) {
5418
+ const field = notChoiceDeclaration(anyField);
5419
+ if (field === void 0) continue;
5420
+ this.debugComment(fieldName, ":", field);
5421
+ const fieldNameFixed = normalizeName(fieldName);
5422
+ const optionalSymbol = field.required ? "" : "?";
5423
+ const arraySymbol = field.array ? "[]" : "";
5424
+ if (field.type === void 0) {
5425
+ continue;
5426
+ }
5427
+ let type = field.type.name;
5428
+ if (field.type.kind === "nested") {
5429
+ type = deriveNestedSchemaName(field.type.url);
5430
+ }
5431
+ if (field.type.kind === "primitive-type") {
5432
+ type = primitiveType2tsType[field.type.name] ?? "string";
5433
+ }
5434
+ if (schema.identifier.name === "Reference" && fieldNameFixed === "reference") {
5435
+ type = "`${T}/${string}`";
5436
+ }
5437
+ if (field.reference?.length) {
5438
+ const references = field.reference.map((ref) => `'${ref.name}'`).join(" | ");
5439
+ type = `Reference<${references}>`;
5440
+ }
5441
+ if (field.enum) {
5442
+ type = field.enum.map((e) => `'${e}'`).join(" | ");
5443
+ }
5444
+ this.lineSM(`${fieldNameFixed}${optionalSymbol}:`, `${type}${arraySymbol}`);
5445
+ if (["resource", "complex-type"].includes(schema.identifier.kind)) {
5446
+ this.addFieldExtension(fieldName, field);
5447
+ }
5448
+ }
5449
+ });
5450
+ this.line();
5451
+ }
5452
+ generateNestedTypes(schema) {
5453
+ if (schema.nested) {
5454
+ this.line();
5455
+ for (const subtype of schema.nested) {
5456
+ this.generateType(subtype);
5457
+ }
5458
+ }
5459
+ }
5460
+ generateResourceModule(schema) {
5461
+ this.cat(`${tsFileName(schema.identifier)}`, () => {
5462
+ this.generateDisclaimer();
5463
+ if (["complex-type", "resource", "logical", "nested"].includes(schema.identifier.kind)) {
5464
+ this.generateDependenciesImports(schema);
5465
+ this.line();
5466
+ this.generateNestedTypes(schema);
5467
+ this.generateType(schema);
5468
+ } else {
5469
+ throw new Error(`Profile generation not implemented for kind: ${schema.identifier.kind}`);
5470
+ }
5471
+ });
5472
+ }
5264
5473
  generate(schemas) {
5474
+ this.resourceRelatives = resourceRelatives(schemas);
5265
5475
  const typesToGenerate = [
5266
5476
  ...collectComplexTypes(schemas),
5267
5477
  ...collectResources(schemas)
@@ -5273,7 +5483,10 @@ var TypeScript = class extends Writer {
5273
5483
  for (const [packageName, packageSchemas] of Object.entries(grouped)) {
5274
5484
  const tsPackageName = kebabCase(packageName);
5275
5485
  this.cd(tsPackageName, () => {
5276
- this.generatePackageIndexFile(packageSchemas);
5486
+ for (const schema of packageSchemas) {
5487
+ this.generateResourceModule(schema);
5488
+ }
5489
+ this.generateFhirPackageIndexFile(packageSchemas);
5277
5490
  });
5278
5491
  }
5279
5492
  });
@@ -5383,7 +5596,7 @@ var APIBuilder = class {
5383
5596
  const writerOpts = {
5384
5597
  outputDir: Path2.join(this.options.outputDir, "/types"),
5385
5598
  tabSize: 2,
5386
- withDebugComment: true,
5599
+ withDebugComment: false,
5387
5600
  commentLinePrefix: "//"
5388
5601
  };
5389
5602
  const effectiveOpts = { logger: this.logger, ...writerOpts, ...opts };
@@ -5440,7 +5653,7 @@ var APIBuilder = class {
5440
5653
  });
5441
5654
  await manager.init();
5442
5655
  const register = await registerFromManager(manager, this.logger);
5443
- const typeSchemas = await generateTypeSchemas(register);
5656
+ const typeSchemas = await generateTypeSchemas(register, this.logger);
5444
5657
  this.logger.debug(`Executing ${this.generators.size} generators`);
5445
5658
  await this.executeGenerators(result, typeSchemas);
5446
5659
  this.logger.info("Generation completed successfully");