@atomic-ehr/codegen 0.0.1-canary.20251008092936.b434b77 → 0.0.1-canary.20251008121245.8324bc2

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.d.ts CHANGED
@@ -256,12 +256,6 @@ interface BindingTypeSchema {
256
256
  dependencies?: Identifier[];
257
257
  }
258
258
  type Field = RegularField | ChoiceFieldDeclaration | ChoiceFieldInstance;
259
- interface TypeschemaGeneratorOptions {
260
- verbose?: boolean;
261
- logger?: CodegenLogger;
262
- treeshake?: string[];
263
- manager?: ReturnType<typeof CanonicalManager> | null;
264
- }
265
259
  type TypeschemaParserOptions = {
266
260
  format?: "auto" | "ndjson" | "json";
267
261
  validate?: boolean;
@@ -301,6 +295,12 @@ type RichValueSet = Omit<ValueSet, "name" | "url"> & {
301
295
  name?: Name;
302
296
  url?: CanonicalUrl;
303
297
  };
298
+ interface TypeschemaGeneratorOptions {
299
+ verbose?: boolean;
300
+ logger?: CodegenLogger;
301
+ treeshake?: string[];
302
+ manager?: ReturnType<typeof CanonicalManager> | null;
303
+ }
304
304
 
305
305
  type Register = {
306
306
  appendFs(fs: FHIRSchema): void;
package/dist/index.js CHANGED
@@ -1409,6 +1409,18 @@ var enrichFHIRSchema = (schema, packageMeta) => {
1409
1409
  base: schema.base
1410
1410
  };
1411
1411
  };
1412
+ var isFhirSchemaBased = (schema) => {
1413
+ return schema.identifier.kind !== "value-set";
1414
+ };
1415
+ var isSpecialization = (schema) => {
1416
+ return schema.identifier.kind === "resource" || schema.identifier.kind === "complex-type" || schema.identifier.kind === "logical";
1417
+ };
1418
+ var isProfile = (schema) => {
1419
+ return schema.identifier.kind === "profile";
1420
+ };
1421
+ var isNotChoiceFieldDeclaration = (field) => {
1422
+ return field.choices === void 0;
1423
+ };
1412
1424
  function isBindingSchema(schema) {
1413
1425
  return schema.identifier.kind === "binding";
1414
1426
  }
@@ -5089,11 +5101,6 @@ var groupByPackages = (typeSchemas) => {
5089
5101
  };
5090
5102
  var collectComplexTypes = (tss) => tss.filter((t) => t.identifier.kind === "complex-type");
5091
5103
  var collectResources = (tss) => tss.filter((t) => t.identifier.kind === "resource");
5092
- var notChoiceDeclaration = (field) => {
5093
- if (field.choices) return void 0;
5094
- if (field.choiceOf) return field;
5095
- return field;
5096
- };
5097
5104
  var resourceRelatives = (schemas) => {
5098
5105
  const regularSchemas = collectResources(schemas);
5099
5106
  const directPairs = [];
@@ -5121,8 +5128,86 @@ var resourceRelatives = (schemas) => {
5121
5128
  }
5122
5129
  return allPairs;
5123
5130
  };
5124
- var resourceChildren = (relatives, id) => {
5125
- return relatives.filter((relative2) => relative2.parent.name === id.name).map((relative2) => relative2.child);
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
+ };
5126
5211
  };
5127
5212
 
5128
5213
  // src/api/writer-generator/typescript.ts
@@ -5153,6 +5238,7 @@ var tsFhirPackageDir = (name) => {
5153
5238
  return kebabCase(name);
5154
5239
  };
5155
5240
  var tsModuleName = (id) => {
5241
+ if (id.kind === "profile") return `${tsResourceName(id)}_profile`;
5156
5242
  return pascalCase(id.name);
5157
5243
  };
