@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/cli/index.js +28 -28
- package/dist/index.d.ts +6 -6
- package/dist/index.js +316 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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) =>
|
|
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
|
|
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
|
|
5125
|
-
|
|
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
|
-
|
|
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
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
}))
|
|
5221
|
-
|
|
5222
|
-
|
|
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(
|
|
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,
|
|
5267
|
-
|
|
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
|
|
5395
|
+
const tsName = tsFieldName(fieldName);
|
|
5271
5396
|
const optionalSymbol = field.required ? "" : "?";
|
|
5272
5397
|
const arraySymbol = field.array ? "[]" : "";
|
|
5273
|
-
if (field.type === void 0)
|
|
5274
|
-
|
|
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
|
-
|
|
5401
|
+
tsType = tsResourceName(field.type);
|
|
5279
5402
|
}
|
|
5280
5403
|
if (field.type.kind === "primitive-type") {
|
|
5281
|
-
|
|
5404
|
+
tsType = primitiveType2tsType[field.type.name] ?? "string";
|
|
5282
5405
|
}
|
|
5283
|
-
if (schema.identifier.name === "Reference" &&
|
|
5284
|
-
|
|
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
|
-
|
|
5411
|
+
tsType = `Reference<${references}>`;
|
|
5289
5412
|
}
|
|
5290
5413
|
if (field.enum) {
|
|
5291
|
-
|
|
5414
|
+
tsType = field.enum.map((e) => `"${e}"`).join(" | ");
|
|
5292
5415
|
}
|
|
5293
|
-
this.lineSM(`${
|
|
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"
|
|
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
|
-
|
|
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(
|
|
5325
|
-
|
|
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)) {
|