@atomic-ehr/codegen 0.0.1 → 0.0.2-canary.20251114095108.8d8e927

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
@@ -2,12 +2,13 @@ import * as fs from 'fs';
2
2
  import fs__default, { existsSync, mkdirSync } from 'fs';
3
3
  import * as afs2 from 'fs/promises';
4
4
  import { readdir, stat, unlink, readFile, writeFile, access, mkdir, rm } from 'fs/promises';
5
- import * as Path4 from 'path';
6
- import Path4__default, { join, resolve, dirname, relative } from 'path';
5
+ import * as Path3 from 'path';
6
+ import Path3__default, { join, resolve, dirname, relative } from 'path';
7
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) {
3083
- this.currentDir = path.startsWith("/") ? Path4.join(this.opts.outputDir, path) : Path4.join(this.currentDir, path);
3038
+ const prev = this.currentDir;
3039
+ this.currentDir = path.startsWith("/") ? Path3.join(this.opts.outputDir, path) : Path3.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;
@@ -3503,31 +3461,84 @@ var CSharp = class extends Writer {
3503
3461
  }
3504
3462
  copyStaticFiles() {
3505
3463
  if (!this.staticSourceDir) return;
3506
- const sourcePath = Path4__default.resolve(this.staticSourceDir);
3464
+ const sourcePath = Path3__default.resolve(this.staticSourceDir);
3507
3465
  fs__default.cpSync(sourcePath, this.opts.outputDir, { recursive: true });
3508
3466
  }
3509
3467
  generateHelperFile() {
3510
3468
  const sourceFile = "src/api/writer-generator/csharp/Helper.cs";
3511
- const destFile = Path4__default.join(this.opts.outputDir, "Helper.cs");
3469
+ const destFile = Path3__default.join(this.opts.outputDir, "Helper.cs");
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,27 @@ 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.writeFile(filename, raw);
3689
+ };
3650
3690
  return {
3651
3691
  _schemaIndex: index,
3652
3692
  _relations: relations,
@@ -3655,13 +3695,15 @@ var mkTypeSchemaIndex = (schemas, logger) => {
3655
3695
  collectLogicalModels: () => schemas.filter(isLogicalTypeSchema),
3656
3696
  collectProfiles: () => schemas.filter(isProfileTypeSchema),
3657
3697
  resolve: resolve2,
3698
+ resolveByUrl,
3658
3699
  resourceChildren,
3659
3700
  tryHierarchy,
3660
3701
  hierarchy,
3661
3702
  findLastSpecialization,
3662
3703
  findLastSpecializationByIdentifier,
3663
3704
  flatProfile,
3664
- isWithMetaField
3705
+ isWithMetaField,
3706
+ exportTree
3665
3707
  };
3666
3708
  };
3667
3709
 
@@ -4179,7 +4221,7 @@ var BaseGenerator = class {
4179
4221
  * This is the main method that orchestrates the entire generation process
4180
4222
  * @param schemas - Array of TypeSchema documents
4181
4223
  */
4182
- async generate(schemas) {
4224
+ async generate({ schemas }) {
4183
4225
  return this.errorBoundary.withErrorBoundary(
4184
4226
  async () => {
4185
4227
  this.generationStartTime = performance.now();
@@ -4219,7 +4261,7 @@ var BaseGenerator = class {
4219
4261
  return result;
4220
4262
  };
4221
4263
  try {
4222
- const result = await this.generate(schemas);
4264
+ const result = await this.generate({ schemas, index: null });
4223
4265
  result.forEach((file) => {
4224
4266
  const mockResult = mockWriteResults.get(file.filename);
4225
4267
  if (mockResult) {
@@ -5527,10 +5569,10 @@ ${nestedInterfaces}`;
5527
5569
  /**
5528
5570
  * Override generate to clean directory first
5529
5571
  */
5530
- async generate(schemas) {
5572
+ async generate(input) {
5531
5573
  await this.fileManager.cleanDirectory();
5532
5574
  this.logger.debug("Cleaned output directory before generation");
5533
- return super.generate(schemas);
5575
+ return super.generate(input);
5534
5576
  }
5535
5577
  /**
5536
5578
  * Run post-generation hooks - generate utility files
@@ -5730,15 +5772,8 @@ var tsModuleFileName = (id) => {
5730
5772
  };
5731
5773
  var canonicalToName2 = (canonical, dropFragment = true) => {
5732
5774
  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
- }
5775
+ const localName = extractNameFromCanonical(canonical, dropFragment);
5738
5776
  if (!localName) return void 0;
5739
- if (/^\d/.test(localName)) {
5740
- localName = `number_${localName}`;
5741
- }
5742
5777
  return normalizeTsName(localName);
5743
5778
  };
5744
5779
  var tsResourceName = (id) => {
@@ -5794,12 +5829,14 @@ var TypeScript = class extends Writer {
5794
5829
  if (["complex-type", "resource", "logical"].includes(dep.kind)) {
5795
5830
  imports.push({
5796
5831
  tsPackage: `../${kebabCase(dep.package)}/${pascalCase(dep.name)}`,
5797
- name: uppercaseFirstLetter(dep.name)
5832
+ name: uppercaseFirstLetter(dep.name),
5833
+ dep
5798
5834
  });
5799
5835
  } else if (isNestedIdentifier(dep)) {
5800
5836
  imports.push({
5801
5837
  tsPackage: `../${kebabCase(dep.package)}/${pascalCase(canonicalToName2(dep.url) ?? "")}`,
5802
- name: tsResourceName(dep)
5838
+ name: tsResourceName(dep),
5839
+ dep
5803
5840
  });
5804
5841
  } else {
5805
5842
  skipped.push(dep);
@@ -5807,6 +5844,7 @@ var TypeScript = class extends Writer {
5807
5844
  }
5808
5845
  imports.sort((a, b) => a.name.localeCompare(b.name));
5809
5846
  for (const dep of imports) {
5847
+ this.debugComment(dep.dep);
5810
5848
  this.tsImportType(dep.tsPackage, dep.name);
5811
5849
  }
5812
5850
  for (const dep of skipped) {
@@ -5849,7 +5887,9 @@ var TypeScript = class extends Writer {
5849
5887
  if (isResourceTypeSchema(schema)) {
5850
5888
  const possibleResourceTypes = [schema.identifier];
5851
5889
  possibleResourceTypes.push(...tsIndex.resourceChildren(schema.identifier));
5852
- this.lineSM(`resourceType: ${possibleResourceTypes.map((e) => `"${e.name}"`).join(" | ")}`);
5890
+ this.lineSM(
5891
+ `resourceType: ${possibleResourceTypes.sort((a, b) => a.name.localeCompare(b.name)).map((e) => `"${e.name}"`).join(" | ")}`
5892
+ );
5853
5893
  this.line();
5854
5894
  }
5855
5895
  if (!schema.fields) return;
@@ -5891,6 +5931,7 @@ var TypeScript = class extends Writer {
5891
5931
  }
5892
5932
  }
5893
5933
  generateProfileType(tsIndex, flatProfile) {
5934
+ this.debugComment("flatProfile", flatProfile);
5894
5935
  const tsName = tsResourceName(flatProfile.identifier);
5895
5936
  this.debugComment("identifier", flatProfile.identifier);
5896
5937
  this.debugComment("base", flatProfile.base);
@@ -5928,6 +5969,8 @@ var TypeScript = class extends Writer {
5928
5969
  tsType = tsResourceName(field.type);
5929
5970
  } else if (isPrimitiveIdentifier(field.type)) {
5930
5971
  tsType = resolvePrimitiveType(field.type.name);
5972
+ } else if (field.type === void 0) {
5973
+ throw new Error(`Undefined type for '${fieldName}' field at ${typeSchemaInfo(flatProfile)}`);
5931
5974
  } else {
5932
5975
  tsType = field.type.name;
5933
5976
  }
@@ -6061,7 +6104,7 @@ var TypeScript = class extends Writer {
6061
6104
  ...tsIndex.collectComplexTypes(),
6062
6105
  ...tsIndex.collectResources(),
6063
6106
  // ...tsIndex.collectLogicalModels(),
6064
- ...tsIndex.collectProfiles().filter((p) => tsIndex.isWithMetaField(p))
6107
+ ...this.opts.generateProfile ? tsIndex.collectProfiles().filter((p) => tsIndex.isWithMetaField(p)) : []
6065
6108
  ];
6066
6109
  const grouped = groupByPackages(typesToGenerate);
6067
6110
  this.cd("/", () => {
@@ -6083,7 +6126,7 @@ var writerToGenerator = (writerGen) => {
6083
6126
  const getGeneratedFiles = () => {
6084
6127
  return writerGen.writtenFiles().map((fn) => {
6085
6128
  return {
6086
- path: Path4.normalize(Path4.join(writerGen.opts.outputDir, fn)),
6129
+ path: Path3.normalize(Path3.join(writerGen.opts.outputDir, fn)),
6087
6130
  filename: fn.replace(/^.*[\\/]/, ""),
6088
6131
  content: "",
6089
6132
  exports: [],
@@ -6093,17 +6136,100 @@ var writerToGenerator = (writerGen) => {
6093
6136
  });
6094
6137
  };
6095
6138
  return {
6096
- generate: async (schemas) => {
6097
- const tsIndex = mkTypeSchemaIndex(schemas);
6139
+ generate: async ({ index: tsIndex }) => {
6098
6140
  writerGen.generate(tsIndex);
6099
6141
  return getGeneratedFiles();
6100
6142
  },
6101
6143
  setOutputDir: (outputDir) => writerGen.opts.outputDir = outputDir,
6102
- build: async (_schemas) => getGeneratedFiles()
6144
+ build: async (_input) => getGeneratedFiles()
6103
6145
  };
6104
6146
  };
6105
- var normalizeFileName = (str) => str.replace(/[^a-zA-Z0-9]/g, "");
6106
- var APIBuilder = class _APIBuilder {
6147
+ var normalizeFileName = (str) => {
6148
+ const res = str.replace(/[^a-zA-Z0-9\-_.@#()]/g, "");
6149
+ if (res.length === 0) return "unknown";
6150
+ return res;
6151
+ };
6152
+ var cleanup = async (opts, logger) => {
6153
+ logger.info(`Cleaning outputs...`);
6154
+ try {
6155
+ logger.info(`Clean ${opts.outputDir}`);
6156
+ fs.rmSync(opts.outputDir, { recursive: true, force: true });
6157
+ if (opts.typeSchemaOutputDir) {
6158
+ logger.info(`Clean ${opts.typeSchemaOutputDir}`);
6159
+ fs.rmSync(opts.typeSchemaOutputDir, {
6160
+ recursive: true,
6161
+ force: true
6162
+ });
6163
+ }
6164
+ if (opts.exportTypeTree) {
6165
+ logger.info(`Clean ${opts.exportTypeTree}`);
6166
+ fs.rmSync(opts.exportTypeTree, {
6167
+ recursive: true,
6168
+ force: true
6169
+ });
6170
+ }
6171
+ } catch (error) {
6172
+ logger.warn(`Error cleaning output directory: ${error instanceof Error ? error.message : String(error)}`);
6173
+ }
6174
+ };
6175
+ var writeTypeSchemasToSeparateFiles = async (typeSchemas, outputDir, logger) => {
6176
+ await afs2.mkdir(outputDir, { recursive: true });
6177
+ logger.info(`Writing TypeSchema files to ${outputDir}/...`);
6178
+ const files = {};
6179
+ for (const ts of typeSchemas) {
6180
+ const pkg = {
6181
+ name: ts.identifier.package,
6182
+ version: ts.identifier.version
6183
+ };
6184
+ const pkgPath = normalizeFileName(packageMetaToFhir(pkg));
6185
+ const name = normalizeFileName(`${ts.identifier.name}(${extractNameFromCanonical(ts.identifier.url)})`);
6186
+ const json = JSON.stringify(ts, null, 2);
6187
+ const baseName = Path3.join(outputDir, pkgPath, name);
6188
+ if (!files[baseName]) files[baseName] = [];
6189
+ if (!files[baseName]?.some((e) => e === json)) {
6190
+ files[baseName].push(json);
6191
+ }
6192
+ }
6193
+ for (const [baseName, jsons] of Object.entries(files)) {
6194
+ await Promise.all(
6195
+ jsons.map(async (json, index) => {
6196
+ let fullName;
6197
+ if (index === 0) {
6198
+ fullName = `${baseName}.typeschema.json`;
6199
+ } else {
6200
+ fullName = `${baseName}-${index}.typeschema.json`;
6201
+ }
6202
+ await afs2.mkdir(Path3.dirname(fullName), { recursive: true });
6203
+ await afs2.writeFile(fullName, json);
6204
+ })
6205
+ );
6206
+ }
6207
+ };
6208
+ var writeTypeSchemasToSingleFile = async (typeSchemas, outputFile, logger) => {
6209
+ logger.info(`Writing TypeSchema files to: ${outputFile}`);
6210
+ await afs2.mkdir(Path3.dirname(outputFile), { recursive: true });
6211
+ logger.info(`Writing TypeSchemas to one file ${outputFile}...`);
6212
+ for (const ts of typeSchemas) {
6213
+ const json = JSON.stringify(ts, null, 2);
6214
+ await afs2.appendFile(outputFile, `${json}
6215
+ `);
6216
+ }
6217
+ };
6218
+ var tryWriteTypeSchema = async (typeSchemas, opts, logger) => {
6219
+ if (!opts.typeSchemaOutputDir) return;
6220
+ try {
6221
+ if (Path3.extname(opts.typeSchemaOutputDir) === ".ndjson") {
6222
+ await writeTypeSchemasToSingleFile(typeSchemas, opts.typeSchemaOutputDir, logger);
6223
+ } else {
6224
+ await writeTypeSchemasToSeparateFiles(typeSchemas, opts.typeSchemaOutputDir, logger);
6225
+ }
6226
+ logger.info(`Writing TypeSchema - DONE`);
6227
+ } catch (error) {
6228
+ logger.error("Failed to write TypeSchema output", error instanceof Error ? error : new Error(String(error)));
6229
+ if (opts.throwException) throw error;
6230
+ }
6231
+ };
6232
+ var APIBuilder = class {
6107
6233
  schemas = [];
6108
6234
  options;
6109
6235
  generators = /* @__PURE__ */ new Map();
@@ -6124,7 +6250,9 @@ var APIBuilder = class _APIBuilder {
6124
6250
  typeSchemaConfig: options.typeSchemaConfig,
6125
6251
  manager: options.manager || null,
6126
6252
  throwException: options.throwException || false,
6127
- typeSchemaOutputDir: options.typeSchemaOutputDir
6253
+ typeSchemaOutputDir: options.typeSchemaOutputDir,
6254
+ exportTypeTree: options.exportTypeTree,
6255
+ treeShake: options.treeShake
6128
6256
  };
6129
6257
  this.typeSchemaConfig = options.typeSchemaConfig;
6130
6258
  this.logger = options.logger || createLogger({
@@ -6136,27 +6264,26 @@ var APIBuilder = class _APIBuilder {
6136
6264
  }
6137
6265
  }
6138
6266
  fromPackage(packageName, version) {
6139
- this.packages.push(packageMetaToNpm({ name: packageName, version: version || "latest" }));
6267
+ const pkg = packageMetaToNpm({ name: packageName, version: version || "latest" });
6268
+ this.packages.push(pkg);
6269
+ return this;
6270
+ }
6271
+ fromPackageRef(packageRef) {
6272
+ this.packages.push(packageRef);
6140
6273
  return this;
6141
6274
  }
6142
- /**
6143
- * Load TypeSchema from files
6144
- */
6145
6275
  fromFiles(...filePaths) {
6146
6276
  this.logger.debug(`Loading from ${filePaths.length} TypeSchema files`);
6147
6277
  const operation = this.loadFromFiles(filePaths);
6148
6278
  this.pendingOperations.push(operation);
6149
6279
  return this;
6150
6280
  }
6151
- /**
6152
- * Load TypeSchema from TypeSchema objects
6153
- */
6154
6281
  fromSchemas(schemas) {
6155
6282
  this.logger.debug(`Adding ${schemas.length} TypeSchemas to generation`);
6156
6283
  this.schemas = [...this.schemas, ...schemas];
6157
6284
  return this;
6158
6285
  }
6159
- typescript(options = {}) {
6286
+ typescriptDepricated(options = {}) {
6160
6287
  const typesOutputDir = `${this.options.outputDir}/types`;
6161
6288
  const generator = new TypeScriptGenerator({
6162
6289
  outputDir: typesOutputDir,
@@ -6181,23 +6308,25 @@ var APIBuilder = class _APIBuilder {
6181
6308
  this.logger.debug(`Configured TypeScript generator (${options.moduleFormat || "esm"})`);
6182
6309
  return this;
6183
6310
  }
6184
- typescript2(opts) {
6311
+ typescript(opts) {
6185
6312
  const writerOpts = {
6186
- outputDir: Path4.join(this.options.outputDir, "/types"),
6313
+ outputDir: Path3.join(this.options.outputDir, "/types"),
6187
6314
  tabSize: 4,
6188
6315
  withDebugComment: false,
6189
- commentLinePrefix: "//"
6316
+ commentLinePrefix: "//",
6317
+ generateProfile: true,
6318
+ exportTypeTree: this.options.exportTypeTree
6190
6319
  };
6191
6320
  const effectiveOpts = { logger: this.logger, ...writerOpts, ...opts };
6192
6321
  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)})`);
6322
+ this.generators.set("typescript", generator);
6323
+ this.logger.debug(`Configured TypeScript generator (${JSON.stringify(effectiveOpts, void 0, 2)})`);
6195
6324
  return this;
6196
6325
  }
6197
6326
  csharp(namespace, staticSourceDir) {
6198
6327
  const generator = writerToGenerator(
6199
6328
  new CSharp({
6200
- outputDir: Path4.join(this.options.outputDir, "/types"),
6329
+ outputDir: Path3.join(this.options.outputDir, "/types"),
6201
6330
  staticSourceDir: staticSourceDir ?? void 0,
6202
6331
  targetNamespace: namespace,
6203
6332
  logger: new CodegenLogger({
@@ -6245,64 +6374,17 @@ var APIBuilder = class _APIBuilder {
6245
6374
  this.options.cleanOutput = enabled;
6246
6375
  return this;
6247
6376
  }
6248
- writeTypeSchemas(target) {
6249
- this.options.typeSchemaOutputDir = target;
6377
+ writeTypeTree(filename) {
6378
+ this.options.exportTypeTree = filename;
6250
6379
  return this;
6251
6380
  }
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
- }
6381
+ treeShake(tree) {
6382
+ this.options.treeShake = tree;
6383
+ return this;
6290
6384
  }
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
- }
6385
+ writeTypeSchemas(target) {
6386
+ this.options.typeSchemaOutputDir = target;
6387
+ return this;
6306
6388
  }
6307
6389
  async generate() {
6308
6390
  const startTime = performance.now();
@@ -6315,35 +6397,36 @@ var APIBuilder = class _APIBuilder {
6315
6397
  duration: 0
6316
6398
  };
6317
6399
  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
6400
  try {
6401
+ if (this.options.cleanOutput) cleanup(this.options, this.logger);
6330
6402
  this.logger.info("Initialize Canonical Manager");
6331
6403
  const manager = CanonicalManager({
6332
6404
  packages: this.packages,
6333
- workingDir: "tmp/fhir"
6405
+ workingDir: ".codegen-cache/canonical-manager-cache"
6406
+ });
6407
+ const ref2meta = await manager.init();
6408
+ const packageMetas = Object.values(ref2meta);
6409
+ const register = await registerFromManager(manager, {
6410
+ logger: this.logger,
6411
+ focusedPackages: packageMetas
6334
6412
  });
6335
- await manager.init();
6336
- const register = await registerFromManager(manager, { logger: this.logger });
6337
6413
  const typeSchemas = await generateTypeSchemas(register, this.logger);
6338
- await this.tryWriteTypeSchema(typeSchemas);
6414
+ await tryWriteTypeSchema(typeSchemas, this.options, this.logger);
6415
+ let tsIndex = mkTypeSchemaIndex(typeSchemas, this.logger);
6416
+ if (this.options.treeShake) tsIndex = treeShake(tsIndex, this.options.treeShake, this.logger);
6417
+ if (this.options.exportTypeTree) await tsIndex.exportTree(this.options.exportTypeTree);
6339
6418
  this.logger.debug(`Executing ${this.generators.size} generators`);
6340
- await this.executeGenerators(result, typeSchemas);
6419
+ await this.executeGenerators(result, {
6420
+ schemas: typeSchemas,
6421
+ index: tsIndex
6422
+ });
6341
6423
  this.logger.info("Generation completed successfully");
6342
6424
  result.success = result.errors.length === 0;
6343
6425
  this.logger.debug(`Generation completed: ${result.filesGenerated.length} files`);
6344
6426
  } catch (error) {
6345
6427
  this.logger.error("Code generation failed", error instanceof Error ? error : new Error(String(error)));
6346
6428
  result.errors.push(error instanceof Error ? error.message : String(error));
6429
+ if (this.options.throwException) throw error;
6347
6430
  }
6348
6431
  return {
6349
6432
  ...result,
@@ -6404,11 +6487,11 @@ var APIBuilder = class _APIBuilder {
6404
6487
  this.cache.setMany(schemas);
6405
6488
  }
6406
6489
  }
6407
- async executeGenerators(result, typeSchemas) {
6490
+ async executeGenerators(result, input) {
6408
6491
  for (const [type, generator] of this.generators.entries()) {
6409
6492
  this.logger.info(`Generating ${type}...`);
6410
6493
  try {
6411
- const files = await generator.generate(typeSchemas);
6494
+ const files = await generator.generate(input);
6412
6495
  result.filesGenerated.push(...files.map((f) => f.path || f.filename));
6413
6496
  this.logger.info(`Generating ${type} finished successfully`);
6414
6497
  } catch (error) {
@@ -6420,9 +6503,6 @@ var APIBuilder = class _APIBuilder {
6420
6503
  }
6421
6504
  }
6422
6505
  };
6423
- function createAPI(options) {
6424
- return new APIBuilder(options);
6425
- }
6426
6506
  function createAPIFromConfig(config) {
6427
6507
  const builder = new APIBuilder({
6428
6508
  outputDir: config.outputDir,
@@ -6441,22 +6521,10 @@ function createAPIFromConfig(config) {
6441
6521
  builder.fromFiles(...config.files);
6442
6522
  }
6443
6523
  if (config.typescript) {
6444
- builder.typescript(config.typescript);
6524
+ builder.typescriptDepricated(config.typescript);
6445
6525
  }
6446
6526
  return builder;
6447
6527
  }
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
6528
  var DEFAULT_CONFIG = {
6461
6529
  outputDir: "./generated",
6462
6530
  verbose: false,
@@ -6969,6 +7037,6 @@ function defineConfig(config) {
6969
7037
  return config;
6970
7038
  }
6971
7039
 
6972
- export { APIBuilder, CONFIG_FILE_NAMES, ConfigLoader, ConfigValidator, DEFAULT_CONFIG, TypeSchemaCache, TypeSchemaGenerator, TypeSchemaParser, TypeScriptGenerator, configLoader, createAPI, createAPIFromConfig, defineConfig, generateTypesFromFiles, generateTypesFromPackage, isConfig, loadConfig };
7040
+ export { APIBuilder, CONFIG_FILE_NAMES, ConfigLoader, ConfigValidator, DEFAULT_CONFIG, TypeSchemaCache, TypeSchemaGenerator, TypeSchemaParser, TypeScriptGenerator, configLoader, createAPIFromConfig, defineConfig, isConfig, loadConfig };
6973
7041
  //# sourceMappingURL=index.js.map
6974
7042
  //# sourceMappingURL=index.js.map