@atomic-ehr/codegen 0.0.1 → 0.0.2-canary.20251114125643.cb2d5e2

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
@@ -8,6 +8,7 @@ import { CanonicalManager } from '@atomic-ehr/fhir-canonical-manager';
8
8
  import * as fhirschema from '@atomic-ehr/fhirschema';
9
9
  import { isStructureDefinition } from '@atomic-ehr/fhirschema';
10
10
  import pc from 'picocolors';
11
+ import * as YAML from 'yaml';
11
12
 
12
13
  var __defProp = Object.defineProperty;
13
14
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1397,6 +1398,18 @@ var init_IndexBuilder = __esm({
1397
1398
  });
1398
1399
 
1399
1400
  // src/typeschema/types.ts
1401
+ var extractNameFromCanonical = (canonical, dropFragment = true) => {
1402
+ let localName = canonical.split("/").pop();
1403
+ if (!localName) return void 0;
1404
+ if (dropFragment && localName.includes("#")) {
1405
+ localName = localName.split("#")[0];
1406
+ }
1407
+ if (!localName) return void 0;
1408
+ if (/^\d/.test(localName)) {
1409
+ localName = `number_${localName}`;
1410
+ }
1411
+ return localName;
1412
+ };
1400
1413
  var packageMetaToFhir = (packageMeta) => `${packageMeta.name}#${packageMeta.version}`;
1401
1414
  var packageMetaToNpm = (packageMeta) => `${packageMeta.name}@${packageMeta.version}`;
