@atomic-ehr/codegen 0.0.1-canary.20251008092936.b434b77 → 0.0.1-canary.20251008162621.549c5d8

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,9 +1409,28 @@ 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
+ };
1418
+ var isFhirSchemaBased = (schema) => {
1419
+ return schema?.identifier.kind !== "value-set";
1420
+ };
1421
+ var isSpecializationTypeSchema = (schema) => {
1422
+ return schema?.identifier.kind === "resource" || schema?.identifier.kind === "complex-type" || schema?.identifier.kind === "logical";
1423
+ };
1424
+ var isProfileTypeSchema = (schema) => {
1425
+ return schema?.identifier.kind === "profile";
1426
+ };
1412
1427
  function isBindingSchema(schema) {
1413
- return schema.identifier.kind === "binding";
1428
+ return schema?.identifier.kind === "binding";
1414
1429
  }
1430
+ var isNotChoiceDeclarationField = (field) => {
1431
+ if (!field) return false;
1432
+ return field.choices === void 0;
1433
+ };
1415
1434
 
1416
1435
  // src/typeschema/register.ts
1417
1436
  var registerFromManager = async (manager, logger) => {
@@ -2051,7 +2070,11 @@ function extractDependencies(identifier, base, fields, nestedTypes) {
2051
2070
  uniqDeps[dep.url] = dep;
2052
2071
  }
2053
2072
  const localNestedTypeUrls = new Set(nestedTypes?.map((nt) => nt.identifier.url));
2054
- const result = Object.values(uniqDeps).filter((e) => !(e.kind === "nested" && localNestedTypeUrls.has(e.url))).sort((a, b) => a.url.localeCompare(b.url));
2073
+ const result = Object.values(uniqDeps).filter((e) => {
2074
+ if (isProfileIdentifier(identifier)) return true;
2075
+ if (!isNestedIdentifier(e)) return true;
2076
+ return !localNestedTypeUrls.has(e.url);
2077
+ }).sort((a, b) => a.url.localeCompare(b.url));
2055
2078
  return result.length > 0 ? result : void 0;
2056
2079
  }
