@atomic-ehr/codegen 0.0.1-canary.20251008121245.8324bc2 → 0.0.1-canary.20251009074815.3e20aa6

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
@@ -1409,21 +1409,37 @@ var enrichFHIRSchema = (schema, packageMeta) => {
1409
1409
  base: schema.base
1410
1410
  };
1411
1411
  };
1412
+ var isNestedIdentifier = (id) => {
1413
+ return id?.kind === "nested";
1414
+ };
1415
+ var isProfileIdentifier = (id) => {
1416
+ return id?.kind === "profile";
1417
+ };
1412
1418
  var isFhirSchemaBased = (schema) => {
1413
- return schema.identifier.kind !== "value-set";
1419
+ return schema?.identifier.kind !== "value-set";
1414
1420
  };
1415
- var isSpecialization = (schema) => {
1416
- return schema.identifier.kind === "resource" || schema.identifier.kind === "complex-type" || schema.identifier.kind === "logical";
1421
+ var isSpecializationTypeSchema = (schema) => {
1422
+ return schema?.identifier.kind === "resource" || schema?.identifier.kind === "complex-type" || schema?.identifier.kind === "logical";
1417
1423
  };
1418
- var isProfile = (schema) => {
1419
- return schema.identifier.kind === "profile";
1424
+ var isComplexTypeTypeSchema = (schema) => {
1425
+ return schema?.identifier.kind === "complex-type";
1420
1426
  };
1421
- var isNotChoiceFieldDeclaration = (field) => {
1422
- return field.choices === void 0;
1427
+ var isResourceTypeSchema = (schema) => {
1428
+ return schema?.identifier.kind === "resource";
1429
+ };
1430
+ var isLogicalTypeSchema = (schema) => {
1431
+ return schema?.identifier.kind === "logical";
1432
+ };
1433
+ var isProfileTypeSchema = (schema) => {
1434
+ return schema?.identifier.kind === "profile";
1423
1435
  };
1424
1436
  function isBindingSchema(schema) {
1425
- return schema.identifier.kind === "binding";
1437
+ return schema?.identifier.kind === "binding";
1426
1438
  }
1439
+ var isNotChoiceDeclarationField = (field) => {
1440
+ if (!field) return false;
1441
+ return field.choices === void 0;
1442
+ };
1427
1443
 
1428
1444
  // src/typeschema/register.ts
1429
1445
  var registerFromManager = async (manager, logger) => {
@@ -1480,29 +1496,29 @@ var registerFromManager = async (manager, logger) => {
1480
1496
  );
1481
1497
  }
1482
1498
  const complexTypes = {};
1483
- for (const fs2 of Object.values(fsIndex)) {
1484
- if (fs2.kind === "complex-type") {
1485
- complexTypes[fs2.url] = fs2;
1499
+ for (const fs3 of Object.values(fsIndex)) {
1500
+ if (fs3.kind === "complex-type") {
1501
+ complexTypes[fs3.url] = fs3;
1486
1502
  }
1487
1503
  }
1488
1504
  const resolveFsGenealogy = (canonicalUrl) => {
1489
- let fs2 = fsIndex[canonicalUrl];
1490
- if (fs2 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
1491
- const genealogy = [fs2];
1492
- while (fs2?.base) {
1493
- fs2 = fsIndex[fs2.base] || fsIndex[nameToCanonical[fs2.base]];
1494
- genealogy.push(fs2);
1495
- if (fs2 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
1505
+ let fs3 = fsIndex[canonicalUrl];
1506
+ if (fs3 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
1507
+ const genealogy = [fs3];
1508
+ while (fs3?.base) {
1509
+ fs3 = fsIndex[fs3.base] || fsIndex[nameToCanonical[fs3.base]];
1510
+ genealogy.push(fs3);
1511
+ if (fs3 === void 0) throw new Error(`Failed to resolve FHIR Schema genealogy for '${canonicalUrl}'`);
1496
1512
  }
1497
1513
  return genealogy;
1498
1514
  };
1499
1515
  const resolveFsSpecializations = (canonicalUrl) => {
1500
- return resolveFsGenealogy(canonicalUrl).filter((fs2) => fs2.derivation === "specialization");
1516
+ return resolveFsGenealogy(canonicalUrl).filter((fs3) => fs3.derivation === "specialization");
1501
1517
  };
1502
1518
  return {
1503
1519
  ...manager,
1504
- appendFs(fs2) {
1505
- const rfs = enrichFHIRSchema(fs2);
1520
+ appendFs(fs3) {
1521
+ const rfs = enrichFHIRSchema(fs3);
1506
1522
  fsIndex[rfs.url] = rfs;
1507
1523
  nameToCanonical[rfs.name] = rfs.url;
1508
1524
  },
@@ -1522,9 +1538,9 @@ var registerFromManager = async (manager, logger) => {
1522
1538
  var resolveFsElementGenealogy = (genealogy, path) => {
1523
1539
  const [top, ...rest] = path;
1524
1540
  if (top === void 0) return [];
1525
- return genealogy.map((fs2) => {
1526
- if (!fs2.elements) return void 0;
1527
- let elem = fs2.elements?.[top];
1541
+ return genealogy.map((fs3) => {
1542
+ if (!fs3.elements) return void 0;
1543
+ let elem = fs3.elements?.[top];
1528
1544
  for (const k of rest) {
1529
1545
  elem = elem?.elements?.[k];
1530
1546
  }
@@ -1606,7 +1622,7 @@ function mkNestedIdentifier(register, fhirSchema, path, logger) {
1606
1622
  var nestedTypeOrigins = {};
1607
1623
  if (fhirSchema.derivation === "constraint") {
1608
1624
  const specializations = register.resolveFsSpecializations(fhirSchema.url);
1609
- const nestedTypeGenealogy = specializations.map((fs2) => mkNestedTypes(register, fs2, logger)).filter((e) => e !== void 0).flat();
1625
+ const nestedTypeGenealogy = specializations.map((fs3) => mkNestedTypes(register, fs3, logger)).filter((e) => e !== void 0).flat();
1610
1626
  for (const nt of nestedTypeGenealogy.reverse()) {
1611
1627
  nestedTypeOrigins[nt.identifier.name] = nt.identifier.url;
1612
1628
  }
@@ -1700,10 +1716,10 @@ function extractNestedDependencies(nestedTypes) {
1700
1716
  function isRequired(register, fhirSchema, path) {
1701
1717
  const fieldName = path[path.length - 1];
1702
1718
  const parentPath = path.slice(0, -1);
1703
- const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((fs2) => {
1704
- if (parentPath.length === 0) return fs2.required || [];
1705
- if (!fs2.elements) return [];
1706
- let elem = fs2;
1719
+ const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((fs3) => {
1720
+ if (parentPath.length === 0) return fs3.required || [];
1721
+ if (!fs3.elements) return [];
1722
+ let elem = fs3;
1707
1723
  for (const k of parentPath) {
1708
1724
  elem = elem?.elements?.[k];
1709
1725
  }
@@ -1715,10 +1731,10 @@ function isExcluded(register, fhirSchema, path) {
1715
1731
  const fieldName = path[path.length - 1];
1716
1732
  if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
1717
1733
  const parentPath = path.slice(0, -1);
1718
- const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((fs2) => {
1719
- if (parentPath.length === 0) return fs2.excluded || [];
1720
- if (!fs2.elements) return [];
1721
- let elem = fs2;
1734
+ const requires = register.resolveFsGenealogy(fhirSchema.url).flatMap((fs3) => {
1735
+ if (parentPath.length === 0) return fs3.excluded || [];
1736
+ if (!fs3.elements) return [];
1737
+ let elem = fs3;
1722
1738
  for (const k of parentPath) {
1723
1739
  elem = elem?.elements?.[k];
1724
1740
  }
@@ -1730,8 +1746,8 @@ var buildReferences = (element, register, _packageInfo) => {
1730
1746
  if (!element.refers) return void 0;
1731
1747
  return element.refers.map((ref) => {
1732
1748
  const curl = register.ensureCanonicalUrl(ref);
1733
- const fs2 = register.resolveFs(curl);
1734
- return mkIdentifier(fs2);
1749
+ const fs3 = register.resolveFs(curl);
1750
+ return mkIdentifier(fs3);
1735
1751
  });
1736
1752
  };
1737
1753
  function buildFieldType(register, fhirSchema, element, logger) {
@@ -2063,7 +2079,11 @@ function extractDependencies(identifier, base, fields, nestedTypes) {
2063
2079
  uniqDeps[dep.url] = dep;
2064
2080
  }
2065
2081
  const localNestedTypeUrls = new Set(nestedTypes?.map((nt) => nt.identifier.url));
2066
- const result = Object.values(uniqDeps).filter((e) => !(e.kind === "nested" && localNestedTypeUrls.has(e.url))).sort((a, b) => a.url.localeCompare(b.url));
2082
+ const result = Object.values(uniqDeps).filter((e) => {
2083
+ if (isProfileIdentifier(identifier)) return true;
2084
+ if (!isNestedIdentifier(e)) return true;
2085
+ return !localNestedTypeUrls.has(e.url);
2086
+ }).sort((a, b) => a.url.localeCompare(b.url));
2067
2087
  return result.length > 0 ? result : void 0;
2068
2088
  }
2069
2089
  function transformFhirSchemaResource(register, fhirSchema, logger) {
@@ -2543,7 +2563,7 @@ var TypeSchemaGenerator = class {
2543
2563
  };
2544
2564
  const register = await this.registerFromPackageMetas([packageInfo]);
2545
2565
  const valueSets = await this.generateValueSetSchemas(register.allVs(), logger);
2546
- const fhirSchemas = (await Promise.all(register.allFs().map(async (fs2) => await transformFhirSchema(register, fs2, logger)))).flat();
2566
+ const fhirSchemas = (await Promise.all(register.allFs().map(async (fs3) => await transformFhirSchema(register, fs3, logger)))).flat();
2547
2567
  const allSchemas = [...fhirSchemas, ...valueSets];
2548
2568
  if (this.cache) {
2549
2569
  for (const schema of allSchemas) {
@@ -2923,6 +2943,143 @@ var generateTypeSchemas = async (register, logger) => {
2923
2943
  return fhirSchemas;
2924
2944
  };
2925
2945
 
2946
+ // src/typeschema/utils.ts
2947
+ var groupByPackages = (typeSchemas) => {
2948
+ const grouped = {};
2949
+ for (const ts of typeSchemas) {
2950
+ const packageName = ts.identifier.package;
2951
+ if (!grouped[packageName]) {
2952
+ grouped[packageName] = [];
2953
+ }
2954
+ grouped[packageName].push(ts);
2955
+ }
2956
+ for (const [_packageName, typeSchemas2] of Object.entries(grouped)) {
2957
+ typeSchemas2.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
2958
+ }
2959
+ return grouped;
2960
+ };
2961
+ var resourceRelatives = (schemas) => {
2962
+ const regularSchemas = schemas.filter(isResourceTypeSchema);
2963
+ const directPairs = [];
2964
+ for (const schema of regularSchemas) {
2965
+ if (schema.base) {
2966
+ directPairs.push({ parent: schema.base, child: schema.identifier });
2967
+ }
2968
+ }
2969
+ const allPairs = [...directPairs];
2970
+ const findTransitiveRelatives = (parentRef) => {
2971
+ const directChildren = directPairs.filter((pair) => pair.parent.name === parentRef.name).map((pair) => pair.child);
2972
+ const transitiveChildren = [];
2973
+ for (const child of directChildren) {
2974
+ transitiveChildren.push(...findTransitiveRelatives(child));
2975
+ }
2976
+ return [...directChildren, ...transitiveChildren];
2977
+ };
2978
+ for (const pair of directPairs) {
2979
+ const transitiveChildren = findTransitiveRelatives(pair.child);
2980
+ for (const transitiveChild of transitiveChildren) {
2981
+ if (!directPairs.some((dp) => dp.parent.name === pair.parent.name && dp.child.name === transitiveChild.name)) {
2982
+ allPairs.push({ parent: pair.parent, child: transitiveChild });
2983
+ }
2984
+ }
2985
+ }
2986
+ return allPairs;
2987
+ };
2988
+ var mkTypeSchemaIndex = (schemas) => {
2989
+ const index = {};
2990
+ const append = (schema) => {
2991
+ const url = schema.identifier.url;
2992
+ if (!index[url]) {
2993
+ index[url] = {};
2994
+ }
2995
+ index[url][schema.identifier.package] = schema;
2996
+ };
2997
+ for (const schema of schemas) {
2998
+ append(schema);
2999
+ }
3000
+ const relations = resourceRelatives(schemas);
3001
+ const resolve2 = (id) => index[id.url]?.[id.package];
3002
+ const resourceChildren = (id) => {
3003
+ return relations.filter((relative2) => relative2.parent.name === id.name).map((relative2) => relative2.child);
3004
+ };
3005
+ const hierarchy = (schema) => {
3006
+ const res = [];
3007
+ let cur = schema;
3008
+ while (cur) {
3009
+ res.push(cur);
3010
+ const base = cur.base;
3011
+ if (base === void 0) break;
3012
+ const resolved = resolve2(base);
3013
+ if (!resolved) {
3014
+ throw new Error(
3015
+ `Failed to resolve base type: ${res.map((e) => `${e.identifier.url} (${e.identifier.kind})`).join(", ")}`
3016
+ );
3017
+ }
3018
+ cur = resolved;
3019
+ }
3020
+ return res;
3021
+ };
3022
+ const findLastSpecialization = (id) => {
3023
+ const schema = resolve2(id);
3024
+ if (!schema) return id;
3025
+ const nonConstraintSchema = hierarchy(schema).find((s) => s.identifier.kind !== "profile");
3026
+ if (!nonConstraintSchema) {
3027
+ throw new Error(`No non-constraint schema found in hierarchy for ${id.name}`);
3028
+ }
3029
+ return nonConstraintSchema.identifier;
3030
+ };
3031
+ const flatProfile = (schema) => {
3032
+ const hierarchySchemas = hierarchy(schema);
3033
+ const constraintSchemas = hierarchySchemas.filter((s) => s.identifier.kind === "profile");
3034
+ const nonConstraintSchema = hierarchySchemas.find((s) => s.identifier.kind !== "profile");
3035
+ if (!nonConstraintSchema)
3036
+ throw new Error(`No non-constraint schema found in hierarchy for ${schema.identifier.name}`);
3037
+ const mergedFields = {};
3038
+ for (const anySchema of constraintSchemas.slice().reverse()) {
3039
+ const schema2 = anySchema;
3040
+ if (!schema2.fields) continue;
3041
+ for (const [fieldName, fieldConstraints] of Object.entries(schema2.fields)) {
3042
+ if (mergedFields[fieldName]) {
3043
+ mergedFields[fieldName] = { ...mergedFields[fieldName], ...fieldConstraints };
3044
+ } else {
3045
+ mergedFields[fieldName] = { ...fieldConstraints };
3046
+ }
3047
+ }
3048
+ }
3049
+ const deps = {};
3050
+ for (const e of constraintSchemas.flatMap((e2) => e2.dependencies ?? [])) {
3051
+ deps[e.url] = e;
3052
+ }
3053
+ const dependencies = Object.values(deps);
3054
+ return {
3055
+ ...schema,
3056
+ base: nonConstraintSchema.identifier,
3057
+ fields: mergedFields,
3058
+ dependencies
3059
+ };
3060
+ };
3061
+ const isWithMetaField = (profile) => {
3062
+ return hierarchy(profile).filter(isSpecializationTypeSchema).some((schema) => {
3063
+ console.log(schema.fields?.meta);
3064
+ return schema.fields?.meta !== void 0;
3065
+ });
3066
+ };
3067
+ return {
3068
+ _schemaIndex: index,
3069
+ _relations: relations,
3070
+ collectComplexTypes: () => schemas.filter(isComplexTypeTypeSchema),
3071
+ collectResources: () => schemas.filter(isResourceTypeSchema),
3072
+ collectLogicalModels: () => schemas.filter(isLogicalTypeSchema),
3073
+ collectProfiles: () => schemas.filter(isProfileTypeSchema),
3074
+ resolve: resolve2,
3075
+ resourceChildren,
3076
+ hierarchy,
3077
+ findLastSpecialization,
3078
+ flatProfile,
3079
+ isWithMetaField
3080
+ };
3081
+ };
3082
+
2926
3083
  // src/api/generators/base/error-handler.ts
2927
3084
  init_errors();
2928
3085
  var ErrorHandler = class {
@@ -5008,7 +5165,7 @@ var FileSystemWriter = class {
5008
5165
  if (!this.currentFileDescriptor) throw new Error("No file opened");
5009
5166
  fs.writeSync(this.currentFileDescriptor, str);
5010
5167
  }
5011
- generate(_schemas) {
5168
+ generate(_tsIndex) {
5012
5169
  throw new Error("Not implemented");
5013
5170
  }
5014
5171
  writtenFiles() {
@@ -5030,6 +5187,7 @@ var Writer = class extends FileSystemWriter {
5030
5187
  if (tokens.length === 0) {
5031
5188
  this.write("\n");
5032
5189
  } else {
5190
+ this.writeIndent();
5033
5191
  this.write(`${tokens.join(" ")}
5034
5192
  `);
5035
5193
  }
@@ -5068,6 +5226,11 @@ var Writer = class extends FileSystemWriter {
5068
5226
  this.disclaimer().forEach((e) => this.comment(e));
5069
5227
  this.line();
5070
5228
  }
5229
+ indentBlock(gencontent) {
5230
+ this.indent();
5231
+ gencontent();
5232
+ this.deindent();
5233
+ }
5071
5234
  curlyBlock(tokens, gencontent, endTokens) {
5072
5235
  this.line(`${tokens.filter(Boolean).join(" ")} {`);
5073
5236
  this.indent();
@@ -5084,132 +5247,6 @@ var Writer = class extends FileSystemWriter {
5084
5247
  }
5085
5248
  };
5086
5249
 
5087
- // src/typeschema/utils.ts
5088
- var groupByPackages = (typeSchemas) => {
5089
- const grouped = {};
5090
- for (const ts of typeSchemas) {
5091
- const packageName = ts.identifier.package;
5092
- if (!grouped[packageName]) {
5093
- grouped[packageName] = [];
5094
- }
5095
- grouped[packageName].push(ts);
5096
- }
5097
- for (const [_packageName, typeSchemas2] of Object.entries(grouped)) {
5098
- typeSchemas2.sort((a, b) => a.identifier.name.localeCompare(b.identifier.name));
5099
- }
5100
- return grouped;
5101
- };
5102
- var collectComplexTypes = (tss) => tss.filter((t) => t.identifier.kind === "complex-type");
5103
- var collectResources = (tss) => tss.filter((t) => t.identifier.kind === "resource");
5104
- var resourceRelatives = (schemas) => {
5105
- const regularSchemas = collectResources(schemas);
5106
- const directPairs = [];
5107
- for (const schema of regularSchemas) {
5108
- if (schema.base) {
5109
- directPairs.push({ parent: schema.base, child: schema.identifier });
5110
- }
5111
- }
5112
- const allPairs = [...directPairs];
5113
- const findTransitiveRelatives = (parentRef) => {
5114
- const directChildren = directPairs.filter((pair) => pair.parent.name === parentRef.name).map((pair) => pair.child);
5115
- const transitiveChildren = [];
5116
- for (const child of directChildren) {
5117
- transitiveChildren.push(...findTransitiveRelatives(child));
5118
- }
5119
- return [...directChildren, ...transitiveChildren];
5120
- };
5121
- for (const pair of directPairs) {
5122
- const transitiveChildren = findTransitiveRelatives(pair.child);
5123
- for (const transitiveChild of transitiveChildren) {
5124
- if (!directPairs.some((dp) => dp.parent.name === pair.parent.name && dp.child.name === transitiveChild.name)) {
5125
- allPairs.push({ parent: pair.parent, child: transitiveChild });
5126
- }
5127
- }
5128
- }
5129
- return allPairs;
5130
- };
5131
- var mkTypeSchemaIndex = (schemas) => {
5132
- const index = {};
5133
- const append = (schema) => {
5134
- const url = schema.identifier.url;
5135
- if (!index[url]) {
5136
- index[url] = {};
5137
- }
5138
- index[url][schema.identifier.package] = schema;
5139
- };
5140
- for (const schema of schemas) {
5141
- append(schema);
5142
- }
5143
- const relations = resourceRelatives(schemas);
5144
- const resolve2 = (id) => index[id.url]?.[id.package];
5145
- const resourceChildren = (id) => {
5146
- return relations.filter((relative2) => relative2.parent.name === id.name).map((relative2) => relative2.child);
5147
- };
5148
- const hierarchy = (schema) => {
5149
- const res = [];
5150
- let cur = schema;
5151
- while (cur) {
5152
- res.push(cur);
5153
- const base = cur.base;
5154
- if (base === void 0) break;
5155
- const resolved = resolve2(base);
5156
- if (!resolved) {
5157
- throw new Error(`Failed to resolve base type: ${JSON.stringify(base)}`);
5158
- }
5159
- cur = resolved;
5160
- }
5161
- return res;
5162
- };
5163
- const findLastSpecialization = (id) => {
5164
- const schema = resolve2(id);
5165
- if (!schema) return id;
5166
- const nonConstraintSchema = hierarchy(schema).find((s) => s.identifier.kind !== "profile");
5167
- if (!nonConstraintSchema) {
5168
- throw new Error(`No non-constraint schema found in hierarchy for ${id.name}`);
5169
- }
5170
- return nonConstraintSchema.identifier;
5171
- };
5172
- const flatProfile = (schema) => {
5173
- const hierarchySchemas = hierarchy(schema);
5174
- const constraintSchemas = hierarchySchemas.filter((s) => s.identifier.kind === "profile");
5175
- const nonConstraintSchema = hierarchySchemas.find((s) => s.identifier.kind !== "profile");
5176
- if (!nonConstraintSchema)
5177
- throw new Error(`No non-constraint schema found in hierarchy for ${schema.identifier.name}`);
5178
- const mergedFields = {};
5179
- for (const anySchema of constraintSchemas.slice().reverse()) {
5180
- const schema2 = anySchema;
5181
- if (!schema2.fields) continue;
5182
- for (const [fieldName, fieldConstraints] of Object.entries(schema2.fields)) {
5183
- if (mergedFields[fieldName]) {
5184
- mergedFields[fieldName] = { ...mergedFields[fieldName], ...fieldConstraints };
5185
- } else {
5186
- mergedFields[fieldName] = { ...fieldConstraints };
5187
- }
5188
- }
5189
- }
5190
- const deps = {};
5191
- for (const e of constraintSchemas.flatMap((e2) => e2.dependencies ?? [])) {
5192
- deps[e.url] = e;
5193
- }
5194
- const dependencies = Object.values(deps);
5195
- return {
5196
- ...schema,
5197
- base: nonConstraintSchema.identifier,
5198
- fields: mergedFields,
5199
- dependencies
5200
- };
5201
- };
5202
- return {
5203
- schemaIndex: index,
5204
- relations,
5205
- resolve: resolve2,
5206
- resourceChildren,
5207
- hierarchy,
5208
- findLastSpecialization,
5209
- flatProfile
5210
- };
5211
- };
5212
-
5213
5250
  // src/api/writer-generator/typescript.ts
5214
5251
  var primitiveType2tsType = {
5215
5252
  boolean: "boolean",
@@ -5270,10 +5307,11 @@ var tsResourceName = (id) => {
5270
5307
  };
5271
5308
  var tsFieldName = (n) => normalizeTsName(n);
5272
5309
  var normalizeTsName = (n) => {
5310
+ const tsKeywords = /* @__PURE__ */ new Set(["abstract", "any", "as", "async", "await", "boolean", "bigint", "break", "case", "catch", "class", "const", "constructor", "continue", "debugger", "declare", "default", "delete", "do", "else", "enum", "export", "extends", "extern", "false", "finally", "for", "function", "from", "get", "goto", "if", "implements", "import", "in", "infer", "instanceof", "interface", "keyof", "let", "module", "namespace", "never", "new", "null", "number", "object", "of", "override", "private", "protected", "public", "readonly", "return", "satisfies", "set", "static", "string", "super", "switch", "this", "throw", "true", "try", "type", "typeof", "unknown", "var", "void", "while"]);
5311
+ if (tsKeywords.has(n)) n = `${n}_`;
5273
5312
  return n.replace(/[- ]/g, "_");
5274
5313
  };
5275
5314
  var TypeScript = class extends Writer {
5276
- tsIndex = mkTypeSchemaIndex([]);
5277
5315
  tsImportType(tsPackageName, ...entities) {
5278
5316
  this.lineSM(`import type { ${entities.join(", ")} } from "${tsPackageName}"`);
5279
5317
  }
@@ -5295,19 +5333,30 @@ var TypeScript = class extends Writer {
5295
5333
  }
5296
5334
  generateDependenciesImports(schema) {
5297
5335
  if (schema.dependencies) {
5298
- const deps = [
5299
- ...schema.dependencies.filter((dep) => ["complex-type", "resource", "logical"].includes(dep.kind)).map((dep) => ({
5300
- tsPackage: `../${kebabCase(dep.package)}/${pascalCase(dep.name)}`,
5301
- name: uppercaseFirstLetter(dep.name)
5302
- })),
5303
- ...schema.dependencies.filter((dep) => ["nested"].includes(dep.kind)).map((dep) => ({
5304
- tsPackage: `../${kebabCase(dep.package)}/${pascalCase(canonicalToName(dep.url) ?? "")}`,
5305
- name: tsResourceName(dep)
5306
- }))
5307
- ].sort((a, b) => a.name.localeCompare(b.name));
5308
- for (const dep of deps) {
5336
+ const imports = [];
5337
+ const skipped = [];
5338
+ for (const dep of schema.dependencies) {
5339
+ if (["complex-type", "resource", "logical"].includes(dep.kind)) {
5340
+ imports.push({
5341
+ tsPackage: `../${kebabCase(dep.package)}/${pascalCase(dep.name)}`,
5342
+ name: uppercaseFirstLetter(dep.name)
5343
+ });
5344
+ } else if (isNestedIdentifier(dep)) {
5345
+ imports.push({
5346
+ tsPackage: `../${kebabCase(dep.package)}/${pascalCase(canonicalToName(dep.url) ?? "")}`,
5347
+ name: tsResourceName(dep)
5348
+ });
5349
+ } else {
5350
+ skipped.push(dep);
5351
+ }
5352
+ }
5353
+ imports.sort((a, b) => a.name.localeCompare(b.name));
5354
+ for (const dep of imports) {
5309
5355
  this.tsImportType(dep.tsPackage, dep.name);
5310
5356
  }
5357
+ for (const dep of skipped) {
5358
+ this.debugComment("skip:", dep);
5359
+ }
5311
5360
  this.line();
5312
5361
  }
5313
5362
  }
@@ -5328,7 +5377,7 @@ var TypeScript = class extends Writer {
5328
5377
  this.lineSM(`_${tsFieldName(fieldName)}?: Element`);
5329
5378
  }
5330
5379
  }
5331
- generateType(schema) {
5380
+ generateType(tsIndex, schema) {
5332
5381
  var name;
5333
5382
  if (schema.identifier.name === "Reference") {
5334
5383
  name = "Reference<T extends string = string>";
@@ -5344,13 +5393,13 @@ var TypeScript = class extends Writer {
5344
5393
  if (!schema.fields) return;
5345
5394
  if (schema.identifier.kind === "resource") {
5346
5395
  const possibleResourceTypes = [schema.identifier];
5347
- possibleResourceTypes.push(...this.tsIndex.resourceChildren(schema.identifier));
5396
+ possibleResourceTypes.push(...tsIndex.resourceChildren(schema.identifier));
5348
5397
  this.lineSM(`resourceType: ${possibleResourceTypes.map((e) => `"${e.name}"`).join(" | ")}`);
5349
5398
  this.line();
5350
5399
  }
5351
5400
  const fields = Object.entries(schema.fields).sort((a, b) => a[0].localeCompare(b[0]));
5352
5401
  for (const [fieldName, field] of fields) {
5353
- if (!isNotChoiceFieldDeclaration(field)) continue;
5402
+ if (!isNotChoiceDeclarationField(field)) continue;
5354
5403
  this.debugComment(fieldName, ":", field);
5355
5404
  const tsName = tsFieldName(fieldName);
5356
5405
  const optionalSymbol = field.required ? "" : "?";
@@ -5380,22 +5429,23 @@ var TypeScript = class extends Writer {
5380
5429
  }
5381
5430
  });
5382
5431
  }
5383
- generateNestedTypes(schema) {
5432
+ generateNestedTypes(tsIndex, schema) {
5384
5433
  if (schema.nested) {
5385
5434
  for (const subtype of schema.nested) {
5386
- this.generateType(subtype);
5435
+ this.generateType(tsIndex, subtype);
5387
5436
  }
5388
5437
  }
5389
5438
  }
5390
- generateProfileType(schema) {
5439
+ generateProfileType(tsIndex, schema) {
5391
5440
  const name = tsResourceName(schema.identifier);
5392
- this.debugComment(schema.identifier);
5441
+ this.debugComment("identifier", schema.identifier);
5442
+ this.debugComment("base", schema.base);
5393
5443
  this.curlyBlock(["export", "interface", name], () => {
5394
5444
  this.lineSM(`__profileUrl: "${schema.identifier.url}"`);
5395
5445
  this.line();
5396
5446
  if (!isFhirSchemaBased(schema)) return;
5397
5447
  for (const [fieldName, field] of Object.entries(schema.fields ?? {})) {
5398
- if (!isNotChoiceFieldDeclaration(field)) continue;
5448
+ if (!isNotChoiceDeclarationField(field)) continue;
5399
5449
  this.debugComment(fieldName, field);
5400
5450
  const tsName = tsFieldName(fieldName);
5401
5451
  let tsType;
@@ -5404,16 +5454,16 @@ var TypeScript = class extends Writer {
5404
5454
  } else if (field.enum) {
5405
5455
  tsType = field.enum.map((e) => `'${e}'`).join(" | ");
5406
5456
  } else if (field.reference && field.reference.length > 0) {
5407
- const specializationId = this.tsIndex.findLastSpecialization(schema.identifier);
5408
- const specialization = this.tsIndex.resolve(specializationId);
5409
- if (specialization === void 0 || !isSpecialization(specialization))
5457
+ const specializationId = tsIndex.findLastSpecialization(schema.identifier);
5458
+ const specialization = tsIndex.resolve(specializationId);
5459
+ if (!isSpecializationTypeSchema(specialization))
5410
5460
  throw new Error(`Invalid specialization for ${schema.identifier}`);
5411
5461
  const sField = specialization.fields?.[fieldName];
5412
- if (sField === void 0 || !isNotChoiceFieldDeclaration(sField))
5462
+ if (sField === void 0 || !isNotChoiceDeclarationField(sField))
5413
5463
  throw new Error(`Invalid field declaration for ${fieldName}`);
5414
5464
  const sRefs = (sField.reference ?? []).map((e) => e.name);
5415
5465
  const references = field.reference.map((ref) => {
5416
- const resRef = this.tsIndex.findLastSpecialization(ref);
5466
+ const resRef = tsIndex.findLastSpecialization(ref);
5417
5467
  if (resRef.name !== ref.name) {
5418
5468
  return `"${resRef.name}" /*${ref.name}*/`;
5419
5469
  }
@@ -5432,39 +5482,135 @@ var TypeScript = class extends Writer {
5432
5482
  });
5433
5483
  this.line();
5434
5484
  }
5435
- generateResourceModule(schema) {
5485
+ generateAttachProfile(flatProfile) {
5486
+ const tsBaseResourceName = tsResourceName(flatProfile.base);
5487
+ const tsProfileName = tsResourceName(flatProfile.identifier);
5488
+ const profileFields = Object.entries(flatProfile.fields || {}).filter(([_fieldName, field]) => {
5489
+ return field && isNotChoiceDeclarationField(field) && field.type !== void 0;
5490
+ }).map(([fieldName]) => tsFieldName(fieldName));
5491
+ this.curlyBlock(
5492
+ [
5493
+ `export const attach_${tsProfileName} =`,
5494
+ `(resource: ${tsBaseResourceName}, profile: ${tsProfileName}): ${tsBaseResourceName}`,
5495
+ "=>"
5496
+ ],
5497
+ () => {
5498
+ this.curlyBlock(["return"], () => {
5499
+ this.line("...resource,");
5500
+ this.curlyBlock(["meta:"], () => {
5501
+ this.line(`profile: ['${flatProfile.identifier.url}']`);
5502
+ }, [","]);
5503
+ profileFields.forEach((fieldName) => {
5504
+ this.line(`${fieldName}:`, `profile.${fieldName},`);
5505
+ });
5506
+ });
5507
+ }
5508
+ );
5509
+ this.line();
5510
+ }
5511
+ generateExtractProfile(tsIndex, flatProfile) {
5512
+ const tsBaseResourceName = tsResourceName(flatProfile.base);
5513
+ const tsProfileName = tsResourceName(flatProfile.identifier);
5514
+ const profileFields = Object.entries(flatProfile.fields || {}).filter(([_fieldName, field]) => {
5515
+ return isNotChoiceDeclarationField(field) && field.type !== void 0;
5516
+ }).map(([fieldName]) => fieldName);
5517
+ const specialization = tsIndex.resolve(tsIndex.findLastSpecialization(flatProfile.identifier));
5518
+ if (!isSpecializationTypeSchema(specialization))
5519
+ throw new Error(`Specialization not found for ${flatProfile.identifier.url}`);
5520
+ const shouldCast = {};
5521
+ this.curlyBlock(
5522
+ [
5523
+ `export const extract_${tsBaseResourceName} =`,
5524
+ `(resource: ${tsBaseResourceName}): ${tsProfileName}`,
5525
+ "=>"
5526
+ ],
5527
+ () => {
5528
+ profileFields.forEach((fieldName) => {
5529
+ const tsField = tsFieldName(fieldName);
5530
+ const pField = flatProfile.fields?.[fieldName];
5531
+ const rField = specialization.fields?.[fieldName];
5532
+ if (!isNotChoiceDeclarationField(pField) || !isNotChoiceDeclarationField(rField)) return;
5533
+ if (pField.required && !rField.required) {
5534
+ this.curlyBlock(
5535
+ [`if (resource.${tsField} === undefined)`],
5536
+ () => this.lineSM(
5537
+ `throw new Error("'${tsField}' is required for ${flatProfile.identifier.url}")`
5538
+ )
5539
+ );
5540
+ }
5541
+ const pRefs = pField?.reference?.map((ref) => ref.name);
5542
+ const rRefs = rField?.reference?.map((ref) => ref.name);
5543
+ if (pRefs && rRefs && pRefs.length !== rRefs.length) {
5544
+ const predName = `reference_pred_${tsField}`;
5545
+ this.curlyBlock(["const", predName, "=", "(ref?: Reference)", "=>"], () => {
5546
+ this.line("return !ref");
5547
+ this.indentBlock(() => {
5548
+ rRefs.forEach((ref) => {
5549
+ this.line(`|| ref.reference?.startsWith('${ref}/')`);
5550
+ });
5551
+ this.line(";");
5552
+ });
5553
+ });
5554
+ let cond = !pField?.required ? `!resource.${tsField} || ` : "";
5555
+ if (pField.array) {
5556
+ cond += `resource.${tsField}.every( (ref) => ${predName}(ref) )`;
5557
+ } else {
5558
+ cond += `${predName}(resource.${tsField})`;
5559
+ }
5560
+ this.curlyBlock(["if (", cond, ")"], () => {
5561
+ this.lineSM(
5562
+ `throw new Error("'${fieldName}' has different references in profile and specialization")`
5563
+ );
5564
+ });
5565
+ this.line();
5566
+ shouldCast[fieldName] = true;
5567
+ }
5568
+ });
5569
+ this.curlyBlock(["return"], () => {
5570
+ this.line(`__profileUrl: '${flatProfile.identifier.url}',`);
5571
+ profileFields.forEach((fieldName) => {
5572
+ const tsField = tsFieldName(fieldName);
5573
+ if (shouldCast[fieldName]) {
5574
+ this.line(`${tsField}:`, `resource.${tsField} as ${tsProfileName}['${tsField}'],`);
5575
+ } else {
5576
+ this.line(`${tsField}:`, `resource.${tsField},`);
5577
+ }
5578
+ });
5579
+ });
5580
+ }
5581
+ );
5582
+ }
5583
+ generateResourceModule(tsIndex, schema) {
5436
5584
  this.cat(`${tsModuleFileName(schema.identifier)}`, () => {
5437
5585
  this.generateDisclaimer();
5438
- if (["complex-type", "resource", "logical", "nested"].includes(schema.identifier.kind)) {
5586
+ if (["complex-type", "resource", "logical"].includes(schema.identifier.kind)) {
5439
5587
  this.generateDependenciesImports(schema);
5440
5588
  this.generateComplexTypeReexports(schema);
5441
- this.generateNestedTypes(schema);
5442
- this.generateType(schema);
5443
- } else if (isProfile(schema)) {
5444
- const flatProfile = this.tsIndex.flatProfile(schema);
5445
- this.debugComment(flatProfile.dependencies);
5589
+ this.generateNestedTypes(tsIndex, schema);
5590
+ this.generateType(tsIndex, schema);
5591
+ } else if (isProfileTypeSchema(schema)) {
5592
+ const flatProfile = tsIndex.flatProfile(schema);
5446
5593
  this.generateDependenciesImports(flatProfile);
5447
- this.generateProfileType(flatProfile);
5448
- } else {
5449
- throw new Error(`Profile generation not implemented for kind: ${schema.identifier.kind}`);
5450
- }
5594
+ this.generateProfileType(tsIndex, flatProfile);
5595
+ this.generateAttachProfile(flatProfile);
5596
+ this.generateExtractProfile(tsIndex, flatProfile);
5597
+ } else throw new Error(`Profile generation not implemented for kind: ${schema.identifier.kind}`);
5451
5598
  });
5452
5599
  }
5453
- generate(schemas) {
5600
+ generate(tsIndex) {
5454
5601
  const typesToGenerate = [
5455
- ...collectComplexTypes(schemas),
5456
- ...collectResources(schemas)
5457
- // ...collectLogicalModels(schemas),
5458
- // ...collectProfiles(schemas),
5602
+ ...tsIndex.collectComplexTypes(),
5603
+ ...tsIndex.collectResources(),
5604
+ // ...tsIndex.collectLogicalModels(),
5605
+ ...tsIndex.collectProfiles().filter((p) => tsIndex.isWithMetaField(p))
5459
5606
  ];
5460
- this.tsIndex = mkTypeSchemaIndex(typesToGenerate);
5461
5607
  const grouped = groupByPackages(typesToGenerate);
5462
5608
  this.cd("/", () => {
5463
5609
  for (const [packageName, packageSchemas] of Object.entries(grouped)) {
5464
5610
  const tsPackageDir = tsFhirPackageDir(packageName);
5465
5611
  this.cd(tsPackageDir, () => {
5466
5612
  for (const schema of packageSchemas) {
5467
- this.generateResourceModule(schema);
5613
+ this.generateResourceModule(tsIndex, schema);
5468
5614
  }
5469
5615
  this.generateFhirPackageIndexFile(packageSchemas);
5470
5616
  });
@@ -5489,7 +5635,8 @@ var writerToGenerator = (writerGen) => {
5489
5635
  };
5490
5636
  return {
5491
5637
  generate: async (schemas) => {
5492
- writerGen.generate(schemas);
5638
+ const tsIndex = mkTypeSchemaIndex(schemas);
5639
+ writerGen.generate(tsIndex);
5493
5640
  return getGeneratedFiles();
5494
5641
  },
5495
5642
  setOutputDir: (outputDir) => writerGen.opts.outputDir = outputDir,
@@ -5513,6 +5660,7 @@ var APIBuilder = class {
5513
5660
  verbose: options.verbose ?? false,
5514
5661
  overwrite: options.overwrite ?? true,
5515
5662
  cache: options.cache ?? true,
5663
+ cleanOutput: options.cleanOutput ?? true,
5516
5664
  typeSchemaConfig: options.typeSchemaConfig,
5517
5665
  manager: options.manager || null,
5518
5666
  throwException: options.throwException || false
@@ -5614,6 +5762,10 @@ var APIBuilder = class {
5614
5762
  this.options.throwException = enabled;
5615
5763
  return this;
5616
5764
  }
5765
+ cleanOutput(enabled = true) {
5766
+ this.options.cleanOutput = enabled;
5767
+ return this;
5768
+ }
5617
5769
  async generate() {
5618
5770
  const startTime = performance.now();
5619
5771
  const result = {
@@ -5625,6 +5777,17 @@ var APIBuilder = class {
5625
5777
  duration: 0
5626
5778
  };
5627
5779
  this.logger.debug(`Starting generation with ${this.generators.size} generators`);
5780
+ if (this.options.cleanOutput) {
5781
+ this.logger.info(`Cleaning output directory: ${this.options.outputDir}`);
5782
+ try {
5783
+ fs.rmSync(this.options.outputDir, { recursive: true, force: true });
5784
+ fs.mkdirSync(this.options.outputDir, { recursive: true });
5785
+ } catch (error) {
5786
+ this.logger.warn(
5787
+ `Error cleaning output directory: ${error instanceof Error ? error.message : String(error)}`
5788
+ );
5789
+ }
5790
+ }
5628
5791
  try {
5629
5792
  this.logger.info("Initialize Canonical Manager");
5630
5793
  const manager = CanonicalManager({
@@ -5726,6 +5889,7 @@ function createAPIFromConfig(config) {
5726
5889
  verbose: config.verbose,
5727
5890
  overwrite: config.overwrite,
5728
5891
  cache: config.cache,
5892
+ cleanOutput: config.cleanOutput,
5729
5893
  typeSchemaConfig: config.typeSchema
5730
5894
  });
5731
5895
  if (config.packages && config.packages.length > 0) {
@@ -5759,6 +5923,7 @@ var DEFAULT_CONFIG = {
5759
5923
  overwrite: true,
5760
5924
  validate: true,
5761
5925
  cache: true,
5926
+ cleanOutput: true,
5762
5927
  typescript: {
5763
5928
  moduleFormat: "esm",
5764
5929
  generateIndex: true,