5158
5244
  var tsModuleFileName = (id) => {
@@ -5187,7 +5273,7 @@ var normalizeTsName = (n) => {
5187
5273
  return n.replace(/[- ]/g, "_");
5188
5274
  };
5189
5275
  var TypeScript = class extends Writer {
5190
- resourceRelatives = [];
5276
+ tsIndex = mkTypeSchemaIndex([]);
5191
5277
  tsImportType(tsPackageName, ...entities) {
5192
5278
  this.lineSM(`import type { ${entities.join(", ")} } from "${tsPackageName}"`);
5193
5279
  }
@@ -5258,39 +5344,36 @@ var TypeScript = class extends Writer {
5258
5344
  if (!schema.fields) return;
5259
5345
  if (schema.identifier.kind === "resource") {
5260
5346
  const possibleResourceTypes = [schema.identifier];
5261
- possibleResourceTypes.push(...resourceChildren(this.resourceRelatives, schema.identifier));
5347
+ possibleResourceTypes.push(...this.tsIndex.resourceChildren(schema.identifier));
5262
5348
  this.lineSM(`resourceType: ${possibleResourceTypes.map((e) => `"${e.name}"`).join(" | ")}`);
5263
5349
  this.line();
5264
5350
  }
5265
5351
  const fields = Object.entries(schema.fields).sort((a, b) => a[0].localeCompare(b[0]));
5266
- for (const [fieldName, anyField] of fields) {
5267
- const field = notChoiceDeclaration(anyField);
5268
- if (field === void 0) continue;
5352
+ for (const [fieldName, field] of fields) {
5353
+ if (!isNotChoiceFieldDeclaration(field)) continue;
5269
5354
  this.debugComment(fieldName, ":", field);
5270
- const fieldNameFixed = tsFieldName(fieldName);
5355
+ const tsName = tsFieldName(fieldName);
5271
5356
  const optionalSymbol = field.required ? "" : "?";
5272
5357
  const arraySymbol = field.array ? "[]" : "";
5273
- if (field.type === void 0) {
5274
- continue;
5275
- }
5276
- let type = field.type.name;
5358
+ if (field.type === void 0) continue;
5359
+ let tsType = field.type.name;
5277
5360
  if (field.type.kind === "nested") {
5278
- type = tsResourceName(field.type);
5361
+ tsType = tsResourceName(field.type);
5279
5362
  }
5280
5363
  if (field.type.kind === "primitive-type") {
5281
- type = primitiveType2tsType[field.type.name] ?? "string";
5364
+ tsType = primitiveType2tsType[field.type.name] ?? "string";
5282
5365
  }
5283
- if (schema.identifier.name === "Reference" && fieldNameFixed === "reference") {
5284
- type = "`${T}/${string}`";
5366
+ if (schema.identifier.name === "Reference" && tsName === "reference") {
5367
+ tsType = "`${T}/${string}`";
5285
5368
  }
5286
5369
  if (field.reference?.length) {
5287
5370
  const references = field.reference.map((ref) => `"${ref.name}"`).join(" | ");
5288
- type = `Reference<${references}>`;
5371
+ tsType = `Reference<${references}>`;
5289
5372
  }
5290
5373
  if (field.enum) {
5291
- type = field.enum.map((e) => `"${e}"`).join(" | ");
5374
+ tsType = field.enum.map((e) => `"${e}"`).join(" | ");
5292
5375
  }
5293
- this.lineSM(`${fieldNameFixed}${optionalSymbol}:`, `${type}${arraySymbol}`);
5376
+ this.lineSM(`${tsName}${optionalSymbol}:`, `${tsType}${arraySymbol}`);
5294
5377
  if (["resource", "complex-type"].includes(schema.identifier.kind)) {
5295
5378
  this.addFieldExtension(fieldName, field);
5296
5379
  }
@@ -5304,6 +5387,51 @@ var TypeScript = class extends Writer {
5304
5387
  }
5305
5388
  }
5306
5389
  }
5390
+ generateProfileType(schema) {
5391
+ const name = tsResourceName(schema.identifier);
5392
+ this.debugComment(schema.identifier);
5393
+ this.curlyBlock(["export", "interface", name], () => {
5394
+ this.lineSM(`__profileUrl: "${schema.identifier.url}"`);
5395
+ this.line();
5396
+ if (!isFhirSchemaBased(schema)) return;
5397
+ for (const [fieldName, field] of Object.entries(schema.fields ?? {})) {
5398
+ if (!isNotChoiceFieldDeclaration(field)) continue;
5399
+ this.debugComment(fieldName, field);
5400
+ const tsName = tsFieldName(fieldName);
5401
+ let tsType;
5402
+ if (field.type.kind === "nested") {
5403
+ tsType = tsResourceName(field.type);
5404
+ } else if (field.enum) {
5405
+ tsType = field.enum.map((e) => `'${e}'`).join(" | ");
5406
+ } 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))
5410
+ throw new Error(`Invalid specialization for ${schema.identifier}`);
5411
+ const sField = specialization.fields?.[fieldName];
5412
+ if (sField === void 0 || !isNotChoiceFieldDeclaration(sField))
5413
+ throw new Error(`Invalid field declaration for ${fieldName}`);
5414
+ const sRefs = (sField.reference ?? []).map((e) => e.name);
5415
+ const references = field.reference.map((ref) => {
5416
+ const resRef = this.tsIndex.findLastSpecialization(ref);
5417
+ if (resRef.name !== ref.name) {
5418
+ return `"${resRef.name}" /*${ref.name}*/`;
5419
+ }
5420
+ return `'${ref.name}'`;
5421
+ }).join(" | ");
5422
+ if (sRefs.length === 1 && sRefs[0] === "Resource" && references !== '"Resource"') {
5423
+ tsType = `Reference<"Resource" /* ${references} */ >`;
5424
+ } else {
5425
+ tsType = `Reference<${references}>`;
5426
+ }
5427
+ } else {
5428
+ tsType = primitiveType2tsType[field.type.name] ?? field.type.name;
5429
+ }
5430
+ this.lineSM(`${tsName}${!field.required ? "?" : ""}: ${tsType}${field.array ? "[]" : ""}`);
5431
+ }
5432
+ });
5433
+ this.line();
5434
+ }
5307
5435
  generateResourceModule(schema) {
5308
5436
  this.cat(`${tsModuleFileName(schema.identifier)}`, () => {
5309
5437
  this.generateDisclaimer();
@@ -5312,6 +5440,11 @@ var TypeScript = class extends Writer {
5312
5440
  this.generateComplexTypeReexports(schema);
5313
5441
  this.generateNestedTypes(schema);
5314
5442
  this.generateType(schema);
5443
+ } else if (isProfile(schema)) {
5444
+ const flatProfile = this.tsIndex.flatProfile(schema);
5445
+ this.debugComment(flatProfile.dependencies);
5446
+ this.generateDependenciesImports(flatProfile);
5447
+ this.generateProfileType(flatProfile);
5315
5448
  } else {
5316
5449
  throw new Error(`Profile generation not implemented for kind: ${schema.identifier.kind}`);
5317
5450
  }
@@ -5321,10 +5454,10 @@ var TypeScript = class extends Writer {
5321
5454
  const typesToGenerate = [
5322
5455
  ...collectComplexTypes(schemas),
5323
5456
  ...collectResources(schemas)
5324
- // ...collectLogicalModels(typeSchemas),
5325
- // ...collectProfiles(typeSchemas),
5457
+ // ...collectLogicalModels(schemas),
5458
+ // ...collectProfiles(schemas),
5326
5459
  ];
5327
- this.resourceRelatives = resourceRelatives(typesToGenerate);
5460
+ this.tsIndex = mkTypeSchemaIndex(typesToGenerate);
5328
5461
  const grouped = groupByPackages(typesToGenerate);
5329
5462
  this.cd("/", () => {
5330
5463
  for (const [packageName, packageSchemas] of Object.entries(grouped)) {