2057
2080
  function transformFhirSchemaResource(register, fhirSchema, logger) {
@@ -5018,6 +5041,7 @@ var Writer = class extends FileSystemWriter {
5018
5041
  if (tokens.length === 0) {
5019
5042
  this.write("\n");
5020
5043
  } else {
5044
+ this.writeIndent();
5021
5045
  this.write(`${tokens.join(" ")}
5022
5046
  `);
5023
5047
  }
@@ -5056,6 +5080,11 @@ var Writer = class extends FileSystemWriter {
5056
5080
  this.disclaimer().forEach((e) => this.comment(e));
5057
5081
  this.line();
5058
5082
  }
5083
+ indentBlock(gencontent) {
5084
+ this.indent();
5085
+ gencontent();
5086
+ this.deindent();
5087
+ }
5059
5088
  curlyBlock(tokens, gencontent, endTokens) {
5060
5089
  this.line(`${tokens.filter(Boolean).join(" ")} {`);
5061
5090
  this.indent();
@@ -5089,11 +5118,7 @@ var groupByPackages = (typeSchemas) => {
5089
5118
  };
5090
5119
  var collectComplexTypes = (tss) => tss.filter((t) => t.identifier.kind === "complex-type");
5091
5120
  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
- };
5121
+ var collectProfiles = (tss) => tss.filter(isProfileTypeSchema);
5097
5122
  var resourceRelatives = (schemas) => {
5098
5123
  const regularSchemas = collectResources(schemas);
5099
5124
  const directPairs = [];
@@ -5121,8 +5146,95 @@ var resourceRelatives = (schemas) => {
5121
5146
  }
5122
5147
  return allPairs;
5123
5148
  };
5124
- var resourceChildren = (relatives, id) => {
5125
- return relatives.filter((relative2) => relative2.parent.name === id.name).map((relative2) => relative2.child);
5149
+ var mkTypeSchemaIndex = (schemas) => {
5150
+ const index = {};
5151
+ const append = (schema) => {
5152
+ const url = schema.identifier.url;
5153
+ if (!index[url]) {
5154
+ index[url] = {};
5155
+ }
5156
+ index[url][schema.identifier.package] = schema;
5157
+ };
5158
+ for (const schema of schemas) {
5159
+ append(schema);
5160
+ }
5161
+ const relations = resourceRelatives(schemas);
5162
+ const resolve2 = (id) => index[id.url]?.[id.package];
5163
+ const resourceChildren = (id) => {
5164
+ return relations.filter((relative2) => relative2.parent.name === id.name).map((relative2) => relative2.child);
5165
+ };
5166
+ const hierarchy = (schema) => {
5167
+ const res = [];
5168
+ let cur = schema;
5169
+ while (cur) {
5170
+ res.push(cur);
5171
+ const base = cur.base;
5172
+ if (base === void 0) break;
5173
+ const resolved = resolve2(base);
5174
+ if (!resolved) {
5175
+ throw new Error(
5176
+ `Failed to resolve base type: ${res.map((e) => `${e.identifier.url} (${e.identifier.kind})`).join(", ")}`
5177
+ );
5178
+ }
5179
+ cur = resolved;
5180
+ }
5181
+ return res;
5182
+ };
5183
+ const findLastSpecialization = (id) => {
5184
+ const schema = resolve2(id);
5185
+ if (!schema) return id;
5186
+ const nonConstraintSchema = hierarchy(schema).find((s) => s.identifier.kind !== "profile");
5187
+ if (!nonConstraintSchema) {
5188
+ throw new Error(`No non-constraint schema found in hierarchy for ${id.name}`);
5189
+ }
5190
+ return nonConstraintSchema.identifier;
5191
+ };
5192
+ const flatProfile = (schema) => {
5193
+ const hierarchySchemas = hierarchy(schema);
5194
+ const constraintSchemas = hierarchySchemas.filter((s) => s.identifier.kind === "profile");
5195
+ const nonConstraintSchema = hierarchySchemas.find((s) => s.identifier.kind !== "profile");
5196
+ if (!nonConstraintSchema)
5197
+ throw new Error(`No non-constraint schema found in hierarchy for ${schema.identifier.name}`);
5198
+ const mergedFields = {};
5199
+ for (const anySchema of constraintSchemas.slice().reverse()) {
5200
+ const schema2 = anySchema;
5201
+ if (!schema2.fields) continue;
5202
+ for (const [fieldName, fieldConstraints] of Object.entries(schema2.fields)) {
5203
+ if (mergedFields[fieldName]) {
5204
+ mergedFields[fieldName] = { ...mergedFields[fieldName], ...fieldConstraints };
5205
+ } else {
5206
+ mergedFields[fieldName] = { ...fieldConstraints };
5207
+ }
5208
+ }
5209
+ }
5210
+ const deps = {};
5211
+ for (const e of constraintSchemas.flatMap((e2) => e2.dependencies ?? [])) {
5212
+ deps[e.url] = e;
5213
+ }
5214
+ const dependencies = Object.values(deps);
5215
+ return {
5216
+ ...schema,
5217
+ base: nonConstraintSchema.identifier,
5218
+ fields: mergedFields,
5219
+ dependencies
5220
+ };
5221
+ };
5222
+ const isWithMetaField = (profile) => {
5223
+ return hierarchy(profile).filter(isSpecializationTypeSchema).some((schema) => {
5224
+ console.log(schema.fields?.meta);
5225
+ return schema.fields?.meta !== void 0;
5226
+ });
5227
+ };
5228
+ return {
5229
+ schemaIndex: index,
5230
+ relations,
5231
+ resolve: resolve2,
5232
+ resourceChildren,
5233
+ hierarchy,
5234
+ findLastSpecialization,
5235
+ flatProfile,
5236
+ isWithMetaField
5237
+ };
5126
5238
  };
5127
5239
 
5128
5240
  // src/api/writer-generator/typescript.ts
@@ -5153,6 +5265,7 @@ var tsFhirPackageDir = (name) => {
5153
5265
  return kebabCase(name);
5154
5266
  };
5155
5267
  var tsModuleName = (id) => {
5268
+ if (id.kind === "profile") return `${tsResourceName(id)}_profile`;
5156
5269
  return pascalCase(id.name);
5157
5270
  };
5158
5271
  var tsModuleFileName = (id) => {
@@ -5184,10 +5297,12 @@ var tsResourceName = (id) => {
5184
5297
  };
5185
5298
  var tsFieldName = (n) => normalizeTsName(n);
5186
5299
  var normalizeTsName = (n) => {
5300
+ 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"]);
5301
+ if (tsKeywords.has(n)) n = `${n}_`;
5187
5302
  return n.replace(/[- ]/g, "_");
5188
5303
  };
5189
5304
  var TypeScript = class extends Writer {
5190
- resourceRelatives = [];
5305
+ tsIndex = mkTypeSchemaIndex([]);
5191
5306
  tsImportType(tsPackageName, ...entities) {
5192
5307
  this.lineSM(`import type { ${entities.join(", ")} } from "${tsPackageName}"`);
5193
5308
  }
@@ -5209,19 +5324,30 @@ var TypeScript = class extends Writer {
5209
5324
  }
5210
5325
  generateDependenciesImports(schema) {
5211
5326
  if (schema.dependencies) {
5212
- const deps = [
5213
- ...schema.dependencies.filter((dep) => ["complex-type", "resource", "logical"].includes(dep.kind)).map((dep) => ({
5214
- tsPackage: `../${kebabCase(dep.package)}/${pascalCase(dep.name)}`,
5215
- name: uppercaseFirstLetter(dep.name)
5216
- })),
5217
- ...schema.dependencies.filter((dep) => ["nested"].includes(dep.kind)).map((dep) => ({
5218
- tsPackage: `../${kebabCase(dep.package)}/${pascalCase(canonicalToName(dep.url) ?? "")}`,
5219
- name: tsResourceName(dep)
5220
- }))
5221
- ].sort((a, b) => a.name.localeCompare(b.name));
5222
- for (const dep of deps) {
5327
+ const imports = [];
5328
+ const skipped = [];
5329
+ for (const dep of schema.dependencies) {
5330
+ if (["complex-type", "resource", "logical"].includes(dep.kind)) {
5331
+ imports.push({
5332
+ tsPackage: `../${kebabCase(dep.package)}/${pascalCase(dep.name)}`,
5333
+ name: uppercaseFirstLetter(dep.name)
5334
+ });
5335
+ } else if (isNestedIdentifier(dep)) {
5336
+ imports.push({
5337
+ tsPackage: `../${kebabCase(dep.package)}/${pascalCase(canonicalToName(dep.url) ?? "")}`,
5338
+ name: tsResourceName(dep)
5339
+ });
5340
+ } else {
5341
+ skipped.push(dep);
5342
+ }
5343
+ }
5344
+ imports.sort((a, b) => a.name.localeCompare(b.name));
5345
+ for (const dep of imports) {
5223
5346
  this.tsImportType(dep.tsPackage, dep.name);
5224
5347
  }
5348
+ for (const dep of skipped) {
5349
+ this.debugComment("skip:", dep);
5350
+ }
5225
5351
  this.line();
5226
5352
  }
5227
5353
  }
@@ -5258,39 +5384,36 @@ var TypeScript = class extends Writer {
5258
5384
  if (!schema.fields) return;
5259
5385
  if (schema.identifier.kind === "resource") {
5260
5386
  const possibleResourceTypes = [schema.identifier];
5261
- possibleResourceTypes.push(...resourceChildren(this.resourceRelatives, schema.identifier));
5387
+ possibleResourceTypes.push(...this.tsIndex.resourceChildren(schema.identifier));
5262
5388
  this.lineSM(`resourceType: ${possibleResourceTypes.map((e) => `"${e.name}"`).join(" | ")}`);
5263
5389
  this.line();
5264
5390
  }
5265
5391
  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;
5392
+ for (const [fieldName, field] of fields) {
5393
+ if (!isNotChoiceDeclarationField(field)) continue;
5269
5394
  this.debugComment(fieldName, ":", field);
5270
- const fieldNameFixed = tsFieldName(fieldName);
5395
+ const tsName = tsFieldName(fieldName);
5271
5396
  const optionalSymbol = field.required ? "" : "?";
5272
5397
  const arraySymbol = field.array ? "[]" : "";
5273
- if (field.type === void 0) {
5274
- continue;
5275
- }
5276
- let type = field.type.name;
5398
+ if (field.type === void 0) continue;
5399
+ let tsType = field.type.name;
5277
5400
  if (field.type.kind === "nested") {
5278
- type = tsResourceName(field.type);
5401
+ tsType = tsResourceName(field.type);
5279
5402
  }
5280
5403
  if (field.type.kind === "primitive-type") {
5281
- type = primitiveType2tsType[field.type.name] ?? "string";
5404
+ tsType = primitiveType2tsType[field.type.name] ?? "string";
5282
5405
  }
5283
- if (schema.identifier.name === "Reference" && fieldNameFixed === "reference") {
5284
- type = "`${T}/${string}`";
5406
+ if (schema.identifier.name === "Reference" && tsName === "reference") {
5407
+ tsType = "`${T}/${string}`";
5285
5408
  }
5286
5409
  if (field.reference?.length) {
5287
5410
  const references = field.reference.map((ref) => `"${ref.name}"`).join(" | ");
5288
- type = `Reference<${references}>`;
5411
+ tsType = `Reference<${references}>`;
5289
5412
  }
5290
5413
  if (field.enum) {
5291
- type = field.enum.map((e) => `"${e}"`).join(" | ");
5414
+ tsType = field.enum.map((e) => `"${e}"`).join(" | ");
5292
5415
  }
5293
- this.lineSM(`${fieldNameFixed}${optionalSymbol}:`, `${type}${arraySymbol}`);
5416
+ this.lineSM(`${tsName}${optionalSymbol}:`, `${tsType}${arraySymbol}`);
5294
5417
  if (["resource", "complex-type"].includes(schema.identifier.kind)) {
5295
5418
  this.addFieldExtension(fieldName, field);
5296
5419
  }
@@ -5304,27 +5427,175 @@ var TypeScript = class extends Writer {
5304
5427
  }
5305
5428
  }
5306
5429
  }
5430
+ generateProfileType(schema) {
5431
+ const name = tsResourceName(schema.identifier);
5432
+ this.debugComment("identifier", schema.identifier);
5433
+ this.debugComment("base", schema.base);
5434
+ this.curlyBlock(["export", "interface", name], () => {
5435
+ this.lineSM(`__profileUrl: "${schema.identifier.url}"`);
5436
+ this.line();
5437
+ if (!isFhirSchemaBased(schema)) return;
5438
+ for (const [fieldName, field] of Object.entries(schema.fields ?? {})) {
5439
+ if (!isNotChoiceDeclarationField(field)) continue;
5440
+ this.debugComment(fieldName, field);
5441
+ const tsName = tsFieldName(fieldName);
5442
+ let tsType;
5443
+ if (field.type.kind === "nested") {
5444
+ tsType = tsResourceName(field.type);
5445
+ } else if (field.enum) {
5446
+ tsType = field.enum.map((e) => `'${e}'`).join(" | ");
5447
+ } else if (field.reference && field.reference.length > 0) {
5448
+ const specializationId = this.tsIndex.findLastSpecialization(schema.identifier);
5449
+ const specialization = this.tsIndex.resolve(specializationId);
5450
+ if (!isSpecializationTypeSchema(specialization))
5451
+ throw new Error(`Invalid specialization for ${schema.identifier}`);
5452
+ const sField = specialization.fields?.[fieldName];
5453
+ if (sField === void 0 || !isNotChoiceDeclarationField(sField))
5454
+ throw new Error(`Invalid field declaration for ${fieldName}`);
5455
+ const sRefs = (sField.reference ?? []).map((e) => e.name);
5456
+ const references = field.reference.map((ref) => {
5457
+ const resRef = this.tsIndex.findLastSpecialization(ref);
5458
+ if (resRef.name !== ref.name) {
5459
+ return `"${resRef.name}" /*${ref.name}*/`;
5460
+ }
5461
+ return `'${ref.name}'`;
5462
+ }).join(" | ");
5463
+ if (sRefs.length === 1 && sRefs[0] === "Resource" && references !== '"Resource"') {
5464
+ tsType = `Reference<"Resource" /* ${references} */ >`;
5465
+ } else {
5466
+ tsType = `Reference<${references}>`;
5467
+ }
5468
+ } else {
5469
+ tsType = primitiveType2tsType[field.type.name] ?? field.type.name;
5470
+ }
5471
+ this.lineSM(`${tsName}${!field.required ? "?" : ""}: ${tsType}${field.array ? "[]" : ""}`);
5472
+ }
5473
+ });
5474
+ this.line();
5475
+ }
5476
+ generateAttachProfile(flatProfile) {
5477
+ const tsBaseResourceName = tsResourceName(flatProfile.base);
5478
+ const tsProfileName = tsResourceName(flatProfile.identifier);
5479
+ const profileFields = Object.entries(flatProfile.fields || {}).filter(([_fieldName, field]) => {
5480
+ return field && isNotChoiceDeclarationField(field) && field.type !== void 0;
5481
+ }).map(([fieldName]) => tsFieldName(fieldName));
5482
+ this.curlyBlock(
5483
+ [
5484
+ `export const attach_${tsProfileName} =`,
5485
+ `(resource: ${tsBaseResourceName}, profile: ${tsProfileName}): ${tsBaseResourceName}`,
5486
+ "=>"
5487
+ ],
5488
+ () => {
5489
+ this.curlyBlock(["return"], () => {
5490
+ this.line("...resource,");
5491
+ this.curlyBlock(["meta:"], () => {
5492
+ this.line(`profile: ['${flatProfile.identifier.url}']`);
5493
+ }, [","]);
5494
+ profileFields.forEach((fieldName) => {
5495
+ this.line(`${fieldName}:`, `profile.${fieldName},`);
5496
+ });
5497
+ });
5498
+ }
5499
+ );
5500
+ this.line();
5501
+ }
5502
+ generateExtractProfile(flatProfile) {
5503
+ const tsBaseResourceName = tsResourceName(flatProfile.base);
5504
+ const tsProfileName = tsResourceName(flatProfile.identifier);
5505
+ const profileFields = Object.entries(flatProfile.fields || {}).filter(([_fieldName, field]) => {
5506
+ return isNotChoiceDeclarationField(field) && field.type !== void 0;
5507
+ }).map(([fieldName]) => fieldName);
5508
+ const specialization = this.tsIndex.resolve(this.tsIndex.findLastSpecialization(flatProfile.identifier));
5509
+ if (!isSpecializationTypeSchema(specialization))
5510
+ throw new Error(`Specialization not found for ${flatProfile.identifier.url}`);
5511
+ const shouldCast = {};
5512
+ this.curlyBlock(
5513
+ [
5514
+ `export const extract_${tsBaseResourceName} =`,
5515
+ `(resource: ${tsBaseResourceName}): ${tsProfileName}`,
5516
+ "=>"
5517
+ ],
5518
+ () => {
5519
+ profileFields.forEach((fieldName) => {
5520
+ const tsField = tsFieldName(fieldName);
5521
+ const pField = flatProfile.fields?.[fieldName];
5522
+ const rField = specialization.fields?.[fieldName];
5523
+ if (!isNotChoiceDeclarationField(pField) || !isNotChoiceDeclarationField(rField)) return;
5524
+ if (pField.required && !rField.required) {
5525
+ this.curlyBlock(
5526
+ [`if (resource.${tsField} === undefined)`],
5527
+ () => this.lineSM(
5528
+ `throw new Error("'${tsField}' is required for ${flatProfile.identifier.url}")`
5529
+ )
5530
+ );
5531
+ }
5532
+ const pRefs = pField?.reference?.map((ref) => ref.name);
5533
+ const rRefs = rField?.reference?.map((ref) => ref.name);
5534
+ if (pRefs && rRefs && pRefs.length !== rRefs.length) {
5535
+ const predName = `reference_pred_${tsField}`;
5536
+ this.curlyBlock(["const", predName, "=", "(ref?: Reference)", "=>"], () => {
5537
+ this.line("return !ref");
5538
+ this.indentBlock(() => {
5539
+ rRefs.forEach((ref) => {
5540
+ this.line(`|| ref.reference?.startsWith('${ref}/')`);
5541
+ });
5542
+ this.line(";");
5543
+ });
5544
+ });
5545
+ let cond = !pField?.required ? `!resource.${tsField} || ` : "";
5546
+ if (pField.array) {
5547
+ cond += `resource.${tsField}.every( (ref) => ${predName}(ref) )`;
5548
+ } else {
5549
+ cond += `${predName}(resource.${tsField})`;
5550
+ }
5551
+ this.curlyBlock(["if (", cond, ")"], () => {
5552
+ this.lineSM(
5553
+ `throw new Error("'${fieldName}' has different references in profile and specialization")`
5554
+ );
5555
+ });
5556
+ this.line();
5557
+ shouldCast[fieldName] = true;
5558
+ }
5559
+ });
5560
+ this.curlyBlock(["return"], () => {
5561
+ this.line(`__profileUrl: '${flatProfile.identifier.url}',`);
5562
+ profileFields.forEach((fieldName) => {
5563
+ const tsField = tsFieldName(fieldName);
5564
+ if (shouldCast[fieldName]) {
5565
+ this.line(`${tsField}:`, `resource.${tsField} as ${tsProfileName}['${tsField}'],`);
5566
+ } else {
5567
+ this.line(`${tsField}:`, `resource.${tsField},`);
5568
+ }
5569
+ });
5570
+ });
5571
+ }
5572
+ );
5573
+ }
5307
5574
  generateResourceModule(schema) {
5308
5575
  this.cat(`${tsModuleFileName(schema.identifier)}`, () => {
5309
5576
  this.generateDisclaimer();
5310
- if (["complex-type", "resource", "logical", "nested"].includes(schema.identifier.kind)) {
5577
+ if (["complex-type", "resource", "logical"].includes(schema.identifier.kind)) {
5311
5578
  this.generateDependenciesImports(schema);
5312
5579
  this.generateComplexTypeReexports(schema);
5313
5580
  this.generateNestedTypes(schema);
5314
5581
  this.generateType(schema);
5315
- } else {
5316
- throw new Error(`Profile generation not implemented for kind: ${schema.identifier.kind}`);
5317
- }
5582
+ } else if (isProfileTypeSchema(schema)) {
5583
+ const flatProfile = this.tsIndex.flatProfile(schema);
5584
+ this.generateDependenciesImports(flatProfile);
5585
+ this.generateProfileType(flatProfile);
5586
+ this.generateAttachProfile(flatProfile);
5587
+ this.generateExtractProfile(flatProfile);
5588
+ } else throw new Error(`Profile generation not implemented for kind: ${schema.identifier.kind}`);
5318
5589
  });
5319
5590
  }
5320
5591
  generate(schemas) {
5592
+ this.tsIndex = mkTypeSchemaIndex(schemas);
5321
5593
  const typesToGenerate = [
5322
5594
  ...collectComplexTypes(schemas),
5323
- ...collectResources(schemas)
5324
- // ...collectLogicalModels(typeSchemas),
5325
- // ...collectProfiles(typeSchemas),
5595
+ ...collectResources(schemas),
5596
+ // ...collectLogicalModels(schemas),
5597
+ ...collectProfiles(schemas).filter((p) => this.tsIndex.isWithMetaField(p))
5326
5598
  ];
5327
- this.resourceRelatives = resourceRelatives(typesToGenerate);
5328
5599
  const grouped = groupByPackages(typesToGenerate);
5329
5600
  this.cd("/", () => {
5330
5601
  for (const [packageName, packageSchemas] of Object.entries(grouped)) {