@atomic-ehr/codegen 0.0.10 → 0.0.11
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/assets/api/writer-generator/typescript/profile-helpers.ts +57 -20
- package/dist/cli/index.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +368 -141
- package/dist/index.js.map +1 -1
- package/package.json +10 -6
package/dist/index.js
CHANGED
|
@@ -1482,11 +1482,31 @@ var Python = class extends Writer {
|
|
|
1482
1482
|
}
|
|
1483
1483
|
generateFields(schema, schemaName) {
|
|
1484
1484
|
const sortedFields = Object.entries(schema.fields ?? []).sort(([a], [b]) => a.localeCompare(b));
|
|
1485
|
+
const withExtensions = this.shouldAddPrimitiveExtensions(schema);
|
|
1485
1486
|
for (const [fieldName, field] of sortedFields) {
|
|
1486
1487
|
if ("choices" in field && field.choices) continue;
|
|
1487
1488
|
const fieldInfo = this.buildFieldInfo(fieldName, field, schemaName);
|
|
1488
1489
|
this.line(`${fieldInfo.name}: ${fieldInfo.type}${fieldInfo.defaultValue}`);
|
|
1490
|
+
if (withExtensions && "type" in field && isPrimitiveIdentifier(field.type)) {
|
|
1491
|
+
this.addPrimitiveExtensionField(fieldName, field.array ?? false);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
shouldAddPrimitiveExtensions(schema) {
|
|
1496
|
+
if (!this.opts.primitiveTypeExtension) return false;
|
|
1497
|
+
if (!isSpecializationTypeSchema(schema)) return false;
|
|
1498
|
+
for (const field of Object.values(schema.fields ?? {})) {
|
|
1499
|
+
if ("choices" in field && field.choices) continue;
|
|
1500
|
+
if ("type" in field && isPrimitiveIdentifier(field.type)) return true;
|
|
1489
1501
|
}
|
|
1502
|
+
return false;
|
|
1503
|
+
}
|
|
1504
|
+
addPrimitiveExtensionField(fieldName, isArray) {
|
|
1505
|
+
const pyFieldName = this.nameFormatFunction(`${fieldName}Extension`);
|
|
1506
|
+
const alias = `_${fieldName}`;
|
|
1507
|
+
const typeExpr = isArray ? "PyList[Element | None] | None" : "Element | None";
|
|
1508
|
+
const aliasSpec = `alias="${alias}", serialization_alias="${alias}"`;
|
|
1509
|
+
this.line(`${pyFieldName}: ${typeExpr} = Field(None, ${aliasSpec})`);
|
|
1490
1510
|
}
|
|
1491
1511
|
buildFieldInfo(fieldName, field, schemaName) {
|
|
1492
1512
|
const pyFieldName = fixReservedWords(this.nameFormatFunction(fieldName));
|
|
@@ -1571,6 +1591,18 @@ var Python = class extends Writer {
|
|
|
1571
1591
|
if (!schema.dependencies || schema.dependencies.length === 0) return;
|
|
1572
1592
|
this.importComplexTypeDependencies(schema.dependencies);
|
|
1573
1593
|
this.importResourceDependencies(schema.dependencies);
|
|
1594
|
+
this.importElementIfNeeded(schema);
|
|
1595
|
+
}
|
|
1596
|
+
importElementIfNeeded(schema) {
|
|
1597
|
+
if (!this.shouldAddPrimitiveExtensions(schema)) return;
|
|
1598
|
+
if (schema.identifier.name === "Element") return;
|
|
1599
|
+
if (schema.dependencies?.find((d) => d.name === "Element")) return;
|
|
1600
|
+
assert4(this.tsIndex !== void 0);
|
|
1601
|
+
const elementUrl = "http://hl7.org/fhir/StructureDefinition/Element";
|
|
1602
|
+
const element = this.tsIndex.resolveByUrl(schema.identifier.package, elementUrl);
|
|
1603
|
+
if (!element) return;
|
|
1604
|
+
const pyPackage = this.pyPackage(element.identifier);
|
|
1605
|
+
this.pyImportFrom(pyPackage, "Element");
|
|
1574
1606
|
}
|
|
1575
1607
|
importComplexTypeDependencies(dependencies) {
|
|
1576
1608
|
const complexTypeDeps = dependencies.filter((dep) => dep.kind === "complex-type");
|
|
@@ -2450,7 +2482,7 @@ var navigateMatch = (match, remainingPath) => {
|
|
|
2450
2482
|
}
|
|
2451
2483
|
return value;
|
|
2452
2484
|
};
|
|
2453
|
-
var collectDiscriminatorValue = (schema, segments, index, result) => {
|
|
2485
|
+
var collectDiscriminatorValue = (schema, segments, index, result, arrayPaths) => {
|
|
2454
2486
|
if (index >= segments.length || !schema.elements) return;
|
|
2455
2487
|
const segment = segments[index];
|
|
2456
2488
|
const element = schema.elements[segment];
|
|
@@ -2460,6 +2492,7 @@ var collectDiscriminatorValue = (schema, segments, index, result) => {
|
|
|
2460
2492
|
return;
|
|
2461
2493
|
}
|
|
2462
2494
|
if (element.slicing?.slices) {
|
|
2495
|
+
arrayPaths.add(segments.slice(0, index + 1).join("."));
|
|
2463
2496
|
const remainingSegments = segments.slice(index + 1);
|
|
2464
2497
|
for (const subSlice of Object.values(element.slicing.slices)) {
|
|
2465
2498
|
if (!subSlice.min || subSlice.min < 1 || !subSlice.match || typeof subSlice.match !== "object") continue;
|
|
@@ -2474,7 +2507,7 @@ var collectDiscriminatorValue = (schema, segments, index, result) => {
|
|
|
2474
2507
|
}
|
|
2475
2508
|
return;
|
|
2476
2509
|
}
|
|
2477
|
-
collectDiscriminatorValue(element, segments, index + 1, result);
|
|
2510
|
+
collectDiscriminatorValue(element, segments, index + 1, result, arrayPaths);
|
|
2478
2511
|
};
|
|
2479
2512
|
var computeTypeDiscriminatorMatch = (path, schema, result) => {
|
|
2480
2513
|
if (path === "$this") return;
|
|
@@ -2491,16 +2524,31 @@ var computeTypeDiscriminatorMatch = (path, schema, result) => {
|
|
|
2491
2524
|
var computeMatchFromSchema = (discriminators, schema) => {
|
|
2492
2525
|
if (!schema || !discriminators || discriminators.length === 0) return void 0;
|
|
2493
2526
|
const result = {};
|
|
2527
|
+
const arrayPaths = /* @__PURE__ */ new Set();
|
|
2494
2528
|
for (const disc of discriminators) {
|
|
2495
2529
|
if (disc.type === "type") {
|
|
2496
2530
|
computeTypeDiscriminatorMatch(disc.path, schema, result);
|
|
2497
2531
|
} else {
|
|
2498
2532
|
if (!schema.elements) continue;
|
|
2499
2533
|
const segments = disc.path.split(".");
|
|
2500
|
-
collectDiscriminatorValue(schema, segments, 0, result);
|
|
2534
|
+
collectDiscriminatorValue(schema, segments, 0, result, arrayPaths);
|
|
2501
2535
|
}
|
|
2502
2536
|
}
|
|
2503
|
-
|
|
2537
|
+
if (Object.keys(result).length === 0) return void 0;
|
|
2538
|
+
for (const path of arrayPaths) {
|
|
2539
|
+
const segments = path.split(".");
|
|
2540
|
+
let target = result;
|
|
2541
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
2542
|
+
const v = target[segments[i]];
|
|
2543
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) break;
|
|
2544
|
+
target = v;
|
|
2545
|
+
}
|
|
2546
|
+
const key = segments[segments.length - 1];
|
|
2547
|
+
if (target[key] && typeof target[key] === "object" && !Array.isArray(target[key])) {
|
|
2548
|
+
target[key] = [target[key]];
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
return result;
|
|
2504
2552
|
};
|
|
2505
2553
|
var buildSlicing = (element) => {
|
|
2506
2554
|
const slicing = element.slicing;
|
|
@@ -4221,6 +4269,9 @@ var tsProfileClassName = (schema) => {
|
|
|
4221
4269
|
var tsSliceFlatTypeName = (profileName, fieldName, sliceName) => {
|
|
4222
4270
|
return `${uppercaseFirstLetter(profileName)}_${uppercaseFirstLetter(normalizeTsName(fieldName))}_${uppercaseFirstLetter(normalizeTsName(sliceName))}SliceFlat`;
|
|
4223
4271
|
};
|
|
4272
|
+
var tsSliceFlatAllTypeName = (profileName, fieldName, sliceName) => {
|
|
4273
|
+
return `${uppercaseFirstLetter(profileName)}_${uppercaseFirstLetter(normalizeTsName(fieldName))}_${uppercaseFirstLetter(normalizeTsName(sliceName))}SliceFlatAll`;
|
|
4274
|
+
};
|
|
4224
4275
|
var tsExtensionFlatTypeName = (profileName, extensionName) => {
|
|
4225
4276
|
return `${uppercaseFirstLetter(profileName)}_${uppercaseFirstLetter(normalizeTsName(extensionName))}Flat`;
|
|
4226
4277
|
};
|
|
@@ -4284,7 +4335,7 @@ var rewriteFieldTypeDefs = {
|
|
|
4284
4335
|
Reference: { reference: () => "`${T}/${string}`" },
|
|
4285
4336
|
CodeableConcept: { coding: () => "Coding<T>" }
|
|
4286
4337
|
};
|
|
4287
|
-
var resolveFieldTsType = (schemaName, tsName, field, resolveRef, genericFieldMap) => {
|
|
4338
|
+
var resolveFieldTsType = (schemaName, tsName, field, resolveRef, genericFieldMap, isFamilyType) => {
|
|
4288
4339
|
if (genericFieldMap?.[tsName]) return genericFieldMap[tsName];
|
|
4289
4340
|
const rewriteFieldType = rewriteFieldTypeDefs[schemaName]?.[tsName];
|
|
4290
4341
|
if (rewriteFieldType) return rewriteFieldType();
|
|
@@ -4294,14 +4345,15 @@ var resolveFieldTsType = (schemaName, tsName, field, resolveRef, genericFieldMap
|
|
|
4294
4345
|
return tsEnumType(field.enum);
|
|
4295
4346
|
}
|
|
4296
4347
|
if (field.reference && field.reference.length > 0) {
|
|
4297
|
-
const
|
|
4348
|
+
const resolved = field.reference.map((ref) => resolveRef ? resolveRef(ref) : ref);
|
|
4349
|
+
const references = resolved.map((ref) => isFamilyType?.(ref) ? `string /* ${ref.name} */` : `"${ref.name}"`).join(" | ");
|
|
4298
4350
|
return `Reference<${references}>`;
|
|
4299
4351
|
}
|
|
4300
4352
|
if (isPrimitiveIdentifier(field.type)) return resolvePrimitiveType(field.type.name);
|
|
4301
4353
|
if (isNestedIdentifier(field.type)) return tsResourceName(field.type);
|
|
4302
4354
|
return field.type.name;
|
|
4303
4355
|
};
|
|
4304
|
-
var fieldTsType = (field, resolveRef) => resolveFieldTsType("", "", field, resolveRef) + (field.array ? "[]" : "");
|
|
4356
|
+
var fieldTsType = (field, resolveRef, isFamilyType) => resolveFieldTsType("", "", field, resolveRef, void 0, isFamilyType) + (field.array ? "[]" : "");
|
|
4305
4357
|
var tsTypeFromIdentifier = (id) => {
|
|
4306
4358
|
if (isNestedIdentifier(id)) return tsResourceName(id);
|
|
4307
4359
|
if (isPrimitiveIdentifier(id)) return resolvePrimitiveType(id.name);
|
|
@@ -4370,21 +4422,22 @@ var resolveExtensionProfile = (tsIndex, pkgName, url) => {
|
|
|
4370
4422
|
const flatProfile = tsIndex.flatProfile(schema);
|
|
4371
4423
|
return { className, modulePath, flatProfile };
|
|
4372
4424
|
};
|
|
4373
|
-
var generateRawExtensionBody = (w, ext, targetPath, paramName = "input") => {
|
|
4425
|
+
var generateRawExtensionBody = (w, ext, targetPath, paramName = "input", useUpsert = false) => {
|
|
4374
4426
|
w.line(
|
|
4375
4427
|
`if (${paramName}.url !== ${JSON.stringify(ext.url)}) throw new Error(\`Expected extension url '${ext.url}', got '\${${paramName}.url}'\`)`
|
|
4376
4428
|
);
|
|
4377
|
-
generateExtensionPush(w, targetPath, paramName);
|
|
4429
|
+
generateExtensionPush(w, targetPath, paramName, useUpsert);
|
|
4378
4430
|
};
|
|
4379
|
-
var generateExtensionPush = (w, targetPath, extExpr) => {
|
|
4431
|
+
var generateExtensionPush = (w, targetPath, extExpr, useUpsert = false) => {
|
|
4432
|
+
const fn = useUpsert ? "upsertExtension" : "pushExtension";
|
|
4380
4433
|
if (targetPath.length === 0) {
|
|
4381
|
-
w.line(
|
|
4434
|
+
w.line(`${fn}(this.resource, ${extExpr})`);
|
|
4382
4435
|
} else {
|
|
4383
4436
|
w.line(
|
|
4384
4437
|
`const target = ensurePath(this.resource as unknown as Record<string, unknown>, ${JSON.stringify(targetPath)})`
|
|
4385
4438
|
);
|
|
4386
4439
|
w.line("if (!Array.isArray(target.extension)) target.extension = [] as Extension[]");
|
|
4387
|
-
w.line(
|
|
4440
|
+
w.line(`${fn}(target as unknown as { extension?: Extension[] }, ${extExpr})`);
|
|
4388
4441
|
}
|
|
4389
4442
|
};
|
|
4390
4443
|
var generateExtLookup = (w, ext, targetPath) => {
|
|
@@ -4437,6 +4490,7 @@ var generateComplexExtensionSetter = (w, info) => {
|
|
|
4437
4490
|
const tsProfileName = tsResourceName(flatProfile.identifier);
|
|
4438
4491
|
const inputTypeName = tsExtensionFlatTypeName(tsProfileName, ext.name);
|
|
4439
4492
|
const extProfileHasFlatInput = extProfileInfo ? collectSubExtensionSlices(extProfileInfo.flatProfile).length > 0 : false;
|
|
4493
|
+
const useUpsert = ext.max === "1";
|
|
4440
4494
|
if (extProfileInfo && extProfileHasFlatInput) {
|
|
4441
4495
|
const paramType = `${extProfileInfo.className}Flat | ${extProfileInfo.className} | Extension`;
|
|
4442
4496
|
w.curlyBlock(["public", setMethodName, `(input: ${paramType}): this`], () => {
|
|
@@ -4444,14 +4498,19 @@ var generateComplexExtensionSetter = (w, info) => {
|
|
|
4444
4498
|
[
|
|
4445
4499
|
{
|
|
4446
4500
|
cond: `input instanceof ${extProfileInfo.className}`,
|
|
4447
|
-
body: () => generateExtensionPush(w, targetPath, "input.toResource()")
|
|
4501
|
+
body: () => generateExtensionPush(w, targetPath, "input.toResource()", useUpsert)
|
|
4448
4502
|
},
|
|
4449
4503
|
{
|
|
4450
4504
|
cond: "isExtension<Extension>(input)",
|
|
4451
|
-
body: () => generateRawExtensionBody(w, ext, targetPath)
|
|
4505
|
+
body: () => generateRawExtensionBody(w, ext, targetPath, "input", useUpsert)
|
|
4452
4506
|
}
|
|
4453
4507
|
],
|
|
4454
|
-
() => generateExtensionPush(
|
|
4508
|
+
() => generateExtensionPush(
|
|
4509
|
+
w,
|
|
4510
|
+
targetPath,
|
|
4511
|
+
`${extProfileInfo.className}.createResource(input)`,
|
|
4512
|
+
useUpsert
|
|
4513
|
+
)
|
|
4455
4514
|
);
|
|
4456
4515
|
w.line("return this");
|
|
4457
4516
|
});
|
|
@@ -4474,15 +4533,16 @@ var generateComplexExtensionSetter = (w, info) => {
|
|
|
4474
4533
|
});
|
|
4475
4534
|
}
|
|
4476
4535
|
}
|
|
4536
|
+
const extLiteral = `{ url: "${ext.url}", extension: subExtensions }`;
|
|
4537
|
+
const fn = useUpsert ? "upsertExtension" : "pushExtension";
|
|
4477
4538
|
if (targetPath.length === 0) {
|
|
4478
|
-
w.line(
|
|
4479
|
-
w.line(`list.push({ url: "${ext.url}", extension: subExtensions })`);
|
|
4539
|
+
w.line(`${fn}(this.resource, ${extLiteral})`);
|
|
4480
4540
|
} else {
|
|
4481
4541
|
w.line(
|
|
4482
4542
|
`const target = ensurePath(this.resource as unknown as Record<string, unknown>, ${JSON.stringify(targetPath)})`
|
|
4483
4543
|
);
|
|
4484
4544
|
w.line("if (!Array.isArray(target.extension)) target.extension = [] as Extension[]");
|
|
4485
|
-
w.line(
|
|
4545
|
+
w.line(`${fn}(target as unknown as { extension?: Extension[] }, ${extLiteral})`);
|
|
4486
4546
|
}
|
|
4487
4547
|
w.line("return this");
|
|
4488
4548
|
});
|
|
@@ -4510,32 +4570,33 @@ var generateSingleValueExtensionSetter = (w, tsIndex, info) => {
|
|
|
4510
4570
|
if (!firstValueType) return;
|
|
4511
4571
|
const valueType = tsTypeFromIdentifier(firstValueType);
|
|
4512
4572
|
const valueField = tsValueFieldName(firstValueType);
|
|
4573
|
+
const useUpsert = ext.max === "1";
|
|
4513
4574
|
if (extProfileInfo) {
|
|
4514
|
-
const
|
|
4515
|
-
const
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
const elseExpr =
|
|
4575
|
+
const extFactoryInfo = collectProfileFactoryInfo(tsIndex, extProfileInfo.flatProfile);
|
|
4576
|
+
const extValueParam = extFactoryInfo.params.find((p) => p.name === valueField);
|
|
4577
|
+
const resolvedValueType = extValueParam?.tsType ?? valueType;
|
|
4578
|
+
const paramType = `${extProfileInfo.className} | Extension | ${resolvedValueType}`;
|
|
4579
|
+
const elseExpr = extValueParam ? `${extProfileInfo.className}.createResource({ ${valueField}: value as ${resolvedValueType} })` : `{ url: "${ext.url}", ${valueField}: value as ${valueType} } as Extension`;
|
|
4519
4580
|
w.curlyBlock(["public", setMethodName, `(value: ${paramType}): this`], () => {
|
|
4520
4581
|
w.ifElseChain(
|
|
4521
4582
|
[
|
|
4522
4583
|
{
|
|
4523
4584
|
cond: `value instanceof ${extProfileInfo.className}`,
|
|
4524
|
-
body: () => generateExtensionPush(w, targetPath, "value.toResource()")
|
|
4585
|
+
body: () => generateExtensionPush(w, targetPath, "value.toResource()", useUpsert)
|
|
4525
4586
|
},
|
|
4526
4587
|
{
|
|
4527
4588
|
cond: "isExtension(value)",
|
|
4528
|
-
body: () => generateRawExtensionBody(w, ext, targetPath, "value")
|
|
4589
|
+
body: () => generateRawExtensionBody(w, ext, targetPath, "value", useUpsert)
|
|
4529
4590
|
}
|
|
4530
4591
|
],
|
|
4531
|
-
() => generateExtensionPush(w, targetPath, elseExpr)
|
|
4592
|
+
() => generateExtensionPush(w, targetPath, elseExpr, useUpsert)
|
|
4532
4593
|
);
|
|
4533
4594
|
w.line("return this");
|
|
4534
4595
|
});
|
|
4535
4596
|
} else {
|
|
4536
4597
|
w.curlyBlock(["public", setMethodName, `(value: ${valueType}): this`], () => {
|
|
4537
4598
|
const extLiteral = `{ url: "${ext.url}", ${valueField}: value } as Extension`;
|
|
4538
|
-
generateExtensionPush(w, targetPath, extLiteral);
|
|
4599
|
+
generateExtensionPush(w, targetPath, extLiteral, useUpsert);
|
|
4539
4600
|
w.line("return this");
|
|
4540
4601
|
});
|
|
4541
4602
|
}
|
|
@@ -4552,15 +4613,16 @@ var generateSingleValueExtensionGetter = (w, info) => {
|
|
|
4552
4613
|
};
|
|
4553
4614
|
var generateGenericExtensionSetter = (w, info) => {
|
|
4554
4615
|
const { ext, setMethodName, targetPath } = info;
|
|
4616
|
+
const useUpsert = ext.max === "1";
|
|
4555
4617
|
w.curlyBlock(["public", setMethodName, `(value: Omit<Extension, "url"> | Extension): this`], () => {
|
|
4556
4618
|
w.ifElseChain(
|
|
4557
4619
|
[
|
|
4558
4620
|
{
|
|
4559
4621
|
cond: "isExtension(value)",
|
|
4560
|
-
body: () => generateRawExtensionBody(w, ext, targetPath, "value")
|
|
4622
|
+
body: () => generateRawExtensionBody(w, ext, targetPath, "value", useUpsert)
|
|
4561
4623
|
}
|
|
4562
4624
|
],
|
|
4563
|
-
() => generateExtensionPush(w, targetPath, `{ url: "${ext.url}", ...value } as Extension
|
|
4625
|
+
() => generateExtensionPush(w, targetPath, `{ url: "${ext.url}", ...value } as Extension`, useUpsert)
|
|
4564
4626
|
);
|
|
4565
4627
|
w.line("return this");
|
|
4566
4628
|
});
|
|
@@ -4694,7 +4756,14 @@ var collectTypesFromSlices = (tsIndex, flatProfile, addType) => {
|
|
|
4694
4756
|
};
|
|
4695
4757
|
var collectRequiredSliceNames = (field) => {
|
|
4696
4758
|
if (!field.array || !field.slicing?.slices) return void 0;
|
|
4697
|
-
const
|
|
4759
|
+
const isTypeDisc = field.slicing.discriminator?.some((d) => d.type === "type") ?? false;
|
|
4760
|
+
if (isTypeDisc) return void 0;
|
|
4761
|
+
const names = Object.entries(field.slicing.slices).filter(([_, s]) => {
|
|
4762
|
+
if (s.min === void 0 || s.min < 1 || !s.match || Object.keys(s.match).length === 0) return false;
|
|
4763
|
+
const matchKeys = new Set(Object.keys(s.match));
|
|
4764
|
+
const requiredBeyondMatch = (s.required ?? []).filter((name) => !matchKeys.has(name));
|
|
4765
|
+
return requiredBeyondMatch.length === 0;
|
|
4766
|
+
}).map(([name]) => name);
|
|
4698
4767
|
return names.length > 0 ? names : void 0;
|
|
4699
4768
|
};
|
|
4700
4769
|
var collectSliceDefs = (tsIndex, flatProfile) => Object.entries(flatProfile.fields ?? {}).filter(([_, field]) => isNotChoiceDeclarationField(field) && field.slicing?.slices).flatMap(([fieldName, field]) => {
|
|
@@ -4722,7 +4791,8 @@ var collectSliceDefs = (tsIndex, flatProfile) => Object.entries(flatProfile.fiel
|
|
|
4722
4791
|
excluded: slice.excluded ?? [],
|
|
4723
4792
|
array: Boolean(field.array),
|
|
4724
4793
|
constrainedChoice,
|
|
4725
|
-
typeDiscriminator: isTypeDisc
|
|
4794
|
+
typeDiscriminator: isTypeDisc,
|
|
4795
|
+
max: slice.max ?? 0
|
|
4726
4796
|
};
|
|
4727
4797
|
});
|
|
4728
4798
|
});
|
|
@@ -4732,39 +4802,61 @@ var generateSliceSetters = (w, sliceDefs, flatProfile, sliceBaseNames) => {
|
|
|
4732
4802
|
for (const sliceDef of sliceDefs) {
|
|
4733
4803
|
const baseName = tsResolvedSliceBaseName(sliceBaseNames, sliceDef.fieldName, sliceDef.sliceName);
|
|
4734
4804
|
const methodName = `set${baseName}`;
|
|
4735
|
-
const
|
|
4805
|
+
const inputTypeName = tsSliceFlatTypeName(tsProfileName, sliceDef.fieldName, sliceDef.sliceName);
|
|
4736
4806
|
const matchRef = `${profileClassName}.${tsSliceStaticName(sliceDef.sliceName)}SliceMatch`;
|
|
4737
4807
|
const tsField = tsFieldName(sliceDef.fieldName);
|
|
4738
4808
|
const fieldAccess = tsGet("this.resource", tsField);
|
|
4739
4809
|
const baseType = sliceDef.typedBaseType;
|
|
4740
|
-
const
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
w.
|
|
4745
|
-
|
|
4810
|
+
const isUnbounded = sliceDef.array && (sliceDef.max === 0 || sliceDef.max === void 0);
|
|
4811
|
+
if (isUnbounded) {
|
|
4812
|
+
const unionType = `(${inputTypeName} | ${baseType})[]`;
|
|
4813
|
+
const paramSignature = `(input: ${unionType}): this`;
|
|
4814
|
+
w.curlyBlock(["public", methodName, paramSignature], () => {
|
|
4815
|
+
w.line(`const match = ${matchRef}`);
|
|
4816
|
+
w.line(`const arr = ${fieldAccess} ??= []`);
|
|
4817
|
+
if (sliceDef.constrainedChoice) {
|
|
4818
|
+
const cc = sliceDef.constrainedChoice;
|
|
4819
|
+
w.line(
|
|
4820
|
+
`const values = input.map(item => matchesValue(item, match) ? item as ${baseType} : applySliceMatch<${baseType}>(wrapSliceChoice<${baseType}>(item, ${JSON.stringify(cc.variant)}), match))`
|
|
4821
|
+
);
|
|
4822
|
+
} else {
|
|
4823
|
+
w.line(
|
|
4824
|
+
`const values = input.map(item => matchesValue(item, match) ? item as ${baseType} : applySliceMatch<${baseType}>(item, match))`
|
|
4825
|
+
);
|
|
4826
|
+
}
|
|
4827
|
+
w.line("setArraySliceAll(arr, match, values)");
|
|
4828
|
+
w.line("return this");
|
|
4829
|
+
});
|
|
4830
|
+
} else {
|
|
4831
|
+
const inputOptional = sliceDef.required.length === 0;
|
|
4832
|
+
const unionType = `${inputTypeName} | ${baseType}`;
|
|
4833
|
+
const paramSignature = inputOptional ? `(input?: ${unionType}): this` : `(input: ${unionType}): this`;
|
|
4834
|
+
w.curlyBlock(["public", methodName, paramSignature], () => {
|
|
4835
|
+
w.line(`const match = ${matchRef}`);
|
|
4836
|
+
w.curlyBlock(["if", "(input && matchesValue(input, match))"], () => {
|
|
4837
|
+
if (sliceDef.array) {
|
|
4838
|
+
w.line(`setArraySlice(${fieldAccess} ??= [], match, input as ${baseType})`);
|
|
4839
|
+
} else {
|
|
4840
|
+
w.line(`${fieldAccess} = input as ${baseType}`);
|
|
4841
|
+
}
|
|
4842
|
+
w.line("return this");
|
|
4843
|
+
});
|
|
4844
|
+
const inputExpr = inputOptional ? "input ?? {}" : "input";
|
|
4845
|
+
if (sliceDef.constrainedChoice) {
|
|
4846
|
+
const cc = sliceDef.constrainedChoice;
|
|
4847
|
+
w.line(`const wrapped = wrapSliceChoice<${baseType}>(${inputExpr}, ${JSON.stringify(cc.variant)})`);
|
|
4848
|
+
w.line(`const value = applySliceMatch<${baseType}>(wrapped, match)`);
|
|
4849
|
+
} else {
|
|
4850
|
+
w.line(`const value = applySliceMatch<${baseType}>(${inputExpr}, match)`);
|
|
4851
|
+
}
|
|
4746
4852
|
if (sliceDef.array) {
|
|
4747
|
-
w.line(`setArraySlice(${fieldAccess} ??= [], match,
|
|
4853
|
+
w.line(`setArraySlice(${fieldAccess} ??= [], match, value)`);
|
|
4748
4854
|
} else {
|
|
4749
|
-
w.line(`${fieldAccess} =
|
|
4855
|
+
w.line(`${fieldAccess} = value`);
|
|
4750
4856
|
}
|
|
4751
4857
|
w.line("return this");
|
|
4752
4858
|
});
|
|
4753
|
-
|
|
4754
|
-
if (sliceDef.constrainedChoice) {
|
|
4755
|
-
const cc = sliceDef.constrainedChoice;
|
|
4756
|
-
w.line(`const wrapped = wrapSliceChoice<${baseType}>(${inputExpr}, ${JSON.stringify(cc.variant)})`);
|
|
4757
|
-
w.line(`const value = applySliceMatch<${baseType}>(wrapped, match)`);
|
|
4758
|
-
} else {
|
|
4759
|
-
w.line(`const value = applySliceMatch<${baseType}>(${inputExpr}, match)`);
|
|
4760
|
-
}
|
|
4761
|
-
if (sliceDef.array) {
|
|
4762
|
-
w.line(`setArraySlice(${fieldAccess} ??= [], match, value)`);
|
|
4763
|
-
} else {
|
|
4764
|
-
w.line(`${fieldAccess} = value`);
|
|
4765
|
-
}
|
|
4766
|
-
w.line("return this");
|
|
4767
|
-
});
|
|
4859
|
+
}
|
|
4768
4860
|
w.line();
|
|
4769
4861
|
}
|
|
4770
4862
|
};
|
|
@@ -4775,52 +4867,85 @@ var generateSliceGetters = (w, sliceDefs, flatProfile, sliceBaseNames) => {
|
|
|
4775
4867
|
for (const sliceDef of sliceDefs) {
|
|
4776
4868
|
const baseName = tsResolvedSliceBaseName(sliceBaseNames, sliceDef.fieldName, sliceDef.sliceName);
|
|
4777
4869
|
const getMethodName = `get${baseName}`;
|
|
4778
|
-
const
|
|
4870
|
+
const flatTypeName = tsSliceFlatAllTypeName(tsProfileName, sliceDef.fieldName, sliceDef.sliceName);
|
|
4779
4871
|
const matchRef = `${profileClassName}.${tsSliceStaticName(sliceDef.sliceName)}SliceMatch`;
|
|
4780
4872
|
const matchKeys = JSON.stringify(Object.keys(sliceDef.match));
|
|
4781
4873
|
const tsField = tsFieldName(sliceDef.fieldName);
|
|
4782
4874
|
const fieldAccess = tsGet("this.resource", tsField);
|
|
4783
4875
|
const baseType = sliceDef.typedBaseType;
|
|
4784
|
-
const
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
w.line(`const
|
|
4798
|
-
w.line(
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4876
|
+
const isUnbounded = sliceDef.array && (sliceDef.max === 0 || sliceDef.max === void 0);
|
|
4877
|
+
if (isUnbounded) {
|
|
4878
|
+
const defaultReturn = defaultMode === "raw" ? `${baseType}[]` : `${flatTypeName}[]`;
|
|
4879
|
+
w.lineSM(`public ${getMethodName}(mode: 'flat'): ${flatTypeName}[] | undefined`);
|
|
4880
|
+
w.lineSM(`public ${getMethodName}(mode: 'raw'): ${baseType}[] | undefined`);
|
|
4881
|
+
w.lineSM(`public ${getMethodName}(): ${defaultReturn} | undefined`);
|
|
4882
|
+
w.curlyBlock(
|
|
4883
|
+
[
|
|
4884
|
+
"public",
|
|
4885
|
+
getMethodName,
|
|
4886
|
+
`(mode: 'flat' | 'raw' = '${defaultMode}'): (${flatTypeName} | ${baseType})[] | undefined`
|
|
4887
|
+
],
|
|
4888
|
+
() => {
|
|
4889
|
+
w.line(`const match = ${matchRef}`);
|
|
4890
|
+
w.line(`const items = getArraySliceAll(${fieldAccess}, match)`);
|
|
4891
|
+
w.line("if (items.length === 0) return undefined");
|
|
4892
|
+
if (sliceDef.typeDiscriminator) {
|
|
4893
|
+
w.line(`if (mode === 'raw') return items as ${baseType}[]`);
|
|
4894
|
+
} else {
|
|
4895
|
+
w.line("if (mode === 'raw') return items");
|
|
4896
|
+
}
|
|
4897
|
+
if (sliceDef.constrainedChoice) {
|
|
4898
|
+
const cc = sliceDef.constrainedChoice;
|
|
4899
|
+
w.line(
|
|
4900
|
+
`return items.map(item => unwrapSliceChoice<${flatTypeName}>(item, ${matchKeys}, ${JSON.stringify(cc.variant)}))`
|
|
4901
|
+
);
|
|
4902
|
+
} else {
|
|
4903
|
+
w.line(`return items as unknown as ${flatTypeName}[]`);
|
|
4904
|
+
}
|
|
4807
4905
|
}
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4906
|
+
);
|
|
4907
|
+
} else {
|
|
4908
|
+
const defaultReturn = defaultMode === "raw" ? baseType : flatTypeName;
|
|
4909
|
+
w.lineSM(`public ${getMethodName}(mode: 'flat'): ${flatTypeName} | undefined`);
|
|
4910
|
+
w.lineSM(`public ${getMethodName}(mode: 'raw'): ${baseType} | undefined`);
|
|
4911
|
+
w.lineSM(`public ${getMethodName}(): ${defaultReturn} | undefined`);
|
|
4912
|
+
w.curlyBlock(
|
|
4913
|
+
[
|
|
4914
|
+
"public",
|
|
4915
|
+
getMethodName,
|
|
4916
|
+
`(mode: 'flat' | 'raw' = '${defaultMode}'): ${flatTypeName} | ${baseType} | undefined`
|
|
4917
|
+
],
|
|
4918
|
+
() => {
|
|
4919
|
+
w.line(`const match = ${matchRef}`);
|
|
4920
|
+
if (sliceDef.array) {
|
|
4921
|
+
w.line(`const item = getArraySlice(${fieldAccess}, match)`);
|
|
4922
|
+
w.line("if (!item) return undefined");
|
|
4923
|
+
} else {
|
|
4924
|
+
w.line(`const item = ${fieldAccess}`);
|
|
4925
|
+
w.line("if (!item || !matchesValue(item, match)) return undefined");
|
|
4926
|
+
}
|
|
4927
|
+
if (sliceDef.typeDiscriminator) {
|
|
4928
|
+
w.line(`if (mode === 'raw') return item as ${baseType}`);
|
|
4929
|
+
} else {
|
|
4930
|
+
w.line("if (mode === 'raw') return item");
|
|
4931
|
+
}
|
|
4932
|
+
if (sliceDef.constrainedChoice) {
|
|
4933
|
+
const cc = sliceDef.constrainedChoice;
|
|
4934
|
+
w.line(
|
|
4935
|
+
`return unwrapSliceChoice<${flatTypeName}>(item, ${matchKeys}, ${JSON.stringify(cc.variant)})`
|
|
4936
|
+
);
|
|
4937
|
+
} else {
|
|
4938
|
+
w.line(`return item as unknown as ${flatTypeName}`);
|
|
4939
|
+
}
|
|
4815
4940
|
}
|
|
4816
|
-
|
|
4817
|
-
|
|
4941
|
+
);
|
|
4942
|
+
}
|
|
4818
4943
|
w.line();
|
|
4819
4944
|
}
|
|
4820
4945
|
};
|
|
4821
4946
|
|
|
4822
4947
|
// src/api/writer-generator/typescript/profile-validation.ts
|
|
4823
|
-
var collectRegularFieldValidation = (errors, warnings, name, field, resolveRef, canonicalUrlExpr) => {
|
|
4948
|
+
var collectRegularFieldValidation = (errors, warnings, name, field, resolveRef, canonicalUrlExpr, tsIndex) => {
|
|
4824
4949
|
if (field.excluded) {
|
|
4825
4950
|
errors.push(`...validateExcluded(res, profileName, ${JSON.stringify(name)})`);
|
|
4826
4951
|
return;
|
|
@@ -4842,14 +4967,29 @@ var collectRegularFieldValidation = (errors, warnings, name, field, resolveRef,
|
|
|
4842
4967
|
);
|
|
4843
4968
|
if (field.slicing?.slices) {
|
|
4844
4969
|
for (const [sliceName, slice] of Object.entries(field.slicing.slices)) {
|
|
4845
|
-
if (slice.min === void 0 && slice.max === void 0) continue;
|
|
4846
4970
|
const match = slice.match ?? {};
|
|
4847
4971
|
if (Object.keys(match).length === 0) continue;
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4972
|
+
if (slice.min !== void 0 || slice.max !== void 0) {
|
|
4973
|
+
const min = slice.min ?? 0;
|
|
4974
|
+
const max = slice.max ?? 0;
|
|
4975
|
+
errors.push(
|
|
4976
|
+
`...validateSliceCardinality(res, profileName, ${JSON.stringify(name)}, ${JSON.stringify(match)}, ${JSON.stringify(sliceName)}, ${min}, ${max})`
|
|
4977
|
+
);
|
|
4978
|
+
}
|
|
4979
|
+
const sliceRequiredFields = [];
|
|
4980
|
+
const matchKeys = new Set(Object.keys(match));
|
|
4981
|
+
for (const rf of slice.required ?? []) {
|
|
4982
|
+
if (!matchKeys.has(rf)) sliceRequiredFields.push(rf);
|
|
4983
|
+
}
|
|
4984
|
+
if (tsIndex && field.type && slice.elements) {
|
|
4985
|
+
const cc = tsIndex.constrainedChoice(field.type.package, field.type, slice.elements);
|
|
4986
|
+
if (cc) sliceRequiredFields.push(cc.variant);
|
|
4987
|
+
}
|
|
4988
|
+
if (sliceRequiredFields.length > 0) {
|
|
4989
|
+
errors.push(
|
|
4990
|
+
`...validateSliceFields(res, profileName, ${JSON.stringify(name)}, ${JSON.stringify(match)}, ${JSON.stringify(sliceName)}, ${JSON.stringify(sliceRequiredFields)})`
|
|
4991
|
+
);
|
|
4992
|
+
}
|
|
4853
4993
|
}
|
|
4854
4994
|
}
|
|
4855
4995
|
};
|
|
@@ -4881,7 +5021,8 @@ var generateValidateMethod = (w, tsIndex, flatProfile) => {
|
|
|
4881
5021
|
name,
|
|
4882
5022
|
field,
|
|
4883
5023
|
tsIndex.findLastSpecializationByIdentifier,
|
|
4884
|
-
canonicalUrlExpr
|
|
5024
|
+
canonicalUrlExpr,
|
|
5025
|
+
tsIndex
|
|
4885
5026
|
);
|
|
4886
5027
|
}
|
|
4887
5028
|
const emitArray = (label, exprs) => {
|
|
@@ -4913,24 +5054,31 @@ var collectChoiceAccessors = (flatProfile, promotedChoices) => {
|
|
|
4913
5054
|
}
|
|
4914
5055
|
return accessors;
|
|
4915
5056
|
};
|
|
4916
|
-
var tryPromoteChoice = (field, fields, params, promotedChoices) => {
|
|
5057
|
+
var tryPromoteChoice = (field, fields, params, promotedChoices, resolveRef, isFamilyType) => {
|
|
4917
5058
|
if (!isChoiceDeclarationField(field) || !field.required || field.choices.length !== 1) return;
|
|
4918
5059
|
const choiceName = field.choices[0];
|
|
4919
5060
|
if (!choiceName) return;
|
|
4920
5061
|
const choiceField = fields[choiceName];
|
|
4921
5062
|
if (!choiceField || !isChoiceInstanceField(choiceField)) return;
|
|
4922
|
-
const tsType =
|
|
5063
|
+
const tsType = fieldTsType(choiceField, resolveRef, isFamilyType);
|
|
4923
5064
|
params.push({ name: choiceName, tsType, typeId: choiceField.type });
|
|
4924
5065
|
promotedChoices.add(choiceName);
|
|
4925
5066
|
};
|
|
5067
|
+
var mkIsFamilyType = (tsIndex) => (ref) => {
|
|
5068
|
+
const schema = tsIndex.resolveType(ref);
|
|
5069
|
+
if (!schema || !("typeFamily" in schema)) return false;
|
|
5070
|
+
return (schema.typeFamily?.resources?.length ?? 0) > 0;
|
|
5071
|
+
};
|
|
4926
5072
|
var collectProfileFactoryInfo = (tsIndex, flatProfile) => {
|
|
4927
5073
|
const autoFields = [];
|
|
4928
5074
|
const sliceAutoFields = [];
|
|
4929
5075
|
const params = [];
|
|
4930
5076
|
const autoAccessors = [];
|
|
5077
|
+
const fixedFields = /* @__PURE__ */ new Set();
|
|
4931
5078
|
const fields = flatProfile.fields ?? {};
|
|
4932
5079
|
const promotedChoices = /* @__PURE__ */ new Set();
|
|
4933
5080
|
const resolveRef = tsIndex.findLastSpecializationByIdentifier;
|
|
5081
|
+
const isFamilyType = mkIsFamilyType(tsIndex);
|
|
4934
5082
|
if (isResourceIdentifier(flatProfile.base)) {
|
|
4935
5083
|
autoFields.push({ name: "resourceType", value: JSON.stringify(flatProfile.base.name) });
|
|
4936
5084
|
}
|
|
@@ -4938,14 +5086,15 @@ var collectProfileFactoryInfo = (tsIndex, flatProfile) => {
|
|
|
4938
5086
|
if (field.excluded) continue;
|
|
4939
5087
|
if (isChoiceInstanceField(field)) continue;
|
|
4940
5088
|
if (isChoiceDeclarationField(field)) {
|
|
4941
|
-
tryPromoteChoice(field, fields, params, promotedChoices);
|
|
5089
|
+
tryPromoteChoice(field, fields, params, promotedChoices, resolveRef, isFamilyType);
|
|
4942
5090
|
continue;
|
|
4943
5091
|
}
|
|
4944
5092
|
if (field.valueConstraint) {
|
|
4945
5093
|
const value = JSON.stringify(field.valueConstraint.value);
|
|
4946
5094
|
autoFields.push({ name, value: field.array ? `[${value}]` : value });
|
|
5095
|
+
fixedFields.add(name);
|
|
4947
5096
|
if (isNotChoiceDeclarationField(field) && field.type) {
|
|
4948
|
-
const tsType = fieldTsType(field, resolveRef);
|
|
5097
|
+
const tsType = fieldTsType(field, resolveRef, isFamilyType);
|
|
4949
5098
|
autoAccessors.push({ name, tsType, typeId: field.type });
|
|
4950
5099
|
}
|
|
4951
5100
|
continue;
|
|
@@ -4954,7 +5103,7 @@ var collectProfileFactoryInfo = (tsIndex, flatProfile) => {
|
|
|
4954
5103
|
const sliceNames = collectRequiredSliceNames(field);
|
|
4955
5104
|
if (sliceNames) {
|
|
4956
5105
|
if (field.type) {
|
|
4957
|
-
const tsType = fieldTsType(field, resolveRef);
|
|
5106
|
+
const tsType = fieldTsType(field, resolveRef, isFamilyType);
|
|
4958
5107
|
sliceAutoFields.push({
|
|
4959
5108
|
name,
|
|
4960
5109
|
tsType,
|
|
@@ -4967,20 +5116,27 @@ var collectProfileFactoryInfo = (tsIndex, flatProfile) => {
|
|
|
4967
5116
|
}
|
|
4968
5117
|
}
|
|
4969
5118
|
if (field.required) {
|
|
4970
|
-
const tsType = fieldTsType(field, resolveRef);
|
|
5119
|
+
const tsType = fieldTsType(field, resolveRef, isFamilyType);
|
|
4971
5120
|
params.push({ name, tsType, typeId: field.type });
|
|
4972
5121
|
}
|
|
4973
5122
|
}
|
|
4974
|
-
collectBaseRequiredParams(
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
5123
|
+
collectBaseRequiredParams(
|
|
5124
|
+
tsIndex,
|
|
5125
|
+
flatProfile,
|
|
5126
|
+
resolveRef,
|
|
5127
|
+
params,
|
|
5128
|
+
[
|
|
5129
|
+
...autoFields.map((f) => f.name),
|
|
5130
|
+
...sliceAutoFields.map((f) => f.name),
|
|
5131
|
+
...params.map((f) => f.name),
|
|
5132
|
+
...promotedChoices
|
|
5133
|
+
],
|
|
5134
|
+
isFamilyType
|
|
5135
|
+
);
|
|
4980
5136
|
const accessors = [...autoAccessors, ...collectChoiceAccessors(flatProfile, promotedChoices)];
|
|
4981
|
-
return { autoFields, sliceAutoFields, params, accessors };
|
|
5137
|
+
return { autoFields, sliceAutoFields, params, accessors, fixedFields };
|
|
4982
5138
|
};
|
|
4983
|
-
var collectBaseRequiredParams = (tsIndex, flatProfile, resolveRef, params, coveredNames) => {
|
|
5139
|
+
var collectBaseRequiredParams = (tsIndex, flatProfile, resolveRef, params, coveredNames, isFamilyType) => {
|
|
4984
5140
|
const covered = new Set(coveredNames);
|
|
4985
5141
|
const baseSchema = tsIndex.resolveType(flatProfile.base);
|
|
4986
5142
|
if (!baseSchema || !("fields" in baseSchema) || !baseSchema.fields) return;
|
|
@@ -4990,7 +5146,7 @@ var collectBaseRequiredParams = (tsIndex, flatProfile, resolveRef, params, cover
|
|
|
4990
5146
|
if (isChoiceInstanceField(field)) continue;
|
|
4991
5147
|
if (isChoiceDeclarationField(field)) continue;
|
|
4992
5148
|
if (isNotChoiceDeclarationField(field) && field.type) {
|
|
4993
|
-
const tsType = fieldTsType(field, resolveRef);
|
|
5149
|
+
const tsType = fieldTsType(field, resolveRef, isFamilyType);
|
|
4994
5150
|
params.push({ name, tsType, typeId: field.type });
|
|
4995
5151
|
}
|
|
4996
5152
|
}
|
|
@@ -5018,23 +5174,27 @@ var generateProfileHelpersImport = (w, tsIndex, flatProfile, sliceDefs, factoryI
|
|
|
5018
5174
|
const hasMeta = tsIndex.isWithMetaField(flatProfile);
|
|
5019
5175
|
const canonicalUrl = flatProfile.identifier.url;
|
|
5020
5176
|
const imports = [];
|
|
5021
|
-
if (!isPrimitiveIdentifier(flatProfile.base)) imports.push("buildResource");
|
|
5022
5177
|
if (flatProfile.base.name === "Extension" && !!canonicalUrl && collectSubExtensionSlices(flatProfile).length > 0)
|
|
5023
5178
|
imports.push("isRawExtensionInput");
|
|
5024
5179
|
if (canonicalUrl && hasMeta) imports.push("ensureProfile");
|
|
5025
5180
|
if (sliceDefs.length > 0 || factoryInfo.sliceAutoFields.length > 0)
|
|
5026
5181
|
imports.push("applySliceMatch", "matchesValue", "setArraySlice", "getArraySlice", "ensureSliceDefaults");
|
|
5182
|
+
const hasUnboundedSlice = sliceDefs.some((s) => s.array && (s.max === 0 || s.max === void 0));
|
|
5183
|
+
if (hasUnboundedSlice) imports.push("setArraySliceAll", "getArraySliceAll");
|
|
5027
5184
|
if (extensions.some((ext) => ext.path.split(".").some((s) => s !== "extension"))) imports.push("ensurePath");
|
|
5028
5185
|
if (extensions.some((ext) => ext.isComplex && ext.subExtensions)) imports.push("extractComplexExtension");
|
|
5029
|
-
if (sliceDefs.some((s) => !s.typeDiscriminator)) imports.push("stripMatchKeys");
|
|
5030
5186
|
if (sliceDefs.some((s) => s.constrainedChoice)) imports.push("wrapSliceChoice", "unwrapSliceChoice");
|
|
5031
|
-
if (extensions.some((ext) => ext.url))
|
|
5187
|
+
if (extensions.some((ext) => ext.url)) {
|
|
5188
|
+
imports.push("isExtension", "getExtensionValue", "pushExtension");
|
|
5189
|
+
if (extensions.some((ext) => ext.url && ext.max === "1")) imports.push("upsertExtension");
|
|
5190
|
+
}
|
|
5032
5191
|
if (Object.keys(flatProfile.fields ?? {}).length > 0)
|
|
5033
5192
|
imports.push(
|
|
5034
5193
|
"validateRequired",
|
|
5035
5194
|
"validateExcluded",
|
|
5036
5195
|
"validateFixedValue",
|
|
5037
5196
|
"validateSliceCardinality",
|
|
5197
|
+
"validateSliceFields",
|
|
5038
5198
|
"validateEnum",
|
|
5039
5199
|
"validateReference",
|
|
5040
5200
|
"validateChoiceRequired",
|
|
@@ -5109,7 +5269,17 @@ var generateProfileImports = (w, tsIndex, flatProfile) => {
|
|
|
5109
5269
|
var generateStaticSliceFields = (w, sliceDefs) => {
|
|
5110
5270
|
for (const sliceDef of sliceDefs) {
|
|
5111
5271
|
const staticName = `${tsSliceStaticName(sliceDef.sliceName)}SliceMatch`;
|
|
5112
|
-
|
|
5272
|
+
const json = JSON.stringify(sliceDef.match);
|
|
5273
|
+
const prefix = `private static readonly ${staticName}: Record<string, unknown> = `;
|
|
5274
|
+
if (prefix.length + json.length <= (w.opts.lineWidth ?? 120)) {
|
|
5275
|
+
w.lineSM(`${prefix}${json}`);
|
|
5276
|
+
} else {
|
|
5277
|
+
w.curlyBlock([prefix.trimEnd()], () => {
|
|
5278
|
+
for (const [key, value] of Object.entries(sliceDef.match)) {
|
|
5279
|
+
w.line(`${JSON.stringify(key)}: ${JSON.stringify(value)},`);
|
|
5280
|
+
}
|
|
5281
|
+
});
|
|
5282
|
+
}
|
|
5113
5283
|
}
|
|
5114
5284
|
if (sliceDefs.length > 0) w.line();
|
|
5115
5285
|
};
|
|
@@ -5147,6 +5317,28 @@ var generateFactoryMethods = (w, tsIndex, flatProfile, factoryInfo) => {
|
|
|
5147
5317
|
if (hasMeta) {
|
|
5148
5318
|
w.lineSM(`ensureProfile(resource, ${profileClassName}.canonicalUrl)`);
|
|
5149
5319
|
}
|
|
5320
|
+
if (flatProfile.base.name === "Extension" && flatProfile.identifier.url) {
|
|
5321
|
+
w.lineSM(`resource.url = ${profileClassName}.canonicalUrl`);
|
|
5322
|
+
}
|
|
5323
|
+
const applyAutoFields = factoryInfo.autoFields.filter((f) => f.name !== "resourceType");
|
|
5324
|
+
if (applyAutoFields.length > 0) {
|
|
5325
|
+
w.curlyBlock(["Object.assign(resource,"], () => {
|
|
5326
|
+
for (const f of applyAutoFields) {
|
|
5327
|
+
w.line(`${f.name}: ${f.value},`);
|
|
5328
|
+
}
|
|
5329
|
+
}, [")"]);
|
|
5330
|
+
}
|
|
5331
|
+
for (const f of factoryInfo.sliceAutoFields) {
|
|
5332
|
+
const matchRefs = f.sliceNames.map((s) => `${profileClassName}.${tsSliceStaticName(s)}SliceMatch`);
|
|
5333
|
+
w.line(`resource.${f.name} = ensureSliceDefaults(`);
|
|
5334
|
+
w.indentBlock(() => {
|
|
5335
|
+
w.line(`[...(resource.${f.name} ?? [])],`);
|
|
5336
|
+
for (const ref of matchRefs) {
|
|
5337
|
+
w.line(`${ref},`);
|
|
5338
|
+
}
|
|
5339
|
+
});
|
|
5340
|
+
w.lineSM(")");
|
|
5341
|
+
}
|
|
5150
5342
|
w.lineSM(`return new ${profileClassName}(resource)`);
|
|
5151
5343
|
});
|
|
5152
5344
|
w.line();
|
|
@@ -5209,7 +5401,7 @@ var generateFactoryMethods = (w, tsIndex, flatProfile, factoryInfo) => {
|
|
|
5209
5401
|
}
|
|
5210
5402
|
w.line();
|
|
5211
5403
|
const extensionVar = extSliceField ? "extensionWithDefaults" : "resolvedExtensions";
|
|
5212
|
-
w.curlyBlock([`const resource
|
|
5404
|
+
w.curlyBlock([`const resource: ${tsBaseResourceName} =`], () => {
|
|
5213
5405
|
for (const f of allFields) {
|
|
5214
5406
|
if (f.name === "extension") continue;
|
|
5215
5407
|
w.line(`${f.name}: ${f.value},`);
|
|
@@ -5218,7 +5410,7 @@ var generateFactoryMethods = (w, tsIndex, flatProfile, factoryInfo) => {
|
|
|
5218
5410
|
if (hasMeta) {
|
|
5219
5411
|
w.line(`meta: { profile: [${profileClassName}.canonicalUrl] },`);
|
|
5220
5412
|
}
|
|
5221
|
-
}
|
|
5413
|
+
});
|
|
5222
5414
|
w.lineSM("return resource");
|
|
5223
5415
|
});
|
|
5224
5416
|
w.line();
|
|
@@ -5245,22 +5437,21 @@ var generateFactoryMethods = (w, tsIndex, flatProfile, factoryInfo) => {
|
|
|
5245
5437
|
if (isPrimitiveIdentifier(flatProfile.base)) {
|
|
5246
5438
|
w.lineSM(`const resource = undefined as unknown as ${tsBaseResourceName}`);
|
|
5247
5439
|
} else {
|
|
5248
|
-
w.curlyBlock([`const resource
|
|
5440
|
+
w.curlyBlock([`const resource: ${tsBaseResourceName} =`], () => {
|
|
5249
5441
|
for (const f of allFields) {
|
|
5250
5442
|
w.line(`${f.name}: ${f.value},`);
|
|
5251
5443
|
}
|
|
5252
5444
|
if (hasMeta) {
|
|
5253
5445
|
w.line(`meta: { profile: [${profileClassName}.canonicalUrl] },`);
|
|
5254
5446
|
}
|
|
5255
|
-
}
|
|
5447
|
+
});
|
|
5256
5448
|
}
|
|
5257
5449
|
w.lineSM("return resource");
|
|
5258
5450
|
});
|
|
5259
5451
|
w.line();
|
|
5260
5452
|
w.curlyBlock(["static", "create", `(${paramSignature})`, `: ${profileClassName}`], () => {
|
|
5261
|
-
w.lineSM(
|
|
5262
|
-
|
|
5263
|
-
);
|
|
5453
|
+
w.lineSM(`const resource = ${profileClassName}.createResource(${hasParams ? "args" : ""})`);
|
|
5454
|
+
w.lineSM(`return ${profileClassName}.apply(resource)`);
|
|
5264
5455
|
});
|
|
5265
5456
|
}
|
|
5266
5457
|
w.line();
|
|
@@ -5291,11 +5482,13 @@ var generateFieldAccessors = (w, factoryInfo, extSliceMethodBaseNames) => {
|
|
|
5291
5482
|
w.lineSM(`return ${tsGet("this.resource", fieldAccess)} as ${a.tsType} | undefined`);
|
|
5292
5483
|
});
|
|
5293
5484
|
w.line();
|
|
5294
|
-
|
|
5295
|
-
w.
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5485
|
+
if (!factoryInfo.fixedFields.has(a.name)) {
|
|
5486
|
+
w.curlyBlock([`set${methodBaseName}`, `(value: ${a.tsType})`, ": this"], () => {
|
|
5487
|
+
w.lineSM(`Object.assign(this.resource, { ${fieldAccess}: value })`);
|
|
5488
|
+
w.lineSM("return this");
|
|
5489
|
+
});
|
|
5490
|
+
w.line();
|
|
5491
|
+
}
|
|
5299
5492
|
}
|
|
5300
5493
|
};
|
|
5301
5494
|
var generateInlineExtensionInputTypes = (w, tsIndex, flatProfile) => {
|
|
@@ -5318,11 +5511,23 @@ var generateInlineExtensionInputTypes = (w, tsIndex, flatProfile) => {
|
|
|
5318
5511
|
w.line();
|
|
5319
5512
|
}
|
|
5320
5513
|
};
|
|
5514
|
+
var valueToTypeLiteral = (value) => {
|
|
5515
|
+
if (value === null || value === void 0) return "undefined";
|
|
5516
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
5517
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
5518
|
+
if (Array.isArray(value)) return `[${value.map(valueToTypeLiteral).join(", ")}]`;
|
|
5519
|
+
if (typeof value === "object") {
|
|
5520
|
+
const entries = Object.entries(value).map(([k, v]) => `${k}: ${valueToTypeLiteral(v)}`).join("; ");
|
|
5521
|
+
return `{ ${entries} }`;
|
|
5522
|
+
}
|
|
5523
|
+
return "unknown";
|
|
5524
|
+
};
|
|
5321
5525
|
var generateSliceInputTypes = (w, flatProfile, sliceDefs) => {
|
|
5322
5526
|
if (sliceDefs.length === 0) return;
|
|
5323
5527
|
const tsProfileName = tsResourceName(flatProfile.identifier);
|
|
5324
5528
|
for (const sliceDef of sliceDefs) {
|
|
5325
|
-
const
|
|
5529
|
+
const inputTypeName = tsSliceFlatTypeName(tsProfileName, sliceDef.fieldName, sliceDef.sliceName);
|
|
5530
|
+
const flatTypeName = tsSliceFlatAllTypeName(tsProfileName, sliceDef.fieldName, sliceDef.sliceName);
|
|
5326
5531
|
const matchFields = sliceDef.typeDiscriminator ? [] : Object.keys(sliceDef.match);
|
|
5327
5532
|
const allExcluded = [.../* @__PURE__ */ new Set([...sliceDef.excluded, ...matchFields])];
|
|
5328
5533
|
if (sliceDef.constrainedChoice) {
|
|
@@ -5335,19 +5540,32 @@ var generateSliceInputTypes = (w, flatProfile, sliceDefs) => {
|
|
|
5335
5540
|
const excludedNames = allExcluded.map((name) => JSON.stringify(name));
|
|
5336
5541
|
const requiredNames = sliceDef.required.map((name) => JSON.stringify(name));
|
|
5337
5542
|
const baseType = sliceDef.typedBaseType;
|
|
5338
|
-
let
|
|
5543
|
+
let inputTypeExpr = baseType;
|
|
5339
5544
|
if (excludedNames.length > 0) {
|
|
5340
|
-
|
|
5545
|
+
inputTypeExpr = `Omit<${inputTypeExpr}, ${excludedNames.join(" | ")}>`;
|
|
5341
5546
|
}
|
|
5342
5547
|
if (requiredNames.length > 0) {
|
|
5343
|
-
|
|
5548
|
+
inputTypeExpr = `${inputTypeExpr} & Required<Pick<${baseType}, ${requiredNames.join(" | ")}>>`;
|
|
5344
5549
|
}
|
|
5345
5550
|
if (sliceDef.constrainedChoice) {
|
|
5346
|
-
|
|
5551
|
+
inputTypeExpr = `${inputTypeExpr} & ${tsTypeFromIdentifier(sliceDef.constrainedChoice.variantType)}`;
|
|
5552
|
+
}
|
|
5553
|
+
w.lineSM(`export type ${inputTypeName} = ${inputTypeExpr}`);
|
|
5554
|
+
const safeMatchEntries = matchFields.length > 0 && !sliceDef.constrainedChoice ? matchFields.filter((key) => {
|
|
5555
|
+
const v = sliceDef.match[key];
|
|
5556
|
+
return Array.isArray(v) || typeof v !== "object" || v === null;
|
|
5557
|
+
}).map((key) => ({ key, typeLiteral: valueToTypeLiteral(sliceDef.match[key]) })) : [];
|
|
5558
|
+
if (safeMatchEntries.length > 0) {
|
|
5559
|
+
w.curlyBlock([`export type ${flatTypeName} = ${inputTypeName} &`], () => {
|
|
5560
|
+
for (const entry of safeMatchEntries) {
|
|
5561
|
+
w.lineSM(`readonly ${entry.key}: ${entry.typeLiteral}`);
|
|
5562
|
+
}
|
|
5563
|
+
});
|
|
5564
|
+
} else {
|
|
5565
|
+
w.lineSM(`export type ${flatTypeName} = ${inputTypeName}`);
|
|
5347
5566
|
}
|
|
5348
|
-
w.
|
|
5567
|
+
w.line();
|
|
5349
5568
|
}
|
|
5350
|
-
w.line();
|
|
5351
5569
|
};
|
|
5352
5570
|
var generateRawType = (w, flatProfile, factoryInfo) => {
|
|
5353
5571
|
const hasParams = factoryInfo.params.length > 0 || factoryInfo.sliceAutoFields.length > 0;
|
|
@@ -5585,7 +5803,7 @@ var TypeScript = class extends Writer {
|
|
|
5585
5803
|
const typeExpr = isArray ? "(Element | null)[]" : "Element";
|
|
5586
5804
|
this.lineSM(`${extFieldName}?: ${typeExpr}`);
|
|
5587
5805
|
}
|
|
5588
|
-
generateType(tsIndex, schema) {
|
|
5806
|
+
generateType(tsIndex, schema, isFamilyType) {
|
|
5589
5807
|
let name;
|
|
5590
5808
|
const genericTypes = ["Reference", "Coding", "CodeableConcept"];
|
|
5591
5809
|
if (genericTypes.includes(schema.identifier.name)) {
|
|
@@ -5639,7 +5857,14 @@ var TypeScript = class extends Writer {
|
|
|
5639
5857
|
if (!field.type) continue;
|
|
5640
5858
|
this.debugComment(fieldName, ":", field);
|
|
5641
5859
|
const tsName = tsFieldName(fieldName);
|
|
5642
|
-
const tsType = resolveFieldTsType(
|
|
5860
|
+
const tsType = resolveFieldTsType(
|
|
5861
|
+
schema.identifier.name,
|
|
5862
|
+
tsName,
|
|
5863
|
+
field,
|
|
5864
|
+
void 0,
|
|
5865
|
+
genericFieldMap,
|
|
5866
|
+
isFamilyType
|
|
5867
|
+
);
|
|
5643
5868
|
const optionalSymbol = field.required ? "" : "?";
|
|
5644
5869
|
const arraySymbol = field.array ? "[]" : "";
|
|
5645
5870
|
this.lineSM(`${tsName}${optionalSymbol}: ${tsType}${arraySymbol}`);
|
|
@@ -5669,10 +5894,10 @@ var TypeScript = class extends Writer {
|
|
|
5669
5894
|
);
|
|
5670
5895
|
});
|
|
5671
5896
|
}
|
|
5672
|
-
generateNestedTypes(tsIndex, schema) {
|
|
5897
|
+
generateNestedTypes(tsIndex, schema, isFamilyType) {
|
|
5673
5898
|
if (schema.nested) {
|
|
5674
5899
|
for (const subtype of schema.nested) {
|
|
5675
|
-
this.generateType(tsIndex, subtype);
|
|
5900
|
+
this.generateType(tsIndex, subtype, isFamilyType);
|
|
5676
5901
|
this.line();
|
|
5677
5902
|
}
|
|
5678
5903
|
}
|
|
@@ -5688,17 +5913,18 @@ var TypeScript = class extends Writer {
|
|
|
5688
5913
|
});
|
|
5689
5914
|
});
|
|
5690
5915
|
} else if (isSpecializationTypeSchema(schema)) {
|
|
5916
|
+
const isFamilyType = mkIsFamilyType(tsIndex);
|
|
5691
5917
|
this.cat(`${tsModuleFileName(schema.identifier)}`, () => {
|
|
5692
5918
|
this.generateDisclaimer();
|
|
5693
5919
|
this.generateDependenciesImports(tsIndex, schema);
|
|
5694
5920
|
this.generateComplexTypeReexports(schema);
|
|
5695
|
-
this.generateNestedTypes(tsIndex, schema);
|
|
5921
|
+
this.generateNestedTypes(tsIndex, schema, isFamilyType);
|
|
5696
5922
|
this.comment(
|
|
5697
5923
|
"CanonicalURL:",
|
|
5698
5924
|
schema.identifier.url,
|
|
5699
5925
|
`(pkg: ${packageMetaToFhir(packageMeta(schema))})`
|
|
5700
5926
|
);
|
|
5701
|
-
this.generateType(tsIndex, schema);
|
|
5927
|
+
this.generateType(tsIndex, schema, isFamilyType);
|
|
5702
5928
|
this.generateResourceTypePredicate(schema);
|
|
5703
5929
|
});
|
|
5704
5930
|
} else {
|
|
@@ -5881,7 +6107,8 @@ var APIBuilder = class {
|
|
|
5881
6107
|
const defaultPyOpts = {
|
|
5882
6108
|
...defaultWriterOpts,
|
|
5883
6109
|
rootPackageName: "fhir_types",
|
|
5884
|
-
fieldFormat: "snake_case"
|
|
6110
|
+
fieldFormat: "snake_case",
|
|
6111
|
+
primitiveTypeExtension: false
|
|
5885
6112
|
};
|
|
5886
6113
|
const opts = {
|
|
5887
6114
|
...defaultPyOpts,
|