1402
1415
  var enrichFHIRSchema = (schema, packageMeta) => {
@@ -1429,6 +1442,9 @@ var isComplexTypeTypeSchema = (schema) => {
1429
1442
  var isResourceTypeSchema = (schema) => {
1430
1443
  return schema?.identifier.kind === "resource";
1431
1444
  };
1445
+ var isPrimitiveTypeSchema = (schema) => {
1446
+ return schema?.identifier.kind === "primitive-type";
1447
+ };
1432
1448
  var isLogicalTypeSchema = (schema) => {
1433
1449
  return schema?.identifier.kind === "logical";
1434
1450
  };
@@ -1438,6 +1454,9 @@ var isProfileTypeSchema = (schema) => {
1438
1454
  function isBindingSchema(schema) {
1439
1455
  return schema?.identifier.kind === "binding";
1440
1456
  }
1457
+ function isValueSetTypeSchema(schema) {
1458
+ return schema?.identifier.kind === "value-set";
1459
+ }
1441
1460
  var isNotChoiceDeclarationField = (field) => {
1442
1461
  if (!field) return false;
1443
1462
  return field.choices === void 0;
@@ -1447,10 +1466,10 @@ var isChoiceDeclarationField = (field) => {
1447
1466
  return field.choices !== void 0;
1448
1467
  };
1449
1468
  var isValueSet = (res) => {
1450
- return res.resourceType === "ValueSet";
1469
+ return res?.resourceType === "ValueSet";
1451
1470
  };
1452
1471
  var isCodeSystem = (res) => {
1453
- return res.resourceType === "CodeSystem";
1472
+ return res?.resourceType === "CodeSystem";
1454
1473
  };
1455
1474
  var enrichValueSet = (vs, packageMeta) => {
1456
1475
  if (!vs.url) throw new Error("ValueSet must have a URL");
@@ -1587,12 +1606,15 @@ function mkNestedTypes(register, fhirSchema, logger) {
1587
1606
  } else {
1588
1607
  baseName = element.type;
1589
1608
  }
1609
+ const baseUrl = register.ensureSpecializationCanonicalUrl(baseName);
1610
+ const baseFs = register.resolveFs(fhirSchema.package_meta, baseUrl);
1611
+ if (!baseFs) throw new Error(`Could not resolve base type ${baseName}`);
1590
1612
  const base = {
1591
1613
  kind: "complex-type",
1592
- package: fhirSchema.package_meta.name,
1593
- version: fhirSchema.package_meta.version,
1614
+ package: baseFs.package_meta.name,
1615
+ version: baseFs.package_meta.version,
1594
1616
  name: baseName,
1595
- url: register.ensureSpecializationCanonicalUrl(fhirSchema.package_meta, baseName)
1617
+ url: baseUrl
1596
1618
  };
1597
1619
  const fields = transformNestedElements(register, fhirSchema, path, element.elements, logger);
1598
1620
  const nestedType = {
@@ -1656,8 +1678,9 @@ function isExcluded(register, fhirSchema, path) {
1656
1678
  var buildReferences = (register, fhirSchema, element) => {
1657
1679
  if (!element.refers) return void 0;
1658
1680
  return element.refers.map((ref) => {
1659
- const curl = register.ensureSpecializationCanonicalUrl(fhirSchema.package_meta, ref);
1681
+ const curl = register.ensureSpecializationCanonicalUrl(ref);
1660
1682
  const fs4 = register.resolveFs(fhirSchema.package_meta, curl);
1683
+ if (!fs4) throw new Error(`Failed to resolve fs for ${curl}`);
1661
1684
  return mkIdentifier(fs4);
1662
1685
  });
1663
1686
  };
@@ -1666,9 +1689,12 @@ function buildFieldType(register, fhirSchema, path, element, logger) {
1666
1689
  const refPath = element.elementReference.slice(1).filter((_, i) => i % 2 === 1);
1667
1690
  return mkNestedIdentifier(register, fhirSchema, refPath, logger);
1668
1691
  } else if (element.type) {
1669
- const url = register.ensureSpecializationCanonicalUrl(fhirSchema.package_meta, element.type);
1692
+ const url = register.ensureSpecializationCanonicalUrl(element.type);
1670
1693
  const fieldFs = register.resolveFs(fhirSchema.package_meta, url);
1671
- if (!fieldFs) throw new Error(`Could not resolve field type: '${element.type}'`);
1694
+ if (!fieldFs)
1695
+ throw new Error(
1696
+ `Could not resolve field type: '${element.type}' (from '${fhirSchema.url}' in '${packageMetaToFhir(fhirSchema.package_meta)}')`
1697
+ );
1672
1698
  return mkIdentifier(fieldFs);
1673
1699
  } else if (element.choices) {
1674
1700
  return void 0;
@@ -1690,8 +1716,11 @@ var mkField = (register, fhirSchema, path, element, logger) => {
1690
1716
  enumValues = buildEnum(register, fhirSchema, element, logger);
1691
1717
  }
1692
1718
  }
1719
+ const fieldType = buildFieldType(register, fhirSchema, path, element, logger);
1720
+ if (!fieldType)
1721
+ logger?.warn(`Field type not found for '${fhirSchema.url}#${path.join(".")}' (${fhirSchema.derivation})`);
1693
1722
  return {
1694
- type: buildFieldType(register, fhirSchema, path, element, logger),
1723
+ type: fieldType,
1695
1724
  required: isRequired(register, fhirSchema, path),
1696
1725
  excluded: isExcluded(register, fhirSchema, path),
1697
1726
  reference: buildReferences(register, fhirSchema, element),
@@ -1711,8 +1740,9 @@ function isNestedElement(element) {
1711
1740
  return isBackbone || isElement || elementsWithoutType;
1712
1741
  }
1713
1742
  function mkNestedField(register, fhirSchema, path, element, logger) {
1743
+ const nestedIdentifier = mkNestedIdentifier(register, fhirSchema, path, logger);
1714
1744
  return {
1715
- type: mkNestedIdentifier(register, fhirSchema, path, logger),
1745
+ type: nestedIdentifier,
1716
1746
  array: element.array || false,
1717
1747
  required: isRequired(register, fhirSchema, path),
1718
1748
  excluded: isExcluded(register, fhirSchema, path)
@@ -1868,19 +1898,6 @@ function extractFieldDependencies(fields) {
1868
1898
  }
1869
1899
  return deps;
1870
1900
  }
1871
- function deduplicateDependencies(deps) {
1872
- const seen = /* @__PURE__ */ new Set();
1873
- const unique = [];
1874
- for (const dep of deps) {
1875
- const key = dep.url;
1876
- if (!seen.has(key)) {
1877
- seen.add(key);
1878
- unique.push(dep);
1879
- }
1880
- }
1881
- unique.sort((a, b) => a.name.localeCompare(b.name));
1882
- return unique;
1883
- }
1884
1901
  function isExtensionSchema(fhirSchema, _identifier) {
1885
1902
  if (fhirSchema.base === "Extension" || fhirSchema.base === "http://hl7.org/fhir/StructureDefinition/Extension") {
1886
1903
  return true;
@@ -1907,62 +1924,6 @@ async function transformValueSet(register, valueSet, logger) {
1907
1924
  compose: !concept ? valueSet.compose : void 0
1908
1925
  };
1909
1926
  }
1910
- async function transformExtension(fhirSchema, register, logger) {
1911
- try {
1912
- const identifier = mkIdentifier(fhirSchema);
1913
- let base;
1914
- if (fhirSchema.base && fhirSchema.base !== "Extension") {
1915
- const baseUrl = fhirSchema.base.includes("/") ? fhirSchema.base : `http://hl7.org/fhir/StructureDefinition/${fhirSchema.base}`;
1916
- const baseName = fhirSchema.base.split("/").pop() || fhirSchema.base;
1917
- base = {
1918
- kind: "complex-type",
1919
- package: "hl7.fhir.r4.core",
1920
- version: "4.0.1",
1921
- name: baseName,
1922
- url: baseUrl
1923
- };
1924
- } else {
1925
- base = {
1926
- kind: "complex-type",
1927
- package: "hl7.fhir.r4.core",
1928
- version: "4.0.1",
1929
- name: "Extension",
1930
- url: "http://hl7.org/fhir/StructureDefinition/Extension"
1931
- };
1932
- }
1933
- const extensionSchema = {
1934
- identifier,
1935
- base,
1936
- description: fhirSchema.description,
1937
- dependencies: [],
1938
- metadata: {
1939
- isExtension: true
1940
- // Mark as extension for file organization
1941
- }
1942
- };
1943
- if (base) {
1944
- extensionSchema.dependencies.push(base);
1945
- }
1946
- if (fhirSchema.elements) {
1947
- const fields = mkFields(register, fhirSchema, [], fhirSchema.elements, logger);
1948
- if (fields && Object.keys(fields).length > 0) {
1949
- extensionSchema.fields = fields;
1950
- extensionSchema.dependencies.push(...extractFieldDependencies(fields));
1951
- }
1952
- }
1953
- const nestedTypes = mkNestedTypes(register, fhirSchema, logger);
1954
- if (nestedTypes && nestedTypes.length > 0) {
1955
- extensionSchema.nested = nestedTypes;
1956
- extensionSchema.dependencies.push(...extractNestedDependencies(nestedTypes));
1957
- }
1958
- extensionSchema.dependencies = deduplicateDependencies(extensionSchema.dependencies);
1959
- extensionSchema.dependencies = extensionSchema.dependencies.filter((dep) => dep.url !== identifier.url);
1960
- return extensionSchema;
1961
- } catch (error) {
1962
- console.warn(`Failed to transform extension ${fhirSchema.name}: ${error}`);
1963
- return null;
1964
- }
1965
- }
1966
1927
  function extractDependencies(identifier, base, fields, nestedTypes) {
1967
1928
  const deps = [];
1968
1929
  if (base) deps.push(base);
@@ -1987,10 +1948,12 @@ function transformFhirSchemaResource(register, fhirSchema, logger) {
1987
1948
  if (fhirSchema.base && fhirSchema.type !== "Element") {
1988
1949
  const baseFs = register.resolveFs(
1989
1950
  fhirSchema.package_meta,
1990
- register.ensureSpecializationCanonicalUrl(fhirSchema.package_meta, fhirSchema.base)
1951
+ register.ensureSpecializationCanonicalUrl(fhirSchema.base)
1991
1952
  );
1992
1953
  if (!baseFs) {
1993
- throw new Error(`Base resource not found '${fhirSchema.base}' for '${fhirSchema.url}'`);
1954
+ throw new Error(
1955
+ `Base resource not found '${fhirSchema.base}' for <${fhirSchema.url}> from ${packageMetaToFhir(fhirSchema.package_meta)}`
1956
+ );
1994
1957
  }
1995
1958
  base = mkIdentifier(baseFs);
1996
1959
  }
@@ -2009,16 +1972,16 @@ function transformFhirSchemaResource(register, fhirSchema, logger) {
2009
1972
  return [typeSchema, ...bindingSchemas];
2010
1973
  }
2011
1974
  async function transformFhirSchema(register, fhirSchema, logger) {
2012
- const results = [];
2013
- mkIdentifier(fhirSchema);
2014
- if (isExtensionSchema(fhirSchema)) {
2015
- const extensionSchema = await transformExtension(fhirSchema, register, logger);
2016
- if (extensionSchema) {
2017
- results.push(extensionSchema);
2018
- }
2019
- return results;
1975
+ const schemas = transformFhirSchemaResource(register, fhirSchema, logger);
1976
+ if (isExtensionSchema(fhirSchema, mkIdentifier(fhirSchema))) {
1977
+ const schema = schemas[0];
1978
+ if (!schema) throw new Error(`Expected schema to be defined`);
1979
+ schema.metadata = {
1980
+ isExtension: true
1981
+ // Mark as extension for file organization
1982
+ };
2020
1983
  }
2021
- return transformFhirSchemaResource(register, fhirSchema, logger);
1984
+ return schemas;
2022
1985
  }
2023
1986
  var TypeSchemaCache = class {
2024
1987
  cache = /* @__PURE__ */ new Map();
@@ -2360,13 +2323,8 @@ new CodegenLogger();
2360
2323
  function createLogger(options = {}) {
2361
2324
  return new CodegenLogger(options);
2362
2325
  }
2363
- var readPackageJSON = async (workDir, packageMeta) => {
2364
- const packageJSONFileName = Path4.join(workDir, "node_modules", packageMeta.name, "package.json");
2365
- const packageJSON = JSON.parse(await afs2.readFile(packageJSONFileName, "utf8"));
2366
- return packageJSON;
2367
- };
2368
- var readPackageDependencies = async (workDir, packageMeta) => {
2369
- const packageJSON = await readPackageJSON(workDir, packageMeta);
2326
+ var readPackageDependencies = async (manager, packageMeta) => {
2327
+ const packageJSON = await manager.packageJson(packageMeta.name);
2370
2328
  const dependencies = packageJSON.dependencies;
2371
2329
  if (dependencies !== void 0) {
2372
2330
  return Object.entries(dependencies).map(([name, version]) => {
@@ -2376,69 +2334,50 @@ var readPackageDependencies = async (workDir, packageMeta) => {
2376
2334
  return [];
2377
2335
  };
2378
2336
  var mkEmptyPkgIndex = (pkg) => {
2379
- return { pkg, nameResolution: {}, canonicalResolution: {}, fhirSchemas: {}, valueSets: {} };
2337
+ return {
2338
+ pkg,
2339
+ canonicalResolution: {},
2340
+ fhirSchemas: {},
2341
+ valueSets: {}
2342
+ };
2380
2343
  };
2381
- var mkPackageAwareResolver = async (manager, pkg, deep = 0, _logger) => {
2382
- const options = {};
2383
- const deps = await readPackageDependencies("tmp/fhir", pkg);
2384
- for (const dep of deps) {
2385
- const depOptions = mkPackageAwareResolver(manager, dep, deep);
2386
- Object.assign(options, depOptions);
2387
- }
2344
+ var mkPackageAwareResolver = async (manager, pkg, deep, acc, logger) => {
2388
2345
  const pkgId = packageMetaToFhir(pkg);
2389
- if (!options[pkgId]) options[pkgId] = mkEmptyPkgIndex(pkg);
2346
+ logger?.info(`${" ".repeat(deep * 2)}+ ${pkgId}`);
2347
+ if (acc[pkgId]) return acc[pkgId];
2348
+ const index = mkEmptyPkgIndex(pkg);
2390
2349
  for (const resource of await manager.search({ package: pkg })) {
2391
2350
  const rawUrl = resource.url;
2392
2351
  if (!rawUrl) continue;
2393
2352
  if (!(isStructureDefinition(resource) || isValueSet(resource) || isCodeSystem(resource))) continue;
2394
2353
  const url = rawUrl;
2395
- if (!options[pkgId].canonicalResolution[url]) {
2396
- options[pkgId].canonicalResolution[url] = [];
2397
- for (const [depPkgId, { canonicalResolution }] of Object.entries(options)) {
2398
- if (pkgId === depPkgId) continue;
2399
- if (!canonicalResolution[url]) continue;
2400
- for (const deepRes of canonicalResolution[url]) {
2401
- options[pkgId].canonicalResolution[url].push({
2402
- deep: deepRes.deep + 1,
2403
- resource: deepRes.resource,
2404
- packageMeta: deepRes.packageMeta
2405
- });
2406
- }
2407
- }
2408
- }
2409
- options[pkgId].canonicalResolution[url].push({ deep, packageMeta: pkg, resource });
2410
- options[pkgId].canonicalResolution[url].sort((a, b) => a.deep - b.deep);
2411
- const name = resource.name;
2412
- if (name && isStructureDefinition(resource) && (resource.derivation === "specialization" || resource.derivation === void 0)) {
2413
- if (!options[pkgId].nameResolution[name]) {
2414
- options[pkgId].nameResolution[name] = resource.url;
2415
- } else {
2416
- throw new Error(`Duplicate name ${name} in package ${pkgId}`);
2417
- }
2354
+ if (index.canonicalResolution[url]) logger?.dry_warn(`Duplicate canonical URL: ${url} at ${pkgId}.`);
2355
+ index.canonicalResolution[url] = [{ deep, pkg, pkgId, resource }];
2356
+ }
2357
+ const deps = await readPackageDependencies(manager, pkg);
2358
+ for (const depPkg of deps) {
2359
+ const { canonicalResolution } = await mkPackageAwareResolver(manager, depPkg, deep + 1, acc, logger);
2360
+ for (const [surl, resolutions] of Object.entries(canonicalResolution)) {
2361
+ const url = surl;
2362
+ index.canonicalResolution[url] = [...index.canonicalResolution[url] || [], ...resolutions];
2418
2363
  }
2419
2364
  }
2420
- return options;
2421
- };
2422
- var packageAwareResolveName = (resolver, pkg, name) => {
2423
- const pkgId = packageMetaToFhir(pkg);
2424
- if (!resolver[pkgId]) throw new Error(`Package ${pkgId} not found`);
2425
- const resource = resolver[pkgId].nameResolution[name];
2426
- return resource;
2365
+ for (const resolutionOptions of Object.values(index.canonicalResolution)) {
2366
+ resolutionOptions.sort((a, b) => a.deep - b.deep);
2367
+ }
2368
+ acc[pkgId] = index;
2369
+ return index;
2427
2370
  };
2428
- var packageAgnosticResolveCanonical = (resolver, url, logger) => {
2371
+ var packageAgnosticResolveCanonical = (resolver, url, _logger) => {
2429
2372
  const options = Object.values(resolver).flatMap((pkg) => pkg.canonicalResolution[url]);
2430
2373
  if (!options) throw new Error(`No canonical resolution found for ${url} in any package`);
2431
- if (options.length > 1)
2432
- logger?.dry_warn(
2433
- `Multiple canonical resolutions found for ${url} in: ${JSON.stringify(options, void 0, 2)}`
2434
- );
2435
2374
  return options[0]?.resource;
2436
2375
  };
2437
- var registerFromManager = async (manager, { logger, fallbackPackageForNameResolution }) => {
2438
- const packages = await manager.packages();
2376
+ var registerFromManager = async (manager, { logger, fallbackPackageForNameResolution, focusedPackages }) => {
2377
+ const packages = focusedPackages ?? await manager.packages();
2439
2378
  const resolver = {};
2440
2379
  for (const pkg of packages) {
2441
- Object.assign(resolver, await mkPackageAwareResolver(manager, pkg));
2380
+ await mkPackageAwareResolver(manager, pkg, 0, resolver, logger);
2442
2381
  }
2443
2382
  for (const { pkg, canonicalResolution } of Object.values(resolver)) {
2444
2383
  const pkgId = packageMetaToFhir(pkg);
@@ -2446,19 +2385,24 @@ var registerFromManager = async (manager, { logger, fallbackPackageForNameResolu
2446
2385
  let counter = 0;
2447
2386
  logger?.info(`FHIR Schema conversion for '${packageMetaToFhir(pkg)}' begins...`);
2448
2387
  for (const [_url, options] of Object.entries(canonicalResolution)) {
2449
- const resource = options[0]?.resource;
2450
- if (!resource) throw new Error(`Resource not found`);
2388
+ const resolition = options[0];
2389
+ if (!resolition) throw new Error(`Resource not found`);
2390
+ const resource = resolition.resource;
2391
+ const resourcePkg = resolition.pkg;
2451
2392
  if (isStructureDefinition(resource)) {
2452
- const rfs = enrichFHIRSchema(fhirschema.translate(resource), pkg);
2393
+ const rfs = enrichFHIRSchema(
2394
+ fhirschema.translate(resource),
2395
+ resourcePkg
2396
+ );
2453
2397
  counter++;
2454
2398
  resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2455
2399
  }
2456
2400
  if (isValueSet(resource)) {
2457
- const rvs = enrichValueSet(resource, pkg);
2401
+ const rvs = enrichValueSet(resource, resourcePkg);
2458
2402
  resolver[pkgId].valueSets[rvs.url] = rvs;
2459
2403
  }
2460
2404
  }
2461
- logger?.success(`FHIR Schema conversion for '${packageMetaToFhir(pkg)}' completed: ${counter} successful`);
2405
+ logger?.info(`FHIR Schema conversion for '${packageMetaToFhir(pkg)}' completed: ${counter} successful`);
2462
2406
  }
2463
2407
  const resolveFs = (pkg, canonicalUrl) => {
2464
2408
  return resolver[packageMetaToFhir(pkg)]?.fhirSchemas[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.fhirSchemas[canonicalUrl];
@@ -2466,14 +2410,19 @@ var registerFromManager = async (manager, { logger, fallbackPackageForNameResolu
2466
2410
  const resolveVs = (pkg, canonicalUrl) => {
2467
2411
  return resolver[packageMetaToFhir(pkg)]?.valueSets[canonicalUrl] || fallbackPackageForNameResolution && resolver[packageMetaToFhir(fallbackPackageForNameResolution)]?.valueSets[canonicalUrl];
2468
2412
  };
2469
- const ensureSpecializationCanonicalUrl = (pkg, name) => packageAwareResolveName(resolver, pkg, name) || fallbackPackageForNameResolution && packageAwareResolveName(resolver, fallbackPackageForNameResolution, name) || name;
2413
+ const ensureSpecializationCanonicalUrl = (name) => name.match(/^[a-zA-Z0-9]+$/) && `http://hl7.org/fhir/StructureDefinition/${name}` || name;
2470
2414
  const resolveFsGenealogy = (pkg, canonicalUrl) => {
2471
2415
  let fs4 = resolveFs(pkg, canonicalUrl);
2472
- if (fs4 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
2416
+ if (fs4 === void 0) throw new Error(`Failed to resolve FHIR Schema: '${canonicalUrl}'`);
2473
2417
  const genealogy = [fs4];
2474
2418
  while (fs4?.base) {
2475
- fs4 = resolveFs(fs4.package_meta, fs4.base) || resolveFs(fs4.package_meta, ensureSpecializationCanonicalUrl(fs4.package_meta, fs4.base));
2476
- if (fs4 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
2419
+ const pkg2 = fs4.package_meta;
2420
+ const baseUrl = ensureSpecializationCanonicalUrl(fs4.base);
2421
+ fs4 = resolveFs(pkg2, baseUrl);
2422
+ if (fs4 === void 0)
2423
+ throw new Error(
2424
+ `Failed to resolve FHIR Schema base for '${canonicalUrl}'. Problem: '${baseUrl}' from '${packageMetaToFhir(pkg2)}'`
2425
+ );
2477
2426
  genealogy.push(fs4);
2478
2427
  }
2479
2428
  return genealogy;
@@ -2501,11 +2450,10 @@ var registerFromManager = async (manager, { logger, fallbackPackageForNameResolu
2501
2450
  };
2502
2451
  return {
2503
2452
  ...manager,
2504
- unsafeAppendFs(fs4) {
2453
+ testAppendFs(fs4) {
2505
2454
  const rfs = enrichFHIRSchema(fs4);
2506
2455
  const pkgId = packageMetaToFhir(rfs.package_meta);
2507
2456
  if (!resolver[pkgId]) resolver[pkgId] = mkEmptyPkgIndex(rfs.package_meta);
2508
- resolver[pkgId].nameResolution[rfs.name] = rfs.url;
2509
2457
  resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2510
2458
  },
2511
2459
  resolveFs,
@@ -2513,16 +2461,17 @@ var registerFromManager = async (manager, { logger, fallbackPackageForNameResolu
2513
2461
  resolveFsSpecializations,
2514
2462
  ensureSpecializationCanonicalUrl,
2515
2463
  resolveSd: (_pkg, canonicalUrl) => {
2516
- const res = packageAgnosticResolveCanonical(resolver, canonicalUrl, logger);
2464
+ const res = packageAgnosticResolveCanonical(resolver, canonicalUrl);
2517
2465
  if (isStructureDefinition(res)) return res;
2518
2466
  return void 0;
2519
2467
  },
2520
2468
  allFs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.fhirSchemas)),
2521
2469
  allVs: () => Object.values(resolver).flatMap((pkgIndex) => Object.values(pkgIndex.valueSets)),
2522
2470
  resolveVs,
2523
- resolveAny: (canonicalUrl) => packageAgnosticResolveCanonical(resolver, canonicalUrl, logger),
2471
+ resolveAny: (canonicalUrl) => packageAgnosticResolveCanonical(resolver, canonicalUrl),
2524
2472
  resolveElementSnapshot,
2525
- getAllElementKeys
2473
+ getAllElementKeys,
2474
+ resolver
2526
2475
  };
2527
2476
  };
2528
2477
  var resolveFsElementGenealogy = (genealogy, path) => {
@@ -2567,10 +2516,10 @@ var TypeSchemaGenerator = class {
2567
2516
  }
2568
2517
  }
2569
2518
  async registerFromPackageMetas(packageMetas) {
2570
- const packageNames = packageMetas.map((meta) => `${meta.name}${meta.version}`);
2519
+ const packageNames = packageMetas.map(packageMetaToFhir);
2571
2520
  this.logger?.step(`Loading FHIR packages: ${packageNames.join(", ")}`);
2572
2521
  await this.manager.init();
2573
- return registerFromManager(this.manager, {});
2522
+ return registerFromManager(this.manager, { focusedPackages: packageMetas });
2574
2523
  }
2575
2524
  generateFhirSchemas(structureDefinitions) {
2576
2525
  this.logger?.progress(`Converting ${structureDefinitions.length} StructureDefinitions to FHIRSchemas`);
@@ -3013,9 +2962,29 @@ var TypeSchemaParser = class {
3013
2962
  };
3014
2963
 
3015
2964
  // src/typeschema/index.ts
2965
+ var codeableReferenceInR4 = "Use CodeableReference which is not provided by FHIR R4.";
2966
+ var availabilityInR4 = "Use Availability which is not provided by FHIR R4.";
2967
+ var skipMe = {
2968
+ "hl7.fhir.uv.extensions.r4#1.0.0": {
2969
+ "http://hl7.org/fhir/StructureDefinition/extended-contact-availability": availabilityInR4,
2970
+ "http://hl7.org/fhir/StructureDefinition/immunization-procedure": codeableReferenceInR4,
2971
+ "http://hl7.org/fhir/StructureDefinition/specimen-additive": codeableReferenceInR4,
2972
+ "http://hl7.org/fhir/StructureDefinition/workflow-barrier": codeableReferenceInR4,
2973
+ "http://hl7.org/fhir/StructureDefinition/workflow-protectiveFactor": codeableReferenceInR4,
2974
+ "http://hl7.org/fhir/StructureDefinition/workflow-reason": codeableReferenceInR4
2975
+ },
2976
+ "hl7.fhir.r5.core#5.0.0": {
2977
+ "http://hl7.org/fhir/StructureDefinition/shareablecodesystem": "FIXME: CodeSystem.concept.concept defined by ElementReference. FHIR Schema generator output broken value in it, so we just skip it for now."
2978
+ }
2979
+ };
3016
2980
  var generateTypeSchemas = async (register, logger) => {
3017
2981
  const fhirSchemas = [];
3018
2982
  for (const fhirSchema of register.allFs()) {
2983
+ const pkgId = packageMetaToFhir(fhirSchema.package_meta);
2984
+ if (skipMe[pkgId]?.[fhirSchema.url]) {
2985
+ logger?.dry_warn(`Skip ${fhirSchema.url} from ${pkgId}. Reason: ${skipMe[pkgId]?.[fhirSchema.url]}`);
2986
+ continue;
2987
+ }
3019
2988
  fhirSchemas.push(...await transformFhirSchema(register, fhirSchema, logger));
3020
2989
  }
3021
2990
  for (const vsSchema of register.allVs()) {
@@ -3050,23 +3019,9 @@ var uppercaseFirstLetter = (str) => {
3050
3019
  var uppercaseFirstLetterOfEach = (strings) => {
3051
3020
  return strings.map((str) => uppercaseFirstLetter(str));
3052
3021
  };
3053
- function deepEqual(obj1, obj2) {
3054
- if (obj1 === obj2) return true;
3055
- if (obj1 === null || obj2 === null || typeof obj1 !== "object" || typeof obj2 !== "object") {
3056
- return false;
3057
- }
3058
- if (Array.isArray(obj1) && Array.isArray(obj2)) {
3059
- if (obj1.length !== obj2.length) return false;
3060
- return obj1.every((item, index) => deepEqual(item, obj2[index]));
3061
- }
3062
- if (Array.isArray(obj1) || Array.isArray(obj2)) {
3063
- return false;
3064
- }
3065
- const keys1 = Object.keys(obj1);
3066
- const keys2 = Object.keys(obj2);
3067
- if (keys1.length !== keys2.length) return false;
3068
- return keys1.every((key) => keys2.includes(key) && deepEqual(obj1[key], obj2[key]));
3069
- }
3022
+ var typeSchemaInfo = (schema) => {
3023
+ return `<${schema.identifier.url}> from ${schema.identifier.package}#${schema.identifier.version}`;
3024
+ };
3070
3025
  var FileSystemWriter = class {
3071
3026
  opts;
3072
3027
  currentDir;
@@ -3080,12 +3035,14 @@ var FileSystemWriter = class {
3080
3035
  return this.opts.logger;
3081
3036
  }
3082
3037
  cd(path, gen) {
3038
+ const prev = this.currentDir;
3083
3039
  this.currentDir = path.startsWith("/") ? Path4.join(this.opts.outputDir, path) : Path4.join(this.currentDir, path);
3084
3040
  if (!fs.existsSync(this.currentDir)) {
3085
3041
  fs.mkdirSync(this.currentDir, { recursive: true });
3086
3042
  }
3087
3043
  this.logger()?.debug(`cd '${this.currentDir}'`);
3088
3044
  gen();
3045
+ this.currentDir = prev;
3089
3046
  }
3090
3047
  cat(fn, gen) {
3091
3048
  if (this.currentFileDescriptor) throw new Error("Can't open file in file");
@@ -3098,6 +3055,7 @@ var FileSystemWriter = class {
3098
3055
  gen();
3099
3056
  } finally {
3100
3057
  if (this.currentFileDescriptor) {
3058
+ fs.fsyncSync(this.currentFileDescriptor);
3101
3059
  fs.closeSync(this.currentFileDescriptor);
3102
3060
  }
3103
3061
  this.currentFileDescriptor = void 0;
@@ -3512,22 +3470,75 @@ var CSharp = class extends Writer {
3512
3470
  fs__default.copyFileSync(sourceFile, destFile);
3513
3471
  }
3514
3472
  };
3515
-
3516
- // src/typeschema/utils.ts
3517
3473
  var groupByPackages = (typeSchemas) => {
3518
3474
  const grouped = {};
3519
3475
  for (const ts of typeSchemas) {
3520
- const packageName = ts.identifier.package;
3521
- if (!grouped[packageName]) {
3522
- grouped[packageName] = [];
3523
- }
3524
- grouped[packageName].push(ts);
3476
+ const pkgName = ts.identifier.package;
3477
+ if (!grouped[pkgName]) grouped[pkgName] = [];
3478
+ grouped[pkgName].push(ts);
3525
3479
  }
3526
- for (const [_packageName, typeSchemas2] of Object.entries(grouped)) {
3527
- typeSchemas2.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
3480
+ for (const [packageName, typeSchemas2] of Object.entries(grouped)) {
3481
+ const dict = {};
3482
+ for (const ts of typeSchemas2) {
3483
+ dict[JSON.stringify(ts.identifier)] = ts;
3484
+ }
3485
+ const tmp = Object.values(dict);
3486
+ tmp.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
3487
+ grouped[packageName] = tmp;
3528
3488
  }
3529
3489
  return grouped;
3530
3490
  };
3491
+ var treeShakeTypeSchema = (schema, rule, _logger) => {
3492
+ schema = structuredClone(schema);
3493
+ if (isPrimitiveTypeSchema(schema) || isValueSetTypeSchema(schema) || isBindingSchema(schema)) return schema;
3494
+ for (const fieldName of rule.ignoreFields ?? []) {
3495
+ if (schema.fields && !schema.fields[fieldName]) throw new Error(`Field ${fieldName} not found`);
3496
+ if (schema.fields) {
3497
+ delete schema.fields[fieldName];
3498
+ }
3499
+ }
3500
+ schema.dependencies = extractDependencies(schema.identifier, schema.base, schema.fields, schema.nested);
3501
+ return schema;
3502
+ };
3503
+ var treeShake = (tsIndex, treeShake2, logger) => {
3504
+ const focusedSchemas = [];
3505
+ for (const [pkgId, requires] of Object.entries(treeShake2)) {
3506
+ for (const [url, rule] of Object.entries(requires)) {
3507
+ const schema = tsIndex.resolveByUrl(pkgId, url);
3508
+ if (!schema) throw new Error(`Schema not found for ${pkgId} ${url}`);
3509
+ const shaked2 = treeShakeTypeSchema(schema, rule);
3510
+ focusedSchemas.push(shaked2);
3511
+ }
3512
+ }
3513
+ const collectDeps = (schemas, acc) => {
3514
+ if (schemas.length === 0) return Object.values(acc);
3515
+ for (const schema of schemas) {
3516
+ acc[JSON.stringify(schema.identifier)] = schema;
3517
+ }
3518
+ const newSchemas = [];
3519
+ for (const schema of schemas) {
3520
+ if (isSpecializationTypeSchema(schema)) {
3521
+ if (!schema.dependencies) continue;
3522
+ schema.dependencies.forEach((dep) => {
3523
+ const depSchema = tsIndex.resolve(dep);
3524
+ if (!depSchema) throw new Error(`Schema not found for ${dep}`);
3525
+ const id = JSON.stringify(depSchema.identifier);
3526
+ if (!acc[id]) newSchemas.push(depSchema);
3527
+ });
3528
+ if (schema.nested) {
3529
+ for (const nest of schema.nested) {
3530
+ if (isNestedIdentifier(nest.identifier)) continue;
3531
+ const id = JSON.stringify(nest.identifier);
3532
+ if (!acc[id]) newSchemas.push(nest);
3533
+ }
3534
+ }
3535
+ }
3536
+ }
3537
+ return collectDeps(newSchemas, acc);
3538
+ };
3539
+ const shaked = collectDeps(focusedSchemas, {});
3540
+ return mkTypeSchemaIndex(shaked, logger);
3541
+ };
3531
3542
  var resourceRelatives = (schemas) => {
3532
3543
  const regularSchemas = schemas.filter(isResourceTypeSchema);
3533
3544
  const directPairs = [];
@@ -3564,7 +3575,8 @@ var mkTypeSchemaIndex = (schemas, logger) => {
3564
3575
  if (index[url][schema.identifier.package] && pkg !== "shared") {
3565
3576
  const r1 = JSON.stringify(schema.identifier, void 0, 2);
3566
3577
  const r2 = JSON.stringify(index[url][pkg]?.identifier, void 0, 2);
3567
- throw new Error(`Duplicate schema: ${r1} and ${r2}`);
3578
+ if (r1 !== r2) throw new Error(`Duplicate schema: ${r1} and ${r2}`);
3579
+ return;
3568
3580
  }
3569
3581
  index[url][pkg] = schema;
3570
3582
  };
@@ -3573,6 +3585,7 @@ var mkTypeSchemaIndex = (schemas, logger) => {
3573
3585
  }
3574
3586
  const relations = resourceRelatives(schemas);
3575
3587
  const resolve2 = (id) => index[id.url]?.[id.package];
3588
+ const resolveByUrl = (pkgName, url) => index[url]?.[pkgName];
3576
3589
  const resourceChildren = (id) => {
3577
3590
  return relations.filter((relative2) => relative2.parent.name === id.name).map((relative2) => relative2.child);
3578
3591
  };
@@ -3585,6 +3598,9 @@ var mkTypeSchemaIndex = (schemas, logger) => {
3585
3598
  if (base === void 0) break;
3586
3599
  const resolved = resolve2(base);
3587
3600
  if (!resolved) {
3601
+ logger?.warn(
3602
+ `Failed to resolve base type: ${res.map((e) => `${e.identifier.url} (${e.identifier.kind})`).join(", ")}`
3603
+ );
3588
3604
  return void 0;
3589
3605
  }
3590
3606
  cur = resolved;
@@ -3622,7 +3638,10 @@ var mkTypeSchemaIndex = (schemas, logger) => {
3622
3638
  if (!schema2.fields) continue;
3623
3639
  for (const [fieldName, fieldConstraints] of Object.entries(schema2.fields)) {
3624
3640
  if (mergedFields[fieldName]) {
3625
- mergedFields[fieldName] = { ...mergedFields[fieldName], ...fieldConstraints };
3641
+ mergedFields[fieldName] = {
3642
+ ...mergedFields[fieldName],
3643
+ ...fieldConstraints
3644
+ };
3626
3645
  } else {
3627
3646
  mergedFields[fieldName] = { ...fieldConstraints };
3628
3647
  }
@@ -3647,6 +3666,28 @@ var mkTypeSchemaIndex = (schemas, logger) => {
3647
3666
  return schema.fields?.meta !== void 0;
3648
3667
  });
3649
3668
  };
3669
+ const exportTree = async (filename) => {
3670
+ const tree = {};
3671
+ for (const [pkgId, shemas] of Object.entries(groupByPackages(schemas))) {
3672
+ tree[pkgId] = {
3673
+ "primitive-type": {},
3674
+ "complex-type": {},
3675
+ resource: {},
3676
+ "value-set": {},
3677
+ nested: {},
3678
+ binding: {},
3679
+ profile: {},
3680
+ logical: {}
3681
+ };
3682
+ for (const schema of shemas) {
3683
+ schema.identifier;
3684
+ tree[pkgId][schema.identifier.kind][schema.identifier.url] = {};
3685
+ }
3686
+ }
3687
+ const raw = filename.endsWith(".yaml") ? YAML.stringify(tree) : JSON.stringify(tree, void 0, 2);
3688
+ await afs2.mkdir(Path4.dirname(filename), { recursive: true });
3689
+ await afs2.writeFile(filename, raw);
3690
+ };
3650
3691
  return {
3651
3692
  _schemaIndex: index,
3652
3693
  _relations: relations,
@@ -3655,13 +3696,15 @@ var mkTypeSchemaIndex = (schemas, logger) => {
3655
3696
  collectLogicalModels: () => schemas.filter(isLogicalTypeSchema),
3656
3697
  collectProfiles: () => schemas.filter(isProfileTypeSchema),
3657
3698
  resolve: resolve2,
3699
+ resolveByUrl,
3658
3700
  resourceChildren,
3659
3701
  tryHierarchy,
3660
3702
  hierarchy,
3661
3703
  findLastSpecialization,
3662
3704
  findLastSpecializationByIdentifier,
3663
3705
  flatProfile,
3664
- isWithMetaField
3706
+ isWithMetaField,
3707
+ exportTree
3665
3708
  };
3666
3709
  };
3667
3710
 
@@ -4179,7 +4222,7 @@ var BaseGenerator = class {
4179
4222
  * This is the main method that orchestrates the entire generation process
4180
4223
  * @param schemas - Array of TypeSchema documents
4181
4224
  */
4182
- async generate(schemas) {
4225
+ async generate({ schemas }) {
4183
4226
  return this.errorBoundary.withErrorBoundary(
4184
4227
  async () => {
4185
4228
  this.generationStartTime = performance.now();
@@ -4219,7 +4262,7 @@ var BaseGenerator = class {
4219
4262
  return result;
4220
4263
  };
4221
4264
  try {
4222
- const result = await this.generate(schemas);
4265
+ const result = await this.generate({ schemas, index: null });
4223
4266
  result.forEach((file) => {
4224
4267
  const mockResult = mockWriteResults.get(file.filename);
4225
4268
  if (mockResult) {
@@ -5527,10 +5570,10 @@ ${nestedInterfaces}`;
5527
5570
  /**
5528
5571
  * Override generate to clean directory first
5529
5572
  */
5530
- async generate(schemas) {
5573
+ async generate(input) {
5531
5574
  await this.fileManager.cleanDirectory();
5532
5575
  this.logger.debug("Cleaned output directory before generation");
5533
- return super.generate(schemas);
5576
+ return super.generate(input);
5534
5577
  }
5535
5578
  /**
5536
5579
  * Run post-generation hooks - generate utility files
@@ -5730,15 +5773,8 @@ var tsModuleFileName = (id) => {
5730
5773
  };
5731
5774
  var canonicalToName2 = (canonical, dropFragment = true) => {
5732
5775
  if (!canonical) return void 0;
5733
- let localName = canonical.split("/").pop();
5734
- if (!localName) return void 0;
5735
- if (dropFragment && localName.includes("#")) {
5736
- localName = localName.split("#")[0];
5737
- }
5776
+ const localName = extractNameFromCanonical(canonical, dropFragment);
5738
5777
  if (!localName) return void 0;
5739
- if (/^\d/.test(localName)) {
5740
- localName = `number_${localName}`;
5741
- }
5742
5778
  return normalizeTsName(localName);
5743
5779
  };
5744
5780
  var tsResourceName = (id) => {
@@ -5794,12 +5830,14 @@ var TypeScript = class extends Writer {
5794
5830
  if (["complex-type", "resource", "logical"].includes(dep.kind)) {
5795
5831
  imports.push({
5796
5832
  tsPackage: `../${kebabCase(dep.package)}/${pascalCase(dep.name)}`,
5797
- name: uppercaseFirstLetter(dep.name)
5833
+ name: uppercaseFirstLetter(dep.name),
5834
+ dep
5798
5835
  });
5799
5836
  } else if (isNestedIdentifier(dep)) {
5800
5837
  imports.push({
5801
5838
  tsPackage: `../${kebabCase(dep.package)}/${pascalCase(canonicalToName2(dep.url) ?? "")}`,
5802
- name: tsResourceName(dep)
5839
+ name: tsResourceName(dep),
5840
+ dep
5803
5841
  });
5804
5842
  } else {
5805
5843
  skipped.push(dep);
@@ -5807,6 +5845,7 @@ var TypeScript = class extends Writer {
5807
5845
  }
5808
5846
  imports.sort((a, b) => a.name.localeCompare(b.name));
5809
5847
  for (const dep of imports) {
5848
+ this.debugComment(dep.dep);
5810
5849
  this.tsImportType(dep.tsPackage, dep.name);
5811
5850
  }
5812
5851
  for (const dep of skipped) {
@@ -5849,7 +5888,9 @@ var TypeScript = class extends Writer {
5849
5888
  if (isResourceTypeSchema(schema)) {
5850
5889
  const possibleResourceTypes = [schema.identifier];
5851
5890
  possibleResourceTypes.push(...tsIndex.resourceChildren(schema.identifier));
5852
- this.lineSM(`resourceType: ${possibleResourceTypes.map((e) => `"${e.name}"`).join(" | ")}`);
5891
+ this.lineSM(
5892
+ `resourceType: ${possibleResourceTypes.sort((a, b) => a.name.localeCompare(b.name)).map((e) => `"${e.name}"`).join(" | ")}`
5893
+ );
5853
5894
  this.line();
5854
5895
  }
5855
5896
  if (!schema.fields) return;
@@ -5891,6 +5932,7 @@ var TypeScript = class extends Writer {
5891
5932
  }
5892
5933
  }
5893
5934
  generateProfileType(tsIndex, flatProfile) {
5935
+ this.debugComment("flatProfile", flatProfile);
5894
5936
  const tsName = tsResourceName(flatProfile.identifier);
5895
5937
  this.debugComment("identifier", flatProfile.identifier);
5896
5938
  this.debugComment("base", flatProfile.base);
@@ -5903,7 +5945,7 @@ var TypeScript = class extends Writer {
5903
5945
  const tsName2 = tsFieldName(fieldName);
5904
5946
  let tsType;
5905
5947
  if (field.enum) {
5906
- tsType = field.enum.map((e) => `'${e}'`).join(" | ");
5948
+ tsType = `(${field.enum.map((e) => `'${e}'`).join(" | ")})`;
5907
5949
  } else if (field.reference && field.reference.length > 0) {
5908
5950
  const specialization = tsIndex.findLastSpecialization(flatProfile);
5909
5951
  if (!isSpecializationTypeSchema(specialization))
@@ -5928,6 +5970,8 @@ var TypeScript = class extends Writer {
5928
5970
  tsType = tsResourceName(field.type);
5929
5971
  } else if (isPrimitiveIdentifier(field.type)) {
5930
5972
  tsType = resolvePrimitiveType(field.type.name);
5973
+ } else if (field.type === void 0) {
5974
+ throw new Error(`Undefined type for '${fieldName}' field at ${typeSchemaInfo(flatProfile)}`);
5931
5975
  } else {
5932
5976
  tsType = field.type.name;
5933
5977
  }
@@ -6061,7 +6105,7 @@ var TypeScript = class extends Writer {
6061
6105
  ...tsIndex.collectComplexTypes(),
6062
6106
  ...tsIndex.collectResources(),
6063
6107
  // ...tsIndex.collectLogicalModels(),
6064
- ...tsIndex.collectProfiles().filter((p) => tsIndex.isWithMetaField(p))
6108
+ ...this.opts.generateProfile ? tsIndex.collectProfiles().filter((p) => tsIndex.isWithMetaField(p)) : []
6065
6109
  ];
6066
6110
  const grouped = groupByPackages(typesToGenerate);
6067
6111
  this.cd("/", () => {
@@ -6093,17 +6137,100 @@ var writerToGenerator = (writerGen) => {
6093
6137
  });
6094
6138
  };
6095
6139
  return {
6096
- generate: async (schemas) => {
6097
- const tsIndex = mkTypeSchemaIndex(schemas);
6140
+ generate: async ({ index: tsIndex }) => {
6098
6141
  writerGen.generate(tsIndex);
6099
6142
  return getGeneratedFiles();
6100
6143
  },
6101
6144
  setOutputDir: (outputDir) => writerGen.opts.outputDir = outputDir,
6102
- build: async (_schemas) => getGeneratedFiles()
6145
+ build: async (_input) => getGeneratedFiles()
6103
6146
  };
6104
6147
  };
6105
- var normalizeFileName = (str) => str.replace(/[^a-zA-Z0-9]/g, "");
6106
- var APIBuilder = class _APIBuilder {
6148
+ var normalizeFileName = (str) => {
6149
+ const res = str.replace(/[^a-zA-Z0-9\-_.@#()]/g, "");
6150
+ if (res.length === 0) return "unknown";
6151
+ return res;
6152
+ };
6153
+ var cleanup = async (opts, logger) => {
6154
+ logger.info(`Cleaning outputs...`);
6155
+ try {
6156
+ logger.info(`Clean ${opts.outputDir}`);
6157
+ fs.rmSync(opts.outputDir, { recursive: true, force: true });
6158
+ if (opts.typeSchemaOutputDir) {
6159
+ logger.info(`Clean ${opts.typeSchemaOutputDir}`);
6160
+ fs.rmSync(opts.typeSchemaOutputDir, {
6161
+ recursive: true,
6162
+ force: true
6163
+ });
6164
+ }
6165
+ if (opts.exportTypeTree) {
6166
+ logger.info(`Clean ${opts.exportTypeTree}`);
6167
+ fs.rmSync(opts.exportTypeTree, {
6168
+ recursive: true,
6169
+ force: true
6170
+ });
6171
+ }
6172
+ } catch (error) {
6173
+ logger.warn(`Error cleaning output directory: ${error instanceof Error ? error.message : String(error)}`);
6174
+ }
6175
+ };
6176
+ var writeTypeSchemasToSeparateFiles = async (typeSchemas, outputDir, logger) => {
6177
+ await afs2.mkdir(outputDir, { recursive: true });
6178
+ logger.info(`Writing TypeSchema files to ${outputDir}/...`);
6179
+ const files = {};
6180
+ for (const ts of typeSchemas) {
6181
+ const pkg = {
6182
+ name: ts.identifier.package,
6183
+ version: ts.identifier.version
6184
+ };
6185
+ const pkgPath = normalizeFileName(packageMetaToFhir(pkg));
6186
+ const name = normalizeFileName(`${ts.identifier.name}(${extractNameFromCanonical(ts.identifier.url)})`);
6187
+ const json = JSON.stringify(ts, null, 2);
6188
+ const baseName = Path4.join(outputDir, pkgPath, name);
6189
+ if (!files[baseName]) files[baseName] = [];
6190
+ if (!files[baseName]?.some((e) => e === json)) {
6191
+ files[baseName].push(json);
6192
+ }
6193
+ }
6194
+ for (const [baseName, jsons] of Object.entries(files)) {
6195
+ await Promise.all(
6196
+ jsons.map(async (json, index) => {
6197
+ let fullName;
6198
+ if (index === 0) {
6199
+ fullName = `${baseName}.typeschema.json`;
6200
+ } else {
6201
+ fullName = `${baseName}-${index}.typeschema.json`;
6202
+ }
6203
+ await afs2.mkdir(Path4.dirname(fullName), { recursive: true });
6204
+ await afs2.writeFile(fullName, json);
6205
+ })
6206
+ );
6207
+ }
6208
+ };
6209
+ var writeTypeSchemasToSingleFile = async (typeSchemas, outputFile, logger) => {
6210
+ logger.info(`Writing TypeSchema files to: ${outputFile}`);
6211
+ await afs2.mkdir(Path4.dirname(outputFile), { recursive: true });
6212
+ logger.info(`Writing TypeSchemas to one file ${outputFile}...`);
6213
+ for (const ts of typeSchemas) {
6214
+ const json = JSON.stringify(ts, null, 2);
6215
+ await afs2.appendFile(outputFile, `${json}
6216
+ `);
6217
+ }
6218
+ };
6219
+ var tryWriteTypeSchema = async (typeSchemas, opts, logger) => {
6220
+ if (!opts.typeSchemaOutputDir) return;
6221
+ try {
6222
+ if (Path4.extname(opts.typeSchemaOutputDir) === ".ndjson") {
6223
+ await writeTypeSchemasToSingleFile(typeSchemas, opts.typeSchemaOutputDir, logger);
6224
+ } else {
6225
+ await writeTypeSchemasToSeparateFiles(typeSchemas, opts.typeSchemaOutputDir, logger);
6226
+ }
6227
+ logger.info(`Writing TypeSchema - DONE`);
6228
+ } catch (error) {
6229
+ logger.error("Failed to write TypeSchema output", error instanceof Error ? error : new Error(String(error)));
6230
+ if (opts.throwException) throw error;
6231
+ }
6232
+ };
6233
+ var APIBuilder = class {
6107
6234
  schemas = [];
6108
6235
  options;
6109
6236
  generators = /* @__PURE__ */ new Map();
@@ -6124,7 +6251,9 @@ var APIBuilder = class _APIBuilder {
6124
6251
  typeSchemaConfig: options.typeSchemaConfig,
6125
6252
  manager: options.manager || null,
6126
6253
  throwException: options.throwException || false,
6127
- typeSchemaOutputDir: options.typeSchemaOutputDir
6254
+ typeSchemaOutputDir: options.typeSchemaOutputDir,
6255
+ exportTypeTree: options.exportTypeTree,
6256
+ treeShake: options.treeShake
6128
6257
  };
6129
6258
  this.typeSchemaConfig = options.typeSchemaConfig;
6130
6259
  this.logger = options.logger || createLogger({
@@ -6136,27 +6265,26 @@ var APIBuilder = class _APIBuilder {
6136
6265
  }
6137
6266
  }
6138
6267
  fromPackage(packageName, version) {
6139
- this.packages.push(packageMetaToNpm({ name: packageName, version: version || "latest" }));
6268
+ const pkg = packageMetaToNpm({ name: packageName, version: version || "latest" });
6269
+ this.packages.push(pkg);
6270
+ return this;
6271
+ }
6272
+ fromPackageRef(packageRef) {
6273
+ this.packages.push(packageRef);
6140
6274
  return this;
6141
6275
  }
6142
- /**
6143
- * Load TypeSchema from files
6144
- */
6145
6276
  fromFiles(...filePaths) {
6146
6277
  this.logger.debug(`Loading from ${filePaths.length} TypeSchema files`);
6147
6278
  const operation = this.loadFromFiles(filePaths);
6148
6279
  this.pendingOperations.push(operation);
6149
6280
  return this;
6150
6281
  }
6151
- /**
6152
- * Load TypeSchema from TypeSchema objects
6153
- */
6154
6282
  fromSchemas(schemas) {
6155
6283
  this.logger.debug(`Adding ${schemas.length} TypeSchemas to generation`);
6156
6284
  this.schemas = [...this.schemas, ...schemas];
6157
6285
  return this;
6158
6286
  }
6159
- typescript(options = {}) {
6287
+ typescriptDepricated(options = {}) {
6160
6288
  const typesOutputDir = `${this.options.outputDir}/types`;
6161
6289
  const generator = new TypeScriptGenerator({
6162
6290
  outputDir: typesOutputDir,
@@ -6181,17 +6309,19 @@ var APIBuilder = class _APIBuilder {
6181
6309
  this.logger.debug(`Configured TypeScript generator (${options.moduleFormat || "esm"})`);
6182
6310
  return this;
6183
6311
  }
6184
- typescript2(opts) {
6312
+ typescript(opts) {
6185
6313
  const writerOpts = {
6186
6314
  outputDir: Path4.join(this.options.outputDir, "/types"),
6187
6315
  tabSize: 4,
6188
6316
  withDebugComment: false,
6189
- commentLinePrefix: "//"
6317
+ commentLinePrefix: "//",
6318
+ generateProfile: true,
6319
+ exportTypeTree: this.options.exportTypeTree
6190
6320
  };
6191
6321
  const effectiveOpts = { logger: this.logger, ...writerOpts, ...opts };
6192
6322
  const generator = writerToGenerator(new TypeScript(effectiveOpts));
6193
- this.generators.set("typescript2", generator);
6194
- this.logger.debug(`Configured TypeScript2 generator (${JSON.stringify(effectiveOpts, void 0, 2)})`);
6323
+ this.generators.set("typescript", generator);
6324
+ this.logger.debug(`Configured TypeScript generator (${JSON.stringify(effectiveOpts, void 0, 2)})`);
6195
6325
  return this;
6196
6326
  }
6197
6327
  csharp(namespace, staticSourceDir) {
@@ -6245,64 +6375,17 @@ var APIBuilder = class _APIBuilder {
6245
6375
  this.options.cleanOutput = enabled;
6246
6376
  return this;
6247
6377
  }
6248
- writeTypeSchemas(target) {
6249
- this.options.typeSchemaOutputDir = target;
6378
+ writeTypeTree(filename) {
6379
+ this.options.exportTypeTree = filename;
6250
6380
  return this;
6251
6381
  }
6252
- static async isIdenticalTo(path, tsJSON) {
6253
- if (!await afs2.exists(path)) return false;
6254
- const json = await afs2.readFile(path);
6255
- const ts1 = JSON.parse(json.toString());
6256
- const ts2 = JSON.parse(tsJSON);
6257
- return deepEqual(ts1, ts2);
6258
- }
6259
- async writeTypeSchemasToSeparateFiles(typeSchemas, outputDir) {
6260
- if (this.options.cleanOutput) fs.rmSync(outputDir, { recursive: true, force: true });
6261
- await afs2.mkdir(outputDir, { recursive: true });
6262
- const usedNames = {};
6263
- this.logger.info(`Writing TypeSchema files to ${outputDir}...`);
6264
- for (const ts of typeSchemas) {
6265
- const package_name = camelCase(ts.identifier.package.replaceAll("/", "-"));
6266
- const name = normalizeFileName(ts.identifier.name.toString());
6267
- const json = JSON.stringify(ts, null, 2);
6268
- const baseName = Path4.join(outputDir, package_name, name);
6269
- let fullName;
6270
- if (usedNames[baseName] !== void 0) {
6271
- usedNames[baseName]++;
6272
- fullName = `${baseName}-${usedNames[baseName]}.typeschema.json`;
6273
- } else {
6274
- usedNames[baseName] = 0;
6275
- fullName = `${baseName}.typeschema.json`;
6276
- }
6277
- if (await _APIBuilder.isIdenticalTo(fullName, json)) continue;
6278
- await afs2.mkdir(Path4.dirname(fullName), { recursive: true });
6279
- await afs2.writeFile(fullName, json);
6280
- }
6281
- }
6282
- async writeTypeSchemasToSingleFile(typeSchemas, outputFile) {
6283
- if (this.options.cleanOutput && fs.existsSync(outputFile)) fs.rmSync(outputFile);
6284
- await afs2.mkdir(Path4.dirname(outputFile), { recursive: true });
6285
- this.logger.info(`Writing TypeSchemas to one file ${outputFile}...`);
6286
- for (const ts of typeSchemas) {
6287
- const json = JSON.stringify(ts, null, 2);
6288
- await afs2.appendFile(outputFile, json + "\n");
6289
- }
6382
+ treeShake(tree) {
6383
+ this.options.treeShake = tree;
6384
+ return this;
6290
6385
  }
6291
- async tryWriteTypeSchema(typeSchemas) {
6292
- if (!this.options.typeSchemaOutputDir) return;
6293
- try {
6294
- this.logger.info(`Starting writing TypeSchema files.`);
6295
- if (Path4.extname(this.options.typeSchemaOutputDir) === ".ndjson")
6296
- await this.writeTypeSchemasToSingleFile(typeSchemas, this.options.typeSchemaOutputDir);
6297
- else await this.writeTypeSchemasToSeparateFiles(typeSchemas, this.options.typeSchemaOutputDir);
6298
- this.logger.info(`Finished writing TypeSchema files.`);
6299
- } catch (error) {
6300
- if (this.options.throwException) throw error;
6301
- this.logger.error(
6302
- "Failed to write TypeSchema output",
6303
- error instanceof Error ? error : new Error(String(error))
6304
- );
6305
- }
6386
+ writeTypeSchemas(target) {
6387
+ this.options.typeSchemaOutputDir = target;
6388
+ return this;
6306
6389
  }
6307
6390
  async generate() {
6308
6391
  const startTime = performance.now();
@@ -6315,35 +6398,36 @@ var APIBuilder = class _APIBuilder {
6315
6398
  duration: 0
6316
6399
  };
6317
6400
  this.logger.debug(`Starting generation with ${this.generators.size} generators`);
6318
- if (this.options.cleanOutput) {
6319
- this.logger.info(`Cleaning output directory: ${this.options.outputDir}`);
6320
- try {
6321
- fs.rmSync(this.options.outputDir, { recursive: true, force: true });
6322
- fs.mkdirSync(this.options.outputDir, { recursive: true });
6323
- } catch (error) {
6324
- this.logger.warn(
6325
- `Error cleaning output directory: ${error instanceof Error ? error.message : String(error)}`
6326
- );
6327
- }
6328
- }
6329
6401
  try {
6402
+ if (this.options.cleanOutput) cleanup(this.options, this.logger);
6330
6403
  this.logger.info("Initialize Canonical Manager");
6331
6404
  const manager = CanonicalManager({
6332
6405
  packages: this.packages,
6333
- workingDir: "tmp/fhir"
6406
+ workingDir: ".codegen-cache/canonical-manager-cache"
6407
+ });
6408
+ const ref2meta = await manager.init();
6409
+ const packageMetas = Object.values(ref2meta);
6410
+ const register = await registerFromManager(manager, {
6411
+ logger: this.logger,
6412
+ focusedPackages: packageMetas
6334
6413
  });
6335
- await manager.init();
6336
- const register = await registerFromManager(manager, { logger: this.logger });
6337
6414
  const typeSchemas = await generateTypeSchemas(register, this.logger);
6338
- await this.tryWriteTypeSchema(typeSchemas);
6415
+ await tryWriteTypeSchema(typeSchemas, this.options, this.logger);
6416
+ let tsIndex = mkTypeSchemaIndex(typeSchemas, this.logger);
6417
+ if (this.options.treeShake) tsIndex = treeShake(tsIndex, this.options.treeShake, this.logger);
6418
+ if (this.options.exportTypeTree) await tsIndex.exportTree(this.options.exportTypeTree);
6339
6419
  this.logger.debug(`Executing ${this.generators.size} generators`);
6340
- await this.executeGenerators(result, typeSchemas);
6420
+ await this.executeGenerators(result, {
6421
+ schemas: typeSchemas,
6422
+ index: tsIndex
6423
+ });
6341
6424
  this.logger.info("Generation completed successfully");
6342
6425
  result.success = result.errors.length === 0;
6343
6426
  this.logger.debug(`Generation completed: ${result.filesGenerated.length} files`);
6344
6427
  } catch (error) {
6345
6428
  this.logger.error("Code generation failed", error instanceof Error ? error : new Error(String(error)));
6346
6429
  result.errors.push(error instanceof Error ? error.message : String(error));
6430
+ if (this.options.throwException) throw error;
6347
6431
  }
6348
6432
  return {
6349
6433
  ...result,
@@ -6404,11 +6488,11 @@ var APIBuilder = class _APIBuilder {
6404
6488
  this.cache.setMany(schemas);
6405
6489
  }
6406
6490
  }
6407
- async executeGenerators(result, typeSchemas) {
6491
+ async executeGenerators(result, input) {
6408
6492
  for (const [type, generator] of this.generators.entries()) {
6409
6493
  this.logger.info(`Generating ${type}...`);
6410
6494
  try {
6411
- const files = await generator.generate(typeSchemas);
6495
+ const files = await generator.generate(input);
6412
6496
  result.filesGenerated.push(...files.map((f) => f.path || f.filename));
6413
6497
  this.logger.info(`Generating ${type} finished successfully`);
6414
6498
  } catch (error) {
@@ -6420,9 +6504,6 @@ var APIBuilder = class _APIBuilder {
6420
6504
  }
6421
6505
  }
6422
6506
  };
6423
- function createAPI(options) {
6424
- return new APIBuilder(options);
6425
- }
6426
6507
  function createAPIFromConfig(config) {
6427
6508
  const builder = new APIBuilder({
6428
6509
  outputDir: config.outputDir,
@@ -6441,22 +6522,10 @@ function createAPIFromConfig(config) {
6441
6522
  builder.fromFiles(...config.files);
6442
6523
  }
6443
6524
  if (config.typescript) {
6444
- builder.typescript(config.typescript);
6525
+ builder.typescriptDepricated(config.typescript);
6445
6526
  }
6446
6527
  return builder;
6447
6528
  }
6448
- async function generateTypesFromPackage(packageName, outputDir, options = {}) {
6449
- return createAPI({
6450
- outputDir,
6451
- verbose: options.verbose
6452
- }).fromPackage(packageName, options.version).typescript().generate();
6453
- }
6454
- async function generateTypesFromFiles(inputFiles, outputDir, options = {}) {
6455
- return createAPI({
6456
- outputDir,
6457
- verbose: options.verbose
6458
- }).fromFiles(...inputFiles).typescript().generate();
6459
- }
6460
6529
  var DEFAULT_CONFIG = {
6461
6530
  outputDir: "./generated",
6462
6531
  verbose: false,
@@ -6969,6 +7038,6 @@ function defineConfig(config) {
6969
7038
  return config;
6970
7039
  }
6971
7040
 
6972
- export { APIBuilder, CONFIG_FILE_NAMES, ConfigLoader, ConfigValidator, DEFAULT_CONFIG, TypeSchemaCache, TypeSchemaGenerator, TypeSchemaParser, TypeScriptGenerator, configLoader, createAPI, createAPIFromConfig, defineConfig, generateTypesFromFiles, generateTypesFromPackage, isConfig, loadConfig };
7041
+ export { APIBuilder, CONFIG_FILE_NAMES, ConfigLoader, ConfigValidator, DEFAULT_CONFIG, TypeSchemaCache, TypeSchemaGenerator, TypeSchemaParser, TypeScriptGenerator, configLoader, createAPIFromConfig, defineConfig, isConfig, loadConfig };
6973
7042
  //# sourceMappingURL=index.js.map
6974
7043
  //# sourceMappingURL=index.js.map