@atomic-ehr/codegen 0.0.16 → 0.0.17-canary.20260727063227.c50c42b
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/LICENSE +1 -1
- package/README.md +67 -1
- package/assets/api/writer-generator/python/fhirpy_base_model.py +5 -1
- package/assets/api/writer-generator/python/fhirpy_base_model_camel_case.py +5 -1
- package/assets/api/writer-generator/python/profile_helpers.py +55 -19
- package/assets/api/writer-generator/typescript/profile-helpers.ts +11 -0
- package/dist/cli/index.js +8 -8
- package/dist/index.d.ts +14 -2
- package/dist/index.js +446 -208
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -383,6 +383,9 @@ var isPrimitiveIdentifier = (id) => {
|
|
|
383
383
|
var isNestedIdentifier = (id) => {
|
|
384
384
|
return id?.kind === "nested";
|
|
385
385
|
};
|
|
386
|
+
var isProfileIdentifier = (id) => {
|
|
387
|
+
return id?.kind === "profile";
|
|
388
|
+
};
|
|
386
389
|
var isSnapshotProfileIdentifier = (id) => {
|
|
387
390
|
return id?.kind === "profile-snapshot";
|
|
388
391
|
};
|
|
@@ -426,6 +429,7 @@ var isValueSetTypeSchema = (schema) => {
|
|
|
426
429
|
var isSnapshotProfileTypeSchema = (s) => {
|
|
427
430
|
return s?.identifier.kind === "profile-snapshot";
|
|
428
431
|
};
|
|
432
|
+
var isTypeDiscriminated = (slicing) => slicing?.discriminator?.some((d) => d.type === "type") ?? false;
|
|
429
433
|
var extractExtensionDeps = (ext) => [
|
|
430
434
|
...ext.valueFieldTypes ?? [],
|
|
431
435
|
...ext.profile ? [ext.profile] : [],
|
|
@@ -892,6 +896,18 @@ var pyTypeFromIdentifier = (id) => {
|
|
|
892
896
|
if (prim !== void 0) return prim;
|
|
893
897
|
return deriveResourceName(id);
|
|
894
898
|
};
|
|
899
|
+
var pyReferenceTypeParam = (field, tsIndex) => {
|
|
900
|
+
if (!field.reference || field.reference.resource.length === 0) return void 0;
|
|
901
|
+
const isFamilyType = (ref) => {
|
|
902
|
+
const schema = tsIndex.resolveType(ref);
|
|
903
|
+
if (!schema || !("typeFamily" in schema)) return false;
|
|
904
|
+
return (schema.typeFamily?.resources?.length ?? 0) > 0;
|
|
905
|
+
};
|
|
906
|
+
const resolved = field.reference.resource.map((ref) => tsIndex.findLastSpecializationByIdentifier(ref));
|
|
907
|
+
if (resolved.some(isFamilyType)) return void 0;
|
|
908
|
+
const names = [...new Set(resolved.map((ref) => ref.name))];
|
|
909
|
+
return `Literal[${names.map((n) => JSON.stringify(n)).join(", ")}]`;
|
|
910
|
+
};
|
|
895
911
|
var groupByPackages = (typeSchemas) => {
|
|
896
912
|
const grouped = {};
|
|
897
913
|
for (const ts of typeSchemas) {
|
|
@@ -1083,6 +1099,54 @@ var populateGeneric = (schemas, resolveType) => {
|
|
|
1083
1099
|
schema.dependencies = concatIdentifiers(schema.dependencies, constraints) ?? schema.dependencies;
|
|
1084
1100
|
}
|
|
1085
1101
|
};
|
|
1102
|
+
var choiceInstances = (fields, declName) => Object.entries(fields).filter(
|
|
1103
|
+
(e) => isChoiceInstanceField(e[1]) && e[1].choiceOf === declName
|
|
1104
|
+
);
|
|
1105
|
+
var choiceUniverse = (fields, baseFields, declName, declField) => {
|
|
1106
|
+
const baseDecl = baseFields[declName];
|
|
1107
|
+
const baseChoices = isChoiceDeclarationField(baseDecl) ? baseDecl.choices : [];
|
|
1108
|
+
return [
|
|
1109
|
+
.../* @__PURE__ */ new Set([...baseChoices, ...declField.choices, ...choiceInstances(fields, declName).map(([name]) => name)])
|
|
1110
|
+
];
|
|
1111
|
+
};
|
|
1112
|
+
var declaredChoiceVariants = (fields, declName) => {
|
|
1113
|
+
const declaration = fields[declName];
|
|
1114
|
+
const fromDeclaration = isChoiceDeclarationField(declaration) && !declaration.excluded ? declaration.choices : [];
|
|
1115
|
+
const fromInstances = choiceInstances(fields, declName).filter(([, field]) => !field.excluded).map(([name]) => name);
|
|
1116
|
+
return [.../* @__PURE__ */ new Set([...fromDeclaration, ...fromInstances])];
|
|
1117
|
+
};
|
|
1118
|
+
var resolvePermittedChoiceVariants = (universe, baseDeclaration, constraintSchemas, declName, logger) => {
|
|
1119
|
+
let permitted = new Set(isChoiceDeclarationField(baseDeclaration) ? baseDeclaration.choices : universe);
|
|
1120
|
+
for (const schema of constraintSchemas.slice().reverse()) {
|
|
1121
|
+
const fields = schema.fields;
|
|
1122
|
+
if (!fields) continue;
|
|
1123
|
+
const reintroduced = declaredChoiceVariants(fields, declName).filter((name) => !permitted.has(name));
|
|
1124
|
+
if (reintroduced.length > 0)
|
|
1125
|
+
logger?.dryWarn(
|
|
1126
|
+
"#nonMonotonicChoice",
|
|
1127
|
+
`Profile '${schema.identifier.name}' declares choice variant(s) ${reintroduced.join(", ")} of '${declName}' that an ancestor prohibits; they stay prohibited`
|
|
1128
|
+
);
|
|
1129
|
+
permitted = applyChoiceConstraints(permitted, fields, declName);
|
|
1130
|
+
}
|
|
1131
|
+
return permitted;
|
|
1132
|
+
};
|
|
1133
|
+
var applyChoiceConstraints = (permitted, fields, declName) => {
|
|
1134
|
+
const result = new Set(permitted);
|
|
1135
|
+
const instances = choiceInstances(fields, declName);
|
|
1136
|
+
for (const [name, field] of instances) {
|
|
1137
|
+
if (field.excluded) result.delete(name);
|
|
1138
|
+
}
|
|
1139
|
+
const declaration = fields[declName];
|
|
1140
|
+
if (isChoiceDeclarationField(declaration)) {
|
|
1141
|
+
if (declaration.excluded) return /* @__PURE__ */ new Set();
|
|
1142
|
+
const declared2 = new Set(declaration.choices);
|
|
1143
|
+
return new Set([...result].filter((name) => declared2.has(name)));
|
|
1144
|
+
}
|
|
1145
|
+
const declared = instances.filter(([, field]) => !field.excluded).map(([name]) => name);
|
|
1146
|
+
if (declared.length === 0) return result;
|
|
1147
|
+
const declaredSet = new Set(declared);
|
|
1148
|
+
return new Set([...result].filter((name) => declaredSet.has(name)));
|
|
1149
|
+
};
|
|
1086
1150
|
var mkTypeSchemaIndex = (schemas, {
|
|
1087
1151
|
register,
|
|
1088
1152
|
logger,
|
|
@@ -1196,28 +1260,29 @@ var mkTypeSchemaIndex = (schemas, {
|
|
|
1196
1260
|
if (isNestedTypeSchema(resolved)) return findLastSpecializationByIdentifier(resolved.base);
|
|
1197
1261
|
return findLastSpecialization(resolved).identifier;
|
|
1198
1262
|
};
|
|
1199
|
-
const narrowMergedChoiceDeclarations = (mergedFields, constraintSchemas) => {
|
|
1263
|
+
const narrowMergedChoiceDeclarations = (mergedFields, constraintSchemas, baseFields = {}) => {
|
|
1200
1264
|
const result = { ...mergedFields };
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
const sFields = cSchema.fields;
|
|
1205
|
-
if (!sFields) continue;
|
|
1206
|
-
if (sFields[declName] && isChoiceDeclarationField(sFields[declName])) continue;
|
|
1207
|
-
const instancesInSchema = Object.entries(sFields).filter(([_, f]) => isChoiceInstanceField(f) && f.choiceOf === declName).map(([name]) => name);
|
|
1208
|
-
if (instancesInSchema.length === 0) continue;
|
|
1209
|
-
const allowed = new Set(instancesInSchema);
|
|
1210
|
-
result[declName] = { ...declField, choices: declField.choices.filter((c) => allowed.has(c)) };
|
|
1211
|
-
break;
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
for (const [declName, declField] of Object.entries(result)) {
|
|
1265
|
+
const declNames = /* @__PURE__ */ new Set([...Object.keys(result), ...Object.keys(baseFields)]);
|
|
1266
|
+
for (const declName of declNames) {
|
|
1267
|
+
const declField = result[declName] ?? baseFields[declName];
|
|
1215
1268
|
if (!isChoiceDeclarationField(declField)) continue;
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1269
|
+
const restated = result[declName] !== void 0;
|
|
1270
|
+
if (!restated && choiceInstances(result, declName).length === 0) continue;
|
|
1271
|
+
const universe = choiceUniverse(result, baseFields, declName, declField);
|
|
1272
|
+
const permitted = resolvePermittedChoiceVariants(
|
|
1273
|
+
universe,
|
|
1274
|
+
baseFields[declName],
|
|
1275
|
+
constraintSchemas,
|
|
1276
|
+
declName,
|
|
1277
|
+
logger
|
|
1278
|
+
);
|
|
1279
|
+
const prohibited = universe.filter((name) => !permitted.has(name));
|
|
1280
|
+
if (!restated && prohibited.length === 0) continue;
|
|
1281
|
+
result[declName] = {
|
|
1282
|
+
...declField,
|
|
1283
|
+
choices: universe.filter((name) => permitted.has(name)),
|
|
1284
|
+
...prohibited.length > 0 ? { prohibited } : {}
|
|
1285
|
+
};
|
|
1221
1286
|
}
|
|
1222
1287
|
return result;
|
|
1223
1288
|
};
|
|
@@ -1228,8 +1293,10 @@ var mkTypeSchemaIndex = (schemas, {
|
|
|
1228
1293
|
if (!nonConstraintSchema)
|
|
1229
1294
|
throw new Error(`No non-constraint schema found in hierarchy for ${schema.identifier.name}`);
|
|
1230
1295
|
const mergedFields = {};
|
|
1296
|
+
const mergedSlicing = {};
|
|
1231
1297
|
for (const anySchema of constraintSchemas.slice().reverse()) {
|
|
1232
1298
|
const schema2 = anySchema;
|
|
1299
|
+
if (schema2.slicing) Object.assign(mergedSlicing, schema2.slicing);
|
|
1233
1300
|
if (!schema2.fields) continue;
|
|
1234
1301
|
for (const [fieldName, fieldConstraints] of Object.entries(schema2.fields)) {
|
|
1235
1302
|
const merged = mergedFields[fieldName] ? { ...mergedFields[fieldName], ...fieldConstraints } : { ...fieldConstraints };
|
|
@@ -1239,7 +1306,11 @@ var mkTypeSchemaIndex = (schemas, {
|
|
|
1239
1306
|
mergedFields[fieldName] = merged;
|
|
1240
1307
|
}
|
|
1241
1308
|
}
|
|
1242
|
-
const narrowedFields = narrowMergedChoiceDeclarations(
|
|
1309
|
+
const narrowedFields = narrowMergedChoiceDeclarations(
|
|
1310
|
+
mergedFields,
|
|
1311
|
+
constraintSchemas,
|
|
1312
|
+
nonConstraintSchema.fields
|
|
1313
|
+
);
|
|
1243
1314
|
const dependencies = Object.values(
|
|
1244
1315
|
Object.fromEntries(
|
|
1245
1316
|
constraintSchemas.flatMap((s) => s.dependencies ?? []).map((dep) => [dep.url, dep])
|
|
@@ -1256,6 +1327,7 @@ var mkTypeSchemaIndex = (schemas, {
|
|
|
1256
1327
|
...schema,
|
|
1257
1328
|
base: nonConstraintSchema.identifier,
|
|
1258
1329
|
fields: narrowedFields,
|
|
1330
|
+
slicing: Object.keys(mergedSlicing).length > 0 ? mergedSlicing : void 0,
|
|
1259
1331
|
dependencies,
|
|
1260
1332
|
extensions: mergedExtensions.length > 0 ? mergedExtensions : void 0
|
|
1261
1333
|
};
|
|
@@ -1281,6 +1353,7 @@ var mkTypeSchemaIndex = (schemas, {
|
|
|
1281
1353
|
base: flat.base,
|
|
1282
1354
|
description: flat.description,
|
|
1283
1355
|
fields: flatFields,
|
|
1356
|
+
slicing: flat.slicing,
|
|
1284
1357
|
inheritedRequiredFields: inheritedRequiredFields.length > 0 ? inheritedRequiredFields : void 0,
|
|
1285
1358
|
extensions: flat.extensions,
|
|
1286
1359
|
dependencies: flat.dependencies,
|
|
@@ -1459,7 +1532,16 @@ var generateExtensionMethods = (w, tsIndex, flatProfile, className, extensionBas
|
|
|
1459
1532
|
const valueField = pyValueFieldName(valueType, w.nameFormatFunction);
|
|
1460
1533
|
const pyType = pyTypeFromIdentifier(valueType);
|
|
1461
1534
|
generateSingleValueExtensionGetter(w, ext, baseName, targetPath, valueField, pyType, extProfileInfo);
|
|
1462
|
-
generateSingleValueExtensionSetter(
|
|
1535
|
+
generateSingleValueExtensionSetter(
|
|
1536
|
+
w,
|
|
1537
|
+
ext,
|
|
1538
|
+
className,
|
|
1539
|
+
baseName,
|
|
1540
|
+
targetPath,
|
|
1541
|
+
valueField,
|
|
1542
|
+
pyType,
|
|
1543
|
+
extProfileInfo
|
|
1544
|
+
);
|
|
1463
1545
|
} else {
|
|
1464
1546
|
generateGenericExtensionGetter(w, ext, baseName, targetPath, extProfileInfo);
|
|
1465
1547
|
generateGenericExtensionSetter(w, ext, className, baseName, targetPath, extProfileInfo);
|
|
@@ -1566,6 +1648,7 @@ var generateExtensionSetter = (w, ext, className, baseName, flatParamType, targe
|
|
|
1566
1648
|
};
|
|
1567
1649
|
var generateComplexExtensionSetter = (w, ext, className, baseName, targetPath, extProfileInfo) => {
|
|
1568
1650
|
generateExtensionSetter(w, ext, className, baseName, "dict[str, Any]", targetPath, extProfileInfo, () => {
|
|
1651
|
+
w.line("assert is_record(value)");
|
|
1569
1652
|
w.line("sub_extensions = []");
|
|
1570
1653
|
for (const sub of ext.subExtensions ?? []) {
|
|
1571
1654
|
const valueField = sub.valueFieldType ? pyValueFieldName(sub.valueFieldType, w.nameFormatFunction) : "value";
|
|
@@ -1594,8 +1677,9 @@ var generateSingleValueExtensionGetter = (w, ext, baseName, targetPath, valueFie
|
|
|
1594
1677
|
w.line(`return cast('${pyType} | None', get_extension_value(ext, ${JSON.stringify(valueField)}))`);
|
|
1595
1678
|
});
|
|
1596
1679
|
};
|
|
1597
|
-
var generateSingleValueExtensionSetter = (w, ext, className, baseName, targetPath, valueField, extProfileInfo) => {
|
|
1598
|
-
generateExtensionSetter(w, ext, className, baseName,
|
|
1680
|
+
var generateSingleValueExtensionSetter = (w, ext, className, baseName, targetPath, valueField, pyType, extProfileInfo) => {
|
|
1681
|
+
generateExtensionSetter(w, ext, className, baseName, pyType, targetPath, extProfileInfo, () => {
|
|
1682
|
+
w.line("assert not isinstance(value, Extension)");
|
|
1599
1683
|
emitExtPush(w, targetPath, `Extension(url=${JSON.stringify(ext.url)}, ${valueField}=value)`);
|
|
1600
1684
|
});
|
|
1601
1685
|
};
|
|
@@ -1608,15 +1692,16 @@ var generateGenericExtensionGetter = (w, ext, baseName, targetPath, extProfileIn
|
|
|
1608
1692
|
};
|
|
1609
1693
|
var generateGenericExtensionSetter = (w, ext, className, baseName, targetPath, extProfileInfo) => {
|
|
1610
1694
|
generateExtensionSetter(w, ext, className, baseName, "dict[str, Any]", targetPath, extProfileInfo, () => {
|
|
1695
|
+
w.line("assert is_record(value)");
|
|
1611
1696
|
emitExtPush(w, targetPath, `{"url": ${JSON.stringify(ext.url)}, **value}`);
|
|
1612
1697
|
});
|
|
1613
1698
|
};
|
|
1614
1699
|
|
|
1615
1700
|
// src/api/writer-generator/python/profile-slices.ts
|
|
1616
|
-
var collectRequiredSliceNames = (field) => {
|
|
1617
|
-
if (!field.array || !
|
|
1618
|
-
if (
|
|
1619
|
-
const names = Object.entries(
|
|
1701
|
+
var collectRequiredSliceNames = (field, fieldSlicing) => {
|
|
1702
|
+
if (!field.array || !fieldSlicing?.slices) return void 0;
|
|
1703
|
+
if (isTypeDiscriminated(fieldSlicing)) return void 0;
|
|
1704
|
+
const names = Object.entries(fieldSlicing.slices).filter(([_, s]) => s.min !== void 0 && s.min >= 1 && s.match && Object.keys(s.match).length > 0).map(([name]) => name);
|
|
1620
1705
|
return names.length > 0 ? names : void 0;
|
|
1621
1706
|
};
|
|
1622
1707
|
var generateStaticSliceFields = (w, sliceDefs) => {
|
|
@@ -1648,8 +1733,8 @@ var normalizeMatchForPython = (tsIndex, match, schema) => {
|
|
|
1648
1733
|
}
|
|
1649
1734
|
return result;
|
|
1650
1735
|
};
|
|
1651
|
-
var extractTypeDiscriminatorResource = (
|
|
1652
|
-
if (!
|
|
1736
|
+
var extractTypeDiscriminatorResource = (isTypeDiscriminated2, rawMatch) => {
|
|
1737
|
+
if (!isTypeDiscriminated2 || !rawMatch) return void 0;
|
|
1653
1738
|
for (const val of Object.values(rawMatch)) {
|
|
1654
1739
|
if (val !== null && typeof val === "object" && !Array.isArray(val)) {
|
|
1655
1740
|
const rt = val.resourceType;
|
|
@@ -1660,8 +1745,9 @@ var extractTypeDiscriminatorResource = (isTypeDiscriminated, rawMatch) => {
|
|
|
1660
1745
|
};
|
|
1661
1746
|
var collectSliceDefs = (tsIndex, flatProfile) => {
|
|
1662
1747
|
const pkgName = flatProfile.identifier.package;
|
|
1663
|
-
return Object.entries(flatProfile.
|
|
1664
|
-
|
|
1748
|
+
return Object.entries(flatProfile.slicing ?? {}).flatMap(([fieldName, fieldSlicing]) => {
|
|
1749
|
+
const field = flatProfile.fields[fieldName];
|
|
1750
|
+
if (!isNotChoiceDeclarationField(field) || !fieldSlicing.slices || !field.type) return [];
|
|
1665
1751
|
const choiceBaseNames = /* @__PURE__ */ new Set();
|
|
1666
1752
|
const baseSchema = tsIndex.resolveType(field.type);
|
|
1667
1753
|
if (baseSchema && "fields" in baseSchema && baseSchema.fields) {
|
|
@@ -1669,16 +1755,16 @@ var collectSliceDefs = (tsIndex, flatProfile) => {
|
|
|
1669
1755
|
if (isChoiceDeclarationField(f)) choiceBaseNames.add(n);
|
|
1670
1756
|
}
|
|
1671
1757
|
}
|
|
1672
|
-
return Object.entries(
|
|
1758
|
+
return Object.entries(fieldSlicing.slices).filter(([_, slice]) => Object.keys(slice.match ?? {}).length > 0).map(([sliceName, slice]) => {
|
|
1673
1759
|
const matchFields = Object.keys(slice.match ?? {});
|
|
1674
1760
|
const required = (slice.required ?? []).filter(
|
|
1675
1761
|
(name) => !matchFields.includes(name) && !choiceBaseNames.has(name)
|
|
1676
1762
|
);
|
|
1677
1763
|
const cc = slice.elements ? tsIndex.constrainedChoice(pkgName, field.type, slice.elements) : void 0;
|
|
1678
1764
|
const constrainedChoice = cc && !isPrimitiveIdentifier(cc.variantType) ? cc : void 0;
|
|
1679
|
-
const
|
|
1765
|
+
const typeDiscriminated = isTypeDiscriminated(fieldSlicing);
|
|
1680
1766
|
const typeDiscriminatorResource = extractTypeDiscriminatorResource(
|
|
1681
|
-
|
|
1767
|
+
typeDiscriminated,
|
|
1682
1768
|
slice.match
|
|
1683
1769
|
);
|
|
1684
1770
|
return {
|
|
@@ -1691,7 +1777,7 @@ var collectSliceDefs = (tsIndex, flatProfile) => {
|
|
|
1691
1777
|
constrainedChoice,
|
|
1692
1778
|
elementTypeName: field.type && !isPrimitiveIdentifier(field.type) ? pyTypeFromIdentifier(field.type) : void 0,
|
|
1693
1779
|
elementTypeId: field.type && !isPrimitiveIdentifier(field.type) ? field.type : void 0,
|
|
1694
|
-
isTypeDiscriminated,
|
|
1780
|
+
isTypeDiscriminated: typeDiscriminated,
|
|
1695
1781
|
typeDiscriminatorResource,
|
|
1696
1782
|
nameCandidates: slice.nameCandidates
|
|
1697
1783
|
};
|
|
@@ -1808,15 +1894,17 @@ var generateSliceSetters = (w, className, sliceDefs, sliceBaseNames) => {
|
|
|
1808
1894
|
} else {
|
|
1809
1895
|
w.line(`merged = apply_slice_match(${inputExpr}, match)`);
|
|
1810
1896
|
}
|
|
1897
|
+
let elementExpr = "merged";
|
|
1811
1898
|
if (sliceDef.elementTypeName) {
|
|
1812
|
-
w.line(`
|
|
1899
|
+
w.line(`element = ${sliceDef.elementTypeName}(**merged)`);
|
|
1900
|
+
elementExpr = "element";
|
|
1813
1901
|
}
|
|
1814
1902
|
if (sliceDef.array) {
|
|
1815
1903
|
w.line(`items = getattr(self._resource, ${JSON.stringify(fieldName)}, None) or []`);
|
|
1816
|
-
w.line(
|
|
1904
|
+
w.line(`set_array_slice(items, match, ${elementExpr})`);
|
|
1817
1905
|
w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, items)`);
|
|
1818
1906
|
} else {
|
|
1819
|
-
w.line(`setattr(self._resource, ${JSON.stringify(fieldName)},
|
|
1907
|
+
w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, ${elementExpr})`);
|
|
1820
1908
|
}
|
|
1821
1909
|
w.line("return self");
|
|
1822
1910
|
});
|
|
@@ -1826,25 +1914,46 @@ var generateSliceSetters = (w, className, sliceDefs, sliceBaseNames) => {
|
|
|
1826
1914
|
};
|
|
1827
1915
|
|
|
1828
1916
|
// src/api/writer-generator/python/profile-factory.ts
|
|
1829
|
-
var fieldPyType = (field, resolveRef) => {
|
|
1917
|
+
var fieldPyType = (field, resolveRef, tsIndex) => {
|
|
1830
1918
|
const resolved = resolveRef ? resolveRef(field.type) : field.type;
|
|
1831
|
-
|
|
1919
|
+
let base = pyTypeFromIdentifier(resolved);
|
|
1832
1920
|
if (base === "str" && field.enum && !field.enum.isOpen && field.enum.values.length > 0) {
|
|
1833
1921
|
const literal = `Literal[${field.enum.values.map((v) => JSON.stringify(v)).join(", ")}]`;
|
|
1834
1922
|
return field.array ? `list[${literal}]` : literal;
|
|
1835
1923
|
}
|
|
1924
|
+
if (base === "Reference" && tsIndex) {
|
|
1925
|
+
const typeParam = pyReferenceTypeParam(field, tsIndex);
|
|
1926
|
+
if (typeParam) base = `Reference[${typeParam}]`;
|
|
1927
|
+
}
|
|
1836
1928
|
return field.array ? `list[${base}]` : base;
|
|
1837
1929
|
};
|
|
1838
|
-
var
|
|
1930
|
+
var pyReferenceComment = (field) => {
|
|
1931
|
+
const urls = (field.reference?.profiles ?? []).map((profile) => profile.url);
|
|
1932
|
+
return urls.length > 0 ? ` # ${urls.join(", ")}` : void 0;
|
|
1933
|
+
};
|
|
1934
|
+
var tryPromoteChoice = (field, fields, params, promotedChoices, tsIndex) => {
|
|
1839
1935
|
if (!isChoiceDeclarationField(field) || !field.required || field.choices.length !== 1) return;
|
|
1840
1936
|
const choiceName = field.choices[0];
|
|
1841
1937
|
if (!choiceName) return;
|
|
1842
1938
|
const choiceField = fields[choiceName];
|
|
1843
1939
|
if (!choiceField || !isChoiceInstanceField(choiceField)) return;
|
|
1844
|
-
const pyType =
|
|
1845
|
-
params.push({
|
|
1940
|
+
const pyType = pyChoiceInstanceType(choiceField, tsIndex);
|
|
1941
|
+
params.push({
|
|
1942
|
+
name: choiceName,
|
|
1943
|
+
pyType,
|
|
1944
|
+
typeId: choiceField.type,
|
|
1945
|
+
refComment: pyReferenceComment(choiceField)
|
|
1946
|
+
});
|
|
1846
1947
|
promotedChoices.add(choiceName);
|
|
1847
1948
|
};
|
|
1949
|
+
var pyChoiceInstanceType = (field, tsIndex) => {
|
|
1950
|
+
let base = pyTypeFromIdentifier(field.type);
|
|
1951
|
+
if (base === "Reference") {
|
|
1952
|
+
const typeParam = pyReferenceTypeParam(field, tsIndex);
|
|
1953
|
+
if (typeParam) base = `Reference[${typeParam}]`;
|
|
1954
|
+
}
|
|
1955
|
+
return base + (field.array ? "[]" : "");
|
|
1956
|
+
};
|
|
1848
1957
|
var collectBaseRequiredParams = (tsIndex, flatProfile, resolveRef, params, coveredNames) => {
|
|
1849
1958
|
const covered = new Set(coveredNames);
|
|
1850
1959
|
const baseSchema = tsIndex.resolveType(flatProfile.base);
|
|
@@ -1855,8 +1964,8 @@ var collectBaseRequiredParams = (tsIndex, flatProfile, resolveRef, params, cover
|
|
|
1855
1964
|
if (isChoiceInstanceField(field)) continue;
|
|
1856
1965
|
if (isChoiceDeclarationField(field)) continue;
|
|
1857
1966
|
if (isNotChoiceDeclarationField(field) && field.type) {
|
|
1858
|
-
const pyType = fieldPyType(field, resolveRef);
|
|
1859
|
-
params.push({ name, pyType, typeId: field.type });
|
|
1967
|
+
const pyType = fieldPyType(field, resolveRef, tsIndex);
|
|
1968
|
+
params.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field) });
|
|
1860
1969
|
}
|
|
1861
1970
|
}
|
|
1862
1971
|
};
|
|
@@ -1885,32 +1994,32 @@ var collectProfileFactoryInfo = (tsIndex, flatProfile) => {
|
|
|
1885
1994
|
continue;
|
|
1886
1995
|
}
|
|
1887
1996
|
if (isChoiceDeclarationField(field)) {
|
|
1888
|
-
tryPromoteChoice(field, fields, params, promotedChoices);
|
|
1997
|
+
tryPromoteChoice(field, fields, params, promotedChoices, tsIndex);
|
|
1889
1998
|
continue;
|
|
1890
1999
|
}
|
|
1891
2000
|
if (field.valueConstraint) {
|
|
1892
2001
|
const value = JSON.stringify(field.valueConstraint.value);
|
|
1893
2002
|
autoFields.push({ name, value: field.array ? `[${value}]` : value });
|
|
1894
2003
|
if (isNotChoiceDeclarationField(field) && field.type) {
|
|
1895
|
-
const pyType = fieldPyType(field, resolveRef);
|
|
1896
|
-
autoAccessors.push({ name, pyType, typeId: field.type });
|
|
2004
|
+
const pyType = fieldPyType(field, resolveRef, tsIndex);
|
|
2005
|
+
autoAccessors.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field) });
|
|
1897
2006
|
}
|
|
1898
2007
|
continue;
|
|
1899
2008
|
}
|
|
1900
2009
|
if (isNotChoiceDeclarationField(field)) {
|
|
1901
|
-
const sliceNames = collectRequiredSliceNames(field);
|
|
2010
|
+
const sliceNames = collectRequiredSliceNames(field, flatProfile.slicing?.[name]);
|
|
1902
2011
|
if (sliceNames) {
|
|
1903
2012
|
if (field.type) {
|
|
1904
|
-
const pyType = fieldPyType(field, resolveRef);
|
|
2013
|
+
const pyType = fieldPyType(field, resolveRef, tsIndex);
|
|
1905
2014
|
sliceAutoFields.push({ name, pyType, typeId: field.type, sliceNames });
|
|
1906
|
-
autoAccessors.push({ name, pyType, typeId: field.type });
|
|
2015
|
+
autoAccessors.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field) });
|
|
1907
2016
|
}
|
|
1908
2017
|
continue;
|
|
1909
2018
|
}
|
|
1910
2019
|
}
|
|
1911
2020
|
if (field.required) {
|
|
1912
|
-
const pyType = fieldPyType(field, resolveRef);
|
|
1913
|
-
params.push({ name, pyType, typeId: field.type });
|
|
2021
|
+
const pyType = fieldPyType(field, resolveRef, tsIndex);
|
|
2022
|
+
params.push({ name, pyType, typeId: field.type, refComment: pyReferenceComment(field) });
|
|
1914
2023
|
}
|
|
1915
2024
|
}
|
|
1916
2025
|
collectBaseRequiredParams(tsIndex, flatProfile, resolveRef, params, [
|
|
@@ -1922,9 +2031,15 @@ var collectProfileFactoryInfo = (tsIndex, flatProfile) => {
|
|
|
1922
2031
|
const choiceAccessors = [];
|
|
1923
2032
|
for (const [name, field] of pendingChoiceInstances) {
|
|
1924
2033
|
if (promotedChoices.has(name)) continue;
|
|
1925
|
-
const pyType =
|
|
2034
|
+
const pyType = pyChoiceInstanceType(field, tsIndex);
|
|
1926
2035
|
const choiceSiblings = (choiceGroups.get(name) ?? []).filter((s) => s !== name && !promotedChoices.has(s));
|
|
1927
|
-
choiceAccessors.push({
|
|
2036
|
+
choiceAccessors.push({
|
|
2037
|
+
name,
|
|
2038
|
+
pyType,
|
|
2039
|
+
typeId: field.type,
|
|
2040
|
+
choiceSiblings,
|
|
2041
|
+
refComment: pyReferenceComment(field)
|
|
2042
|
+
});
|
|
1928
2043
|
}
|
|
1929
2044
|
return { autoFields, sliceAutoFields, params, accessors: [...autoAccessors, ...choiceAccessors] };
|
|
1930
2045
|
};
|
|
@@ -2007,12 +2122,12 @@ var generateFieldAccessors = (w, className, factoryInfo, extSliceMethodBaseNames
|
|
|
2007
2122
|
for (const p of factoryInfo.params) {
|
|
2008
2123
|
const fieldName = pyFieldName(p.name, fmt);
|
|
2009
2124
|
const methodSuffix = pySnakeName(p.name);
|
|
2010
|
-
w.line(`def get_${methodSuffix}(self) -> ${p.pyType} | None
|
|
2125
|
+
w.line(`def get_${methodSuffix}(self) -> ${p.pyType} | None:${p.refComment ?? ""}`);
|
|
2011
2126
|
w.indentBlock(() => {
|
|
2012
2127
|
w.line(`return cast('${p.pyType} | None', getattr(self._resource, ${JSON.stringify(fieldName)}, None))`);
|
|
2013
2128
|
});
|
|
2014
2129
|
w.line();
|
|
2015
|
-
w.line(`def set_${methodSuffix}(self, value: ${p.pyType}) -> "${className}"
|
|
2130
|
+
w.line(`def set_${methodSuffix}(self, value: ${p.pyType}) -> "${className}":${p.refComment ?? ""}`);
|
|
2016
2131
|
w.indentBlock(() => {
|
|
2017
2132
|
w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, value)`);
|
|
2018
2133
|
w.line("return self");
|
|
@@ -2023,12 +2138,12 @@ var generateFieldAccessors = (w, className, factoryInfo, extSliceMethodBaseNames
|
|
|
2023
2138
|
const methodSuffix = pySnakeName(a.name);
|
|
2024
2139
|
if (extSliceMethodBaseNames.has(methodSuffix)) continue;
|
|
2025
2140
|
const fieldName = pyFieldName(a.name, fmt);
|
|
2026
|
-
w.line(`def get_${methodSuffix}(self) -> ${a.pyType} | None
|
|
2141
|
+
w.line(`def get_${methodSuffix}(self) -> ${a.pyType} | None:${a.refComment ?? ""}`);
|
|
2027
2142
|
w.indentBlock(() => {
|
|
2028
2143
|
w.line(`return cast('${a.pyType} | None', getattr(self._resource, ${JSON.stringify(fieldName)}, None))`);
|
|
2029
2144
|
});
|
|
2030
2145
|
w.line();
|
|
2031
|
-
w.line(`def set_${methodSuffix}(self, value: ${a.pyType}) -> "${className}"
|
|
2146
|
+
w.line(`def set_${methodSuffix}(self, value: ${a.pyType}) -> "${className}":${a.refComment ?? ""}`);
|
|
2032
2147
|
w.indentBlock(() => {
|
|
2033
2148
|
if (a.choiceSiblings?.length) {
|
|
2034
2149
|
for (const sibling of a.choiceSiblings) {
|
|
@@ -2043,94 +2158,125 @@ var generateFieldAccessors = (w, className, factoryInfo, extSliceMethodBaseNames
|
|
|
2043
2158
|
};
|
|
2044
2159
|
|
|
2045
2160
|
// src/api/writer-generator/python/profile-validation.ts
|
|
2046
|
-
var
|
|
2161
|
+
var pushListValidation = (lines, target, fn, args, items) => {
|
|
2162
|
+
const argList = ["self._resource", "profile_name", ...args].join(", ");
|
|
2163
|
+
lines.push(
|
|
2164
|
+
`${target}.extend(`,
|
|
2165
|
+
` ${fn}(${argList}, [`,
|
|
2166
|
+
` ${items.map((i) => JSON.stringify(i)).join(",")}`,
|
|
2167
|
+
"]))"
|
|
2168
|
+
);
|
|
2169
|
+
};
|
|
2170
|
+
var collectValidateBody = (flatProfile, tsIndex, errorLines, warningLines, formatName2) => {
|
|
2047
2171
|
const helpers = /* @__PURE__ */ new Set();
|
|
2048
2172
|
const fields = flatProfile.fields;
|
|
2049
2173
|
for (const [name, field] of Object.entries(fields)) {
|
|
2050
2174
|
const pyName = pyFieldName(name, formatName2);
|
|
2051
|
-
if (isChoiceInstanceField(field))
|
|
2052
|
-
collectProhibitedChoiceValidation(fields, name, pyName, helpers, errorLines);
|
|
2053
|
-
continue;
|
|
2054
|
-
}
|
|
2175
|
+
if (isChoiceInstanceField(field)) continue;
|
|
2055
2176
|
if (isChoiceDeclarationField(field)) {
|
|
2056
2177
|
if (field.required) {
|
|
2057
2178
|
helpers.add("validate_choice_required");
|
|
2058
2179
|
const pyChoices = field.choices.map((c) => pyFieldName(c, formatName2));
|
|
2059
|
-
errorLines
|
|
2060
|
-
|
|
2061
|
-
|
|
2180
|
+
pushListValidation(errorLines, "errors", "validate_choice_required", [], pyChoices);
|
|
2181
|
+
}
|
|
2182
|
+
if (field.prohibited?.length) {
|
|
2183
|
+
helpers.add("validate_choice_prohibited");
|
|
2184
|
+
const pyProhibited = field.prohibited.map((c) => pyFieldName(c, formatName2));
|
|
2185
|
+
pushListValidation(errorLines, "errors", "validate_choice_prohibited", [], pyProhibited);
|
|
2062
2186
|
}
|
|
2063
2187
|
continue;
|
|
2064
2188
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2189
|
+
collectRegularFieldValidation(
|
|
2190
|
+
field,
|
|
2191
|
+
flatProfile.slicing?.[name],
|
|
2192
|
+
pyName,
|
|
2193
|
+
helpers,
|
|
2194
|
+
errorLines,
|
|
2195
|
+
warningLines,
|
|
2196
|
+
tsIndex,
|
|
2197
|
+
formatName2
|
|
2198
|
+
);
|
|
2199
|
+
}
|
|
2200
|
+
for (const inheritedName of flatProfile.inheritedRequiredFields ?? []) {
|
|
2201
|
+
helpers.add("validate_required");
|
|
2202
|
+
errorLines.push(
|
|
2203
|
+
`errors.extend(validate_required(self._resource, profile_name, ${JSON.stringify(pyFieldName(inheritedName, formatName2))}))`
|
|
2204
|
+
);
|
|
2205
|
+
}
|
|
2206
|
+
return helpers;
|
|
2207
|
+
};
|
|
2208
|
+
var collectRegularFieldValidation = (field, fieldSlicing, pyName, helpers, errorLines, warningLines, tsIndex, formatName2) => {
|
|
2209
|
+
if (field.excluded) {
|
|
2210
|
+
helpers.add("validate_excluded");
|
|
2211
|
+
errorLines.push(`errors.extend(validate_excluded(self._resource, profile_name, ${JSON.stringify(pyName)}))`);
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2214
|
+
if (field.required) {
|
|
2215
|
+
helpers.add("validate_required");
|
|
2216
|
+
errorLines.push(`errors.extend(validate_required(self._resource, profile_name, ${JSON.stringify(pyName)}))`);
|
|
2217
|
+
}
|
|
2218
|
+
if (field.valueConstraint) {
|
|
2219
|
+
helpers.add("validate_fixed_value");
|
|
2220
|
+
const value = JSON.stringify(field.valueConstraint.value);
|
|
2221
|
+
errorLines.push(
|
|
2222
|
+
`errors.extend(validate_fixed_value(self._resource, profile_name, ${JSON.stringify(pyName)}, ${value}))`
|
|
2223
|
+
);
|
|
2224
|
+
}
|
|
2225
|
+
if (isNotChoiceDeclarationField(field)) {
|
|
2226
|
+
if (field.enum) {
|
|
2227
|
+
helpers.add("validate_enum");
|
|
2228
|
+
const target = field.enum.isOpen ? warningLines : errorLines;
|
|
2229
|
+
const listName = field.enum.isOpen ? "warnings" : "errors";
|
|
2230
|
+
pushListValidation(target, listName, "validate_enum", [JSON.stringify(pyName)], field.enum.values);
|
|
2231
|
+
}
|
|
2232
|
+
if (field.mustSupport && !field.required) {
|
|
2233
|
+
helpers.add("validate_must_support");
|
|
2234
|
+
warningLines.push(
|
|
2235
|
+
`warnings.extend(validate_must_support(self._resource, profile_name, ${JSON.stringify(pyName)}))`
|
|
2076
2236
|
);
|
|
2077
2237
|
}
|
|
2078
|
-
if (field.
|
|
2079
|
-
helpers.add("
|
|
2080
|
-
const
|
|
2081
|
-
errorLines.
|
|
2082
|
-
`errors.extend(validate_fixed_value(self._resource, profile_name, ${JSON.stringify(pyName)}, ${value}))`
|
|
2083
|
-
);
|
|
2238
|
+
if (field.reference && field.reference.resource.length > 0) {
|
|
2239
|
+
helpers.add("validate_reference");
|
|
2240
|
+
const allowed = field.reference.resource.map((ref) => tsIndex.findLastSpecializationByIdentifier(ref).name);
|
|
2241
|
+
pushListValidation(errorLines, "errors", "validate_reference", [JSON.stringify(pyName)], allowed);
|
|
2084
2242
|
}
|
|
2085
|
-
if (
|
|
2086
|
-
|
|
2087
|
-
helpers.add("validate_enum");
|
|
2088
|
-
const target = field.enum.isOpen ? warningLines : errorLines;
|
|
2089
|
-
const listName = field.enum.isOpen ? "warnings" : "errors";
|
|
2090
|
-
target.push(
|
|
2091
|
-
`${listName}.extend(validate_enum(self._resource, profile_name, ${JSON.stringify(pyName)}, ${JSON.stringify(field.enum.values)}))`
|
|
2092
|
-
);
|
|
2093
|
-
}
|
|
2094
|
-
if (field.mustSupport && !field.required) {
|
|
2095
|
-
helpers.add("validate_must_support");
|
|
2096
|
-
warningLines.push(
|
|
2097
|
-
`warnings.extend(validate_must_support(self._resource, profile_name, ${JSON.stringify(pyName)}))`
|
|
2098
|
-
);
|
|
2099
|
-
}
|
|
2100
|
-
if (field.reference && field.reference.length > 0) {
|
|
2101
|
-
helpers.add("validate_reference");
|
|
2102
|
-
const allowed = field.reference.map((ref) => resolveRef(ref).name);
|
|
2103
|
-
errorLines.push(
|
|
2104
|
-
`errors.extend(validate_reference(self._resource, profile_name, ${JSON.stringify(pyName)}, ${JSON.stringify(allowed)}))`
|
|
2105
|
-
);
|
|
2106
|
-
}
|
|
2107
|
-
if (field.slicing?.slices) {
|
|
2108
|
-
collectSliceCardinalityValidation(field, pyName, helpers, errorLines);
|
|
2109
|
-
}
|
|
2243
|
+
if (fieldSlicing?.slices) {
|
|
2244
|
+
collectSliceValidation(field, fieldSlicing, pyName, helpers, errorLines, tsIndex, formatName2);
|
|
2110
2245
|
}
|
|
2111
2246
|
}
|
|
2112
|
-
return helpers;
|
|
2113
2247
|
};
|
|
2114
|
-
var
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
const decl = fields[field.choiceOf];
|
|
2118
|
-
if (!decl || !isChoiceDeclarationField(decl) || !decl.prohibited?.includes(name)) return;
|
|
2119
|
-
helpers.add("validate_excluded");
|
|
2120
|
-
errorLines.push(`errors.extend(validate_excluded(self._resource, profile_name, ${JSON.stringify(pyName)}))`);
|
|
2121
|
-
};
|
|
2122
|
-
var collectSliceCardinalityValidation = (field, name, helpers, errorLines) => {
|
|
2123
|
-
if (!field.slicing?.slices) return;
|
|
2124
|
-
for (const [sliceName, slice] of Object.entries(field.slicing.slices)) {
|
|
2125
|
-
if (slice.min === void 0 && slice.max === void 0) continue;
|
|
2248
|
+
var collectSliceValidation = (field, fieldSlicing, name, helpers, errorLines, tsIndex, formatName2) => {
|
|
2249
|
+
if (!fieldSlicing.slices) return;
|
|
2250
|
+
for (const [sliceName, slice] of Object.entries(fieldSlicing.slices)) {
|
|
2126
2251
|
const match = slice.match ?? {};
|
|
2127
2252
|
if (Object.keys(match).length === 0) continue;
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2253
|
+
if (slice.min !== void 0 || slice.max !== void 0) {
|
|
2254
|
+
const min = slice.min ?? 0;
|
|
2255
|
+
const max = slice.max ?? 0;
|
|
2256
|
+
helpers.add("validate_slice_cardinality");
|
|
2257
|
+
errorLines.push(
|
|
2258
|
+
`errors.extend(validate_slice_cardinality(self._resource, profile_name, ${JSON.stringify(name)}, ${JSON.stringify(match)}, ${JSON.stringify(sliceName)}, ${min}, ${max}))`
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
const sliceRequiredFields = [];
|
|
2262
|
+
const matchKeys = new Set(Object.keys(match));
|
|
2263
|
+
for (const rf of slice.required ?? []) {
|
|
2264
|
+
if (!matchKeys.has(rf)) sliceRequiredFields.push(pyFieldName(rf, formatName2));
|
|
2265
|
+
}
|
|
2266
|
+
if (field.type && slice.elements) {
|
|
2267
|
+
const cc = tsIndex.constrainedChoice(field.type.package, field.type, slice.elements);
|
|
2268
|
+
if (cc) sliceRequiredFields.push(pyFieldName(cc.variant, formatName2));
|
|
2269
|
+
}
|
|
2270
|
+
if (sliceRequiredFields.length > 0) {
|
|
2271
|
+
helpers.add("validate_slice_fields");
|
|
2272
|
+
pushListValidation(
|
|
2273
|
+
errorLines,
|
|
2274
|
+
"errors",
|
|
2275
|
+
"validate_slice_fields",
|
|
2276
|
+
[JSON.stringify(name), JSON.stringify(match), JSON.stringify(sliceName)],
|
|
2277
|
+
sliceRequiredFields
|
|
2278
|
+
);
|
|
2279
|
+
}
|
|
2134
2280
|
}
|
|
2135
2281
|
};
|
|
2136
2282
|
|
|
@@ -2188,6 +2334,10 @@ var collectHelperImports = (isResourceBase, factoryInfo, sliceDefs, extensions,
|
|
|
2188
2334
|
imports.push("_get_key", "is_extension", "get_extension_value", "push_extension");
|
|
2189
2335
|
if (extensions.some((ext) => ext.isComplex && ext.subExtensions)) imports.push("extract_complex_extension");
|
|
2190
2336
|
if (extensions.some((ext) => ext.path.split(".").some((s) => s !== "extension"))) imports.push("ensure_path");
|
|
2337
|
+
const hasDictFormSetter = extensions.some(
|
|
2338
|
+
(ext) => ext.isComplex && ext.subExtensions || !(ext.valueFieldTypes?.length === 1 && ext.valueFieldTypes[0])
|
|
2339
|
+
);
|
|
2340
|
+
if (hasDictFormSetter) imports.push("is_record");
|
|
2191
2341
|
}
|
|
2192
2342
|
imports.push(...validationHelpers);
|
|
2193
2343
|
imports.sort();
|
|
@@ -2369,13 +2519,7 @@ var generateProfileModule = (w, tsIndex, flatProfile) => {
|
|
|
2369
2519
|
const resolvedNames = resolveProfileMethodBaseNames(extensions, sliceDefs);
|
|
2370
2520
|
const errorLines = [];
|
|
2371
2521
|
const warningLines = [];
|
|
2372
|
-
const validationHelpers = collectValidateBody(
|
|
2373
|
-
flatProfile,
|
|
2374
|
-
tsIndex.findLastSpecializationByIdentifier,
|
|
2375
|
-
errorLines,
|
|
2376
|
-
warningLines,
|
|
2377
|
-
w.nameFormatFunction
|
|
2378
|
-
);
|
|
2522
|
+
const validationHelpers = collectValidateBody(flatProfile, tsIndex, errorLines, warningLines, w.nameFormatFunction);
|
|
2379
2523
|
const helperImports = collectHelperImports(isResourceBase, factoryInfo, sliceDefs, extensions, validationHelpers);
|
|
2380
2524
|
const typeImports = collectTypeImports(
|
|
2381
2525
|
w.opts.rootPackageName,
|
|
@@ -2482,7 +2626,8 @@ var AVAILABLE_STRING_FORMATS = {
|
|
|
2482
2626
|
var MAX_IMPORT_LINE_LENGTH = 100;
|
|
2483
2627
|
var GENERIC_FIELD_REWRITES = {
|
|
2484
2628
|
Coding: { code: "T" },
|
|
2485
|
-
CodeableConcept: { coding: "Coding[T]" }
|
|
2629
|
+
CodeableConcept: { coding: "Coding[T]" },
|
|
2630
|
+
Reference: { type: "T" }
|
|
2486
2631
|
};
|
|
2487
2632
|
var leafOf2 = (path) => path[path.length - 1] ?? "";
|
|
2488
2633
|
var collectResourceGenericTypeVars = (schema) => {
|
|
@@ -2789,13 +2934,9 @@ var Python = class extends Writer {
|
|
|
2789
2934
|
}
|
|
2790
2935
|
generateResourceTypeField(schema) {
|
|
2791
2936
|
const hasChildren = (schema.typeFamily?.resources?.length ?? 0) > 0;
|
|
2792
|
-
|
|
2793
|
-
this.line(`${this.nameFormatFunction("resourceType")}: str = Field(`);
|
|
2794
|
-
} else {
|
|
2795
|
-
this.line(`${this.nameFormatFunction("resourceType")}: Literal['${schema.identifier.name}'] = Field(`);
|
|
2796
|
-
}
|
|
2937
|
+
this.line(`${this.nameFormatFunction("resourceType")}: str = Field(`);
|
|
2797
2938
|
this.indentBlock(() => {
|
|
2798
|
-
this.line(`default='${schema.identifier.name}',`);
|
|
2939
|
+
if (!hasChildren) this.line(`default='${schema.identifier.name}',`);
|
|
2799
2940
|
this.line(`alias='resourceType',`);
|
|
2800
2941
|
this.line(`serialization_alias='resourceType',`);
|
|
2801
2942
|
if (!this.forFhirpyClient) {
|
|
@@ -2883,6 +3024,11 @@ var Python = class extends Writer {
|
|
|
2883
3024
|
fieldType = `Literal[${s}]`;
|
|
2884
3025
|
}
|
|
2885
3026
|
}
|
|
3027
|
+
if (fieldType === "Reference" && "reference" in field && field.reference) {
|
|
3028
|
+
assert4(this.tsIndex !== void 0);
|
|
3029
|
+
const typeParam = pyReferenceTypeParam(field, this.tsIndex);
|
|
3030
|
+
if (typeParam) fieldType = `Reference[${typeParam}]`;
|
|
3031
|
+
}
|
|
2886
3032
|
if (field.array) {
|
|
2887
3033
|
fieldType = `PyList[${fieldType}]`;
|
|
2888
3034
|
}
|
|
@@ -3034,6 +3180,18 @@ var Python = class extends Writer {
|
|
|
3034
3180
|
}
|
|
3035
3181
|
};
|
|
3036
3182
|
|
|
3183
|
+
// src/typeschema/collision-order.ts
|
|
3184
|
+
var compareStrings = (left, right) => {
|
|
3185
|
+
if (left < right) return -1;
|
|
3186
|
+
if (left > right) return 1;
|
|
3187
|
+
return 0;
|
|
3188
|
+
};
|
|
3189
|
+
var compareCollisionSources = (left, right) => compareStrings(left.sourcePackage, right.sourcePackage) || compareStrings(left.sourceCanonical, right.sourceCanonical);
|
|
3190
|
+
var collisionSourcesKey = (sources) => JSON.stringify(
|
|
3191
|
+
[...sources].sort(compareCollisionSources).map(({ sourcePackage, sourceCanonical }) => [sourcePackage, sourceCanonical])
|
|
3192
|
+
);
|
|
3193
|
+
var compareCollisionVariants = (left, right) => right.sources.length - left.sources.length || compareStrings(collisionSourcesKey(left.sources), collisionSourcesKey(right.sources)) || compareStrings(left.schemaHash, right.schemaHash);
|
|
3194
|
+
|
|
3037
3195
|
// src/typeschema/skip-hack.ts
|
|
3038
3196
|
var codeableReferenceInR4 = "Use CodeableReference which is not provided by FHIR R4.";
|
|
3039
3197
|
var availabilityInR4 = "Use Availability which is not provided by FHIR R4.";
|
|
@@ -3346,9 +3504,9 @@ var assignRecommendedBaseNames = (profile) => {
|
|
|
3346
3504
|
key: `ext:${ext.url}:${ext.path}`,
|
|
3347
3505
|
candidates: ext.nameCandidates.candidates
|
|
3348
3506
|
}));
|
|
3349
|
-
const sliceEntries = Object.entries(profile.
|
|
3350
|
-
if (!
|
|
3351
|
-
return Object.entries(
|
|
3507
|
+
const sliceEntries = Object.entries(profile.slicing ?? {}).flatMap(([fieldName, fieldSlicing]) => {
|
|
3508
|
+
if (!fieldSlicing.slices) return [];
|
|
3509
|
+
return Object.entries(fieldSlicing.slices).map(([sliceName, slice]) => ({
|
|
3352
3510
|
key: `slice:${fieldName}:${sliceName}`,
|
|
3353
3511
|
candidates: slice.nameCandidates.candidates
|
|
3354
3512
|
}));
|
|
@@ -3362,9 +3520,9 @@ var assignRecommendedBaseNames = (profile) => {
|
|
|
3362
3520
|
const key = `ext:${ext.url}:${ext.path}`;
|
|
3363
3521
|
if (resolved[key]) ext.nameCandidates.recommended = resolved[key];
|
|
3364
3522
|
}
|
|
3365
|
-
for (const [fieldName,
|
|
3366
|
-
if (!
|
|
3367
|
-
for (const [sliceName, slice] of Object.entries(
|
|
3523
|
+
for (const [fieldName, fieldSlicing] of Object.entries(profile.slicing ?? {})) {
|
|
3524
|
+
if (!fieldSlicing.slices) continue;
|
|
3525
|
+
for (const [sliceName, slice] of Object.entries(fieldSlicing.slices)) {
|
|
3368
3526
|
const key = `slice:${fieldName}:${sliceName}`;
|
|
3369
3527
|
if (resolved[key]) slice.nameCandidates.recommended = resolved[key];
|
|
3370
3528
|
}
|
|
@@ -3571,8 +3729,8 @@ var registerFromManager = async (manager, { logger, focusedPackages }) => {
|
|
|
3571
3729
|
if (!sd.package_name) {
|
|
3572
3730
|
return {
|
|
3573
3731
|
...sd,
|
|
3574
|
-
package_name:
|
|
3575
|
-
package_version:
|
|
3732
|
+
package_name: r.pkg.name,
|
|
3733
|
+
package_version: r.pkg.version
|
|
3576
3734
|
};
|
|
3577
3735
|
}
|
|
3578
3736
|
return sd;
|
|
@@ -3701,6 +3859,7 @@ function collectNestedElements(fhirSchema, parentPath, elements) {
|
|
|
3701
3859
|
}
|
|
3702
3860
|
function transformNestedElements(register, fhirSchema, parentPath, elements, logger) {
|
|
3703
3861
|
const fields = {};
|
|
3862
|
+
const slicing = {};
|
|
3704
3863
|
const genealogy = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url);
|
|
3705
3864
|
const elemGenealogy = resolveFsElementGenealogy(genealogy, parentPath);
|
|
3706
3865
|
const allKeys = /* @__PURE__ */ new Set();
|
|
@@ -3719,8 +3878,10 @@ function transformNestedElements(register, fhirSchema, parentPath, elements, log
|
|
|
3719
3878
|
} else {
|
|
3720
3879
|
fields[key] = mkField(register, fhirSchema, path, elemSnapshot, logger);
|
|
3721
3880
|
}
|
|
3881
|
+
const fieldSlicing = buildSlicing(key, elemSnapshot);
|
|
3882
|
+
if (fieldSlicing) slicing[key] = fieldSlicing;
|
|
3722
3883
|
}
|
|
3723
|
-
return fields;
|
|
3884
|
+
return { fields, slicing: Object.keys(slicing).length > 0 ? slicing : void 0 };
|
|
3724
3885
|
}
|
|
3725
3886
|
function mkNestedTypes(register, fhirSchema, logger) {
|
|
3726
3887
|
if (!fhirSchema.elements) return void 0;
|
|
@@ -3750,11 +3911,12 @@ function mkNestedTypes(register, fhirSchema, logger) {
|
|
|
3750
3911
|
name: baseName,
|
|
3751
3912
|
url: baseUrl
|
|
3752
3913
|
};
|
|
3753
|
-
const fields = transformNestedElements(register, fhirSchema, path, element.elements ?? {}, logger);
|
|
3914
|
+
const { fields, slicing } = transformNestedElements(register, fhirSchema, path, element.elements ?? {}, logger);
|
|
3754
3915
|
const nestedType = {
|
|
3755
3916
|
identifier,
|
|
3756
3917
|
base,
|
|
3757
|
-
fields
|
|
3918
|
+
fields,
|
|
3919
|
+
slicing
|
|
3758
3920
|
};
|
|
3759
3921
|
nestedTypes.push(nestedType);
|
|
3760
3922
|
}
|
|
@@ -3837,12 +3999,27 @@ function isExcluded(register, fhirSchema, path) {
|
|
|
3837
3999
|
}
|
|
3838
4000
|
var buildReferences = (register, fhirSchema, element) => {
|
|
3839
4001
|
if (!element.refers) return void 0;
|
|
3840
|
-
|
|
4002
|
+
const resource = [];
|
|
4003
|
+
const profiles = [];
|
|
4004
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4005
|
+
for (const ref of element.refers) {
|
|
3841
4006
|
const curl = register.ensureSpecializationCanonicalUrl(ref);
|
|
3842
4007
|
const fs6 = register.resolveFs(fhirSchema.package_meta, curl);
|
|
3843
4008
|
if (!fs6) throw new Error(`Failed to resolve fs for ${curl}`);
|
|
3844
|
-
|
|
3845
|
-
|
|
4009
|
+
const id = mkIdentifier(fs6);
|
|
4010
|
+
let resolved = id;
|
|
4011
|
+
if (isProfileIdentifier(id)) {
|
|
4012
|
+
profiles.push(id);
|
|
4013
|
+
const baseFs = register.resolveFsSpecializations(fs6.package_meta, fs6.url)[0];
|
|
4014
|
+
if (!baseFs) throw new Error(`Failed to resolve base specialization for ${curl}`);
|
|
4015
|
+
resolved = mkIdentifier(baseFs);
|
|
4016
|
+
}
|
|
4017
|
+
if (!seen.has(resolved.url)) {
|
|
4018
|
+
seen.add(resolved.url);
|
|
4019
|
+
resource.push(resolved);
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
return { resource, profiles: profiles.length > 0 ? profiles : void 0 };
|
|
3846
4023
|
};
|
|
3847
4024
|
var extractSliceFieldNames = (schema) => {
|
|
3848
4025
|
const required = /* @__PURE__ */ new Set();
|
|
@@ -4068,7 +4245,6 @@ var mkField = (register, fhirSchema, path, element, logger, rawElement) => {
|
|
|
4068
4245
|
array: element.array || false,
|
|
4069
4246
|
min: element.min,
|
|
4070
4247
|
max: element.max,
|
|
4071
|
-
slicing: buildSlicing(path[path.length - 1] ?? "", element),
|
|
4072
4248
|
choices: element.choices,
|
|
4073
4249
|
choiceOf: element.choiceOf,
|
|
4074
4250
|
binding,
|
|
@@ -4083,8 +4259,7 @@ function mkNestedField(register, fhirSchema, path, element) {
|
|
|
4083
4259
|
type: nestedIdentifier,
|
|
4084
4260
|
array: element.array || false,
|
|
4085
4261
|
required: isRequired(register, fhirSchema, path),
|
|
4086
|
-
excluded: isExcluded(register, fhirSchema, path)
|
|
4087
|
-
slicing: buildSlicing(path[path.length - 1] ?? "", element)
|
|
4262
|
+
excluded: isExcluded(register, fhirSchema, path)
|
|
4088
4263
|
};
|
|
4089
4264
|
}
|
|
4090
4265
|
|
|
@@ -4223,8 +4398,9 @@ var extractProfileExtensions = (register, fhirSchema, logger) => {
|
|
|
4223
4398
|
|
|
4224
4399
|
// src/typeschema/core/transformer.ts
|
|
4225
4400
|
function mkFields(register, fhirSchema, parentPath, elements, logger) {
|
|
4226
|
-
if (!elements) return
|
|
4401
|
+
if (!elements) return {};
|
|
4227
4402
|
const fields = {};
|
|
4403
|
+
const slicing = {};
|
|
4228
4404
|
for (const key of register.getAllElementKeys(elements)) {
|
|
4229
4405
|
const path = [...parentPath, key];
|
|
4230
4406
|
const elemSnapshot = register.resolveElementSnapshot(fhirSchema, path);
|
|
@@ -4241,8 +4417,10 @@ function mkFields(register, fhirSchema, parentPath, elements, logger) {
|
|
|
4241
4417
|
} else {
|
|
4242
4418
|
fields[key] = mkField(register, fhirSchema, path, elemSnapshot, logger, elements[key]);
|
|
4243
4419
|
}
|
|
4420
|
+
const fieldSlicing = buildSlicing(key, elemSnapshot);
|
|
4421
|
+
if (fieldSlicing) slicing[key] = fieldSlicing;
|
|
4244
4422
|
}
|
|
4245
|
-
return fields;
|
|
4423
|
+
return { fields, slicing: Object.keys(slicing).length > 0 ? slicing : void 0 };
|
|
4246
4424
|
}
|
|
4247
4425
|
function extractFieldDependencies(fields) {
|
|
4248
4426
|
const deps = [];
|
|
@@ -4303,7 +4481,7 @@ function transformFhirSchema(register, fhirSchema, logger) {
|
|
|
4303
4481
|
assert4(!isNestedIdentifier(baseId), `Unexpected nested base for ${fhirSchema.url}`);
|
|
4304
4482
|
base = baseId;
|
|
4305
4483
|
}
|
|
4306
|
-
const fields = mkFields(register, fhirSchema, [], fhirSchema.elements, logger);
|
|
4484
|
+
const { fields, slicing } = mkFields(register, fhirSchema, [], fhirSchema.elements, logger);
|
|
4307
4485
|
const nested = mkNestedTypes(register, fhirSchema, logger);
|
|
4308
4486
|
const bindingSchemas = collectBindingSchemas(register, fhirSchema, logger);
|
|
4309
4487
|
if (fhirSchema.derivation === "constraint") {
|
|
@@ -4316,6 +4494,7 @@ function transformFhirSchema(register, fhirSchema, logger) {
|
|
|
4316
4494
|
identifier: identifier2,
|
|
4317
4495
|
base,
|
|
4318
4496
|
fields,
|
|
4497
|
+
slicing,
|
|
4319
4498
|
nested,
|
|
4320
4499
|
description: fhirSchema.description,
|
|
4321
4500
|
dependencies: concatIdentifiers(rawDeps, extensionDeps),
|
|
@@ -4342,6 +4521,7 @@ function transformFhirSchema(register, fhirSchema, logger) {
|
|
|
4342
4521
|
identifier,
|
|
4343
4522
|
base,
|
|
4344
4523
|
fields,
|
|
4524
|
+
slicing,
|
|
4345
4525
|
nested,
|
|
4346
4526
|
description: fhirSchema.description,
|
|
4347
4527
|
dependencies: extractDependencies(identifier, base, fields, nested),
|
|
@@ -4363,7 +4543,11 @@ var deduplicateSchemas = (schemasWithSources, resolveCollisions, logger) => {
|
|
|
4363
4543
|
const schemas = [];
|
|
4364
4544
|
const collisions = {};
|
|
4365
4545
|
for (const versions of Object.values(groups)) {
|
|
4366
|
-
const sorted = Object.
|
|
4546
|
+
const sorted = Object.entries(versions).map(([schemaHash, version]) => ({
|
|
4547
|
+
...version,
|
|
4548
|
+
schemaHash,
|
|
4549
|
+
sources: [...version.sources].sort(compareCollisionSources)
|
|
4550
|
+
})).sort(compareCollisionVariants);
|
|
4367
4551
|
const best = sorted[0];
|
|
4368
4552
|
if (!best) continue;
|
|
4369
4553
|
if (sorted.length > 1) {
|
|
@@ -4588,6 +4772,10 @@ var treeShakeTypeSchema = (schema, rule, _logger) => {
|
|
|
4588
4772
|
if (isProfileTypeSchema(schema) && rule.ignoreExtensions) {
|
|
4589
4773
|
mutableIgnoreExtensions(schema, rule.ignoreExtensions);
|
|
4590
4774
|
}
|
|
4775
|
+
if (schema.slicing) {
|
|
4776
|
+
const kept = Object.fromEntries(Object.entries(schema.slicing).filter(([name]) => schema.fields?.[name]));
|
|
4777
|
+
schema.slicing = Object.keys(kept).length > 0 ? kept : void 0;
|
|
4778
|
+
}
|
|
4591
4779
|
if (schema.nested) {
|
|
4592
4780
|
const usedTypes = /* @__PURE__ */ new Set();
|
|
4593
4781
|
const collectUsedNestedTypes = (s) => {
|
|
@@ -4616,16 +4804,36 @@ var treeShakeTypeSchema = (schema, rule, _logger) => {
|
|
|
4616
4804
|
}
|
|
4617
4805
|
return schema;
|
|
4618
4806
|
};
|
|
4619
|
-
var
|
|
4807
|
+
var collectReferenceTargets = (schema) => {
|
|
4808
|
+
if (!isSpecializationTypeSchema(schema) && !isProfileTypeSchema(schema)) return [];
|
|
4809
|
+
const fieldSets = [schema.fields, ...(schema.nested ?? []).map((n) => n.fields)];
|
|
4810
|
+
return fieldSets.flatMap(
|
|
4811
|
+
(fields) => Object.values(fields ?? {}).filter(isNotChoiceDeclarationField).flatMap((f) => [...f.reference?.resource ?? [], ...f.reference?.profiles ?? []]).filter((id) => !isNestedIdentifier(id))
|
|
4812
|
+
);
|
|
4813
|
+
};
|
|
4814
|
+
var treeShake = (tsIndex, treeShake2, defaults) => {
|
|
4620
4815
|
const focusedSchemas = [];
|
|
4816
|
+
const followedSchemas = [];
|
|
4621
4817
|
for (const [pkgId, requires] of Object.entries(treeShake2)) {
|
|
4622
4818
|
for (const [url, rule] of Object.entries(requires)) {
|
|
4623
4819
|
const schema = tsIndex.resolveByUrl(pkgId, url);
|
|
4624
4820
|
if (!schema || isNestedTypeSchema(schema)) throw new Error(`Schema not found for ${pkgId} ${url}`);
|
|
4625
4821
|
const shaked2 = treeShakeTypeSchema(schema, rule);
|
|
4626
4822
|
focusedSchemas.push(shaked2);
|
|
4823
|
+
if (rule.followReferences ?? defaults?.followReferences) {
|
|
4824
|
+
for (const refId of collectReferenceTargets(shaked2)) {
|
|
4825
|
+
const refSchema = tsIndex.resolve(refId);
|
|
4826
|
+
if (!refSchema)
|
|
4827
|
+
throw new Error(`Reference target ${JSON.stringify(refId)} not found for ${pkgId} ${url}`);
|
|
4828
|
+
followedSchemas.push(refSchema);
|
|
4829
|
+
}
|
|
4830
|
+
}
|
|
4627
4831
|
}
|
|
4628
4832
|
}
|
|
4833
|
+
const rootIds = new Set(focusedSchemas.map((s) => JSON.stringify(s.identifier)));
|
|
4834
|
+
for (const schema of followedSchemas) {
|
|
4835
|
+
if (!rootIds.has(JSON.stringify(schema.identifier))) focusedSchemas.push(schema);
|
|
4836
|
+
}
|
|
4629
4837
|
const collectDeps = (schemas, acc) => {
|
|
4630
4838
|
if (schemas.length === 0) return Object.values(acc);
|
|
4631
4839
|
for (const schema of schemas) {
|
|
@@ -4664,7 +4872,8 @@ var normalizeFileName = (str) => {
|
|
|
4664
4872
|
};
|
|
4665
4873
|
var typeSchemaToJson = (ts, pretty) => {
|
|
4666
4874
|
const pkgPath = normalizeFileName(ts.identifier.package);
|
|
4667
|
-
const
|
|
4875
|
+
const suffix = isSnapshotProfileTypeSchema(ts) ? ".snapshot" : "";
|
|
4876
|
+
const name = normalizeFileName(`${ts.identifier.name}(${extractNameFromCanonical(ts.identifier.url)})`) + suffix;
|
|
4668
4877
|
const baseName = Path5.join(pkgPath, name);
|
|
4669
4878
|
return {
|
|
4670
4879
|
filename: baseName,
|
|
@@ -4698,17 +4907,19 @@ var IntrospectionWriter = class extends FileSystemWriter {
|
|
|
4698
4907
|
this.logger()?.info(`IntrospectionWriter: Type tree written to ${this.opts.typeTree}`);
|
|
4699
4908
|
}
|
|
4700
4909
|
if (this.opts.typeSchemas) {
|
|
4701
|
-
|
|
4702
|
-
|
|
4910
|
+
const tsOpts = typeof this.opts.typeSchemas === "string" ? { target: this.opts.typeSchemas } : this.opts.typeSchemas;
|
|
4911
|
+
const schemas = tsOpts.profileSnapshots ? [...tsIndex.schemas, ...tsIndex.collectSnapshotProfiles()] : tsIndex.schemas;
|
|
4912
|
+
if (Path5.extname(tsOpts.target) === ".ndjson") {
|
|
4913
|
+
await this.writeNdjson(schemas, tsOpts.target, typeSchemaToJson);
|
|
4703
4914
|
} else {
|
|
4704
|
-
const items =
|
|
4915
|
+
const items = schemas.map((ts) => typeSchemaToJson(ts, true));
|
|
4705
4916
|
const seenFilenames = /* @__PURE__ */ new Set();
|
|
4706
4917
|
const dedupedItems = items.filter((item) => {
|
|
4707
4918
|
if (seenFilenames.has(item.filename)) return false;
|
|
4708
4919
|
seenFilenames.add(item.filename);
|
|
4709
4920
|
return true;
|
|
4710
4921
|
});
|
|
4711
|
-
this.cd(
|
|
4922
|
+
this.cd(tsOpts.target, () => {
|
|
4712
4923
|
for (const { filename, genContent } of dedupedItems) {
|
|
4713
4924
|
const fileName = `${filename}.json`;
|
|
4714
4925
|
this.cd(Path5.dirname(fileName), () => {
|
|
@@ -4739,15 +4950,15 @@ var IntrospectionWriter = class extends FileSystemWriter {
|
|
|
4739
4950
|
}
|
|
4740
4951
|
});
|
|
4741
4952
|
}
|
|
4742
|
-
this.logger()?.info(
|
|
4743
|
-
`IntrospectionWriter: ${tsIndex.schemas.length} TypeSchema written to ${this.opts.typeSchemas}`
|
|
4744
|
-
);
|
|
4953
|
+
this.logger()?.info(`IntrospectionWriter: ${schemas.length} TypeSchema written to ${tsOpts.target}`);
|
|
4745
4954
|
}
|
|
4955
|
+
const indexUrls = new Set(tsIndex.schemas.map((ts) => ts.identifier.url));
|
|
4746
4956
|
if (this.opts.fhirSchemas && tsIndex.register) {
|
|
4747
4957
|
const outputPath = this.opts.fhirSchemas;
|
|
4748
4958
|
const allFs = tsIndex.register.allFs();
|
|
4749
4959
|
const seenUrls = /* @__PURE__ */ new Set();
|
|
4750
4960
|
const fhirSchemas = allFs.filter((fs6) => {
|
|
4961
|
+
if (!indexUrls.has(fs6.url)) return false;
|
|
4751
4962
|
if (seenUrls.has(fs6.url)) return false;
|
|
4752
4963
|
seenUrls.add(fs6.url);
|
|
4753
4964
|
return true;
|
|
@@ -4767,6 +4978,7 @@ var IntrospectionWriter = class extends FileSystemWriter {
|
|
|
4767
4978
|
const allSd = tsIndex.register.allSd();
|
|
4768
4979
|
const seenUrls = /* @__PURE__ */ new Set();
|
|
4769
4980
|
const structureDefinitions = allSd.filter((sd) => {
|
|
4981
|
+
if (!indexUrls.has(sd.url)) return false;
|
|
4770
4982
|
if (seenUrls.has(sd.url)) return false;
|
|
4771
4983
|
seenUrls.add(sd.url);
|
|
4772
4984
|
return true;
|
|
@@ -4865,11 +5077,15 @@ var generatePackageSection = (lines, pkgName, treeShakePkg, promotedCanonicals)
|
|
|
4865
5077
|
var groupCollisionVersions = (entries, resolution) => {
|
|
4866
5078
|
const uniqueSchemas = /* @__PURE__ */ new Map();
|
|
4867
5079
|
for (const entry of entries) {
|
|
4868
|
-
const key =
|
|
5080
|
+
const key = hashSchema(entry.typeSchema);
|
|
4869
5081
|
if (!uniqueSchemas.has(key)) uniqueSchemas.set(key, []);
|
|
4870
5082
|
uniqueSchemas.get(key)?.push(entry);
|
|
4871
5083
|
}
|
|
4872
|
-
const sorted = [...uniqueSchemas.
|
|
5084
|
+
const sorted = [...uniqueSchemas.entries()].map(([schemaHash, group]) => ({
|
|
5085
|
+
entries: [...group].sort(compareCollisionSources),
|
|
5086
|
+
schemaHash,
|
|
5087
|
+
sources: group
|
|
5088
|
+
})).sort(compareCollisionVariants).map((group) => group.entries);
|
|
4873
5089
|
const markVersion = (group, i) => {
|
|
4874
5090
|
if (resolution)
|
|
4875
5091
|
return group.some(
|
|
@@ -5769,9 +5985,21 @@ var resolveFieldTsType = (schemaName, tsName, field, resolveRef, genericFieldMap
|
|
|
5769
5985
|
if (field.type.name === "CodeableConcept") return `CodeableConcept<${tsEnumType(field.enum)}>`;
|
|
5770
5986
|
return tsEnumType(field.enum);
|
|
5771
5987
|
}
|
|
5772
|
-
if (field.reference && field.reference.length > 0) {
|
|
5773
|
-
const
|
|
5774
|
-
|
|
5988
|
+
if (field.reference && field.reference.resource.length > 0) {
|
|
5989
|
+
const profilesByResource = {};
|
|
5990
|
+
if (resolveRef) {
|
|
5991
|
+
for (const profile of field.reference.profiles ?? []) {
|
|
5992
|
+
const base = resolveRef(profile).name;
|
|
5993
|
+
(profilesByResource[base] ??= []).push(profile.url);
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
const references = field.reference.resource.map((original) => {
|
|
5997
|
+
const ref = resolveRef ? resolveRef(original) : original;
|
|
5998
|
+
if (isFamilyType?.(ref)) return `string /* ${ref.name} */`;
|
|
5999
|
+
const profiles = profilesByResource[ref.name];
|
|
6000
|
+
if (profiles) return `"${ref.name}" /* ${profiles.join(", ")} */`;
|
|
6001
|
+
return `"${ref.name}"`;
|
|
6002
|
+
}).join(" | ");
|
|
5775
6003
|
return `Reference<${references}>`;
|
|
5776
6004
|
}
|
|
5777
6005
|
if (isPrimitiveIdentifier(field.type)) return resolvePrimitiveType(field.type.name);
|
|
@@ -5820,9 +6048,10 @@ var valueFieldToTsType = (valueField) => {
|
|
|
5820
6048
|
};
|
|
5821
6049
|
var collectSubExtensionSlices = (extProfile) => {
|
|
5822
6050
|
const extensionField = extProfile.fields.extension;
|
|
5823
|
-
|
|
6051
|
+
const extensionSlicing = extProfile.slicing?.extension;
|
|
6052
|
+
if (!extensionField || isChoiceDeclarationField(extensionField) || !extensionSlicing?.slices) return [];
|
|
5824
6053
|
const result = [];
|
|
5825
|
-
for (const [sliceName, slice] of Object.entries(
|
|
6054
|
+
for (const [sliceName, slice] of Object.entries(extensionSlicing.slices)) {
|
|
5826
6055
|
const valueField = extractValueField(slice.elements);
|
|
5827
6056
|
if (!valueField) continue;
|
|
5828
6057
|
const tsType = valueFieldToTsType(valueField);
|
|
@@ -6160,10 +6389,11 @@ var extractResourceTypeFromMatch = (match) => {
|
|
|
6160
6389
|
};
|
|
6161
6390
|
var collectTypesFromSlices = (tsIndex, snapshot, addType) => {
|
|
6162
6391
|
const pkgName = snapshot.identifier.package;
|
|
6163
|
-
for (const
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6392
|
+
for (const [fieldName, fieldSlicing] of Object.entries(snapshot.slicing ?? {})) {
|
|
6393
|
+
const field = snapshot.fields[fieldName];
|
|
6394
|
+
if (!isNotChoiceDeclarationField(field) || !fieldSlicing.slices || !field.type) continue;
|
|
6395
|
+
const isTypeDisc = isTypeDiscriminated(fieldSlicing);
|
|
6396
|
+
for (const slice of Object.values(fieldSlicing.slices)) {
|
|
6167
6397
|
if (Object.keys(slice.match ?? {}).length > 0) {
|
|
6168
6398
|
addType(field.type);
|
|
6169
6399
|
const cc = slice.elements ? tsIndex.constrainedChoice(pkgName, field.type, slice.elements) : void 0;
|
|
@@ -6181,11 +6411,10 @@ var collectTypesFromSlices = (tsIndex, snapshot, addType) => {
|
|
|
6181
6411
|
}
|
|
6182
6412
|
}
|
|
6183
6413
|
};
|
|
6184
|
-
var collectRequiredSliceNames2 = (field) => {
|
|
6185
|
-
if (!field.array || !
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
const names = Object.entries(field.slicing.slices).filter(([_, s]) => {
|
|
6414
|
+
var collectRequiredSliceNames2 = (field, fieldSlicing) => {
|
|
6415
|
+
if (!field.array || !fieldSlicing?.slices) return void 0;
|
|
6416
|
+
if (isTypeDiscriminated(fieldSlicing)) return void 0;
|
|
6417
|
+
const names = Object.entries(fieldSlicing.slices).filter(([_, s]) => {
|
|
6189
6418
|
if (s.min === void 0 || s.min < 1 || !s.match || Object.keys(s.match).length === 0) return false;
|
|
6190
6419
|
const matchKeys = new Set(Object.keys(s.match));
|
|
6191
6420
|
const requiredBeyondMatch = (s.required ?? []).filter((name) => !matchKeys.has(name));
|
|
@@ -6193,13 +6422,14 @@ var collectRequiredSliceNames2 = (field) => {
|
|
|
6193
6422
|
}).map(([name]) => name);
|
|
6194
6423
|
return names.length > 0 ? names : void 0;
|
|
6195
6424
|
};
|
|
6196
|
-
var collectSliceDefs2 = (tsIndex, snapshot) => Object.entries(snapshot.
|
|
6197
|
-
|
|
6425
|
+
var collectSliceDefs2 = (tsIndex, snapshot) => Object.entries(snapshot.slicing ?? {}).flatMap(([fieldName, fieldSlicing]) => {
|
|
6426
|
+
const field = snapshot.fields[fieldName];
|
|
6427
|
+
if (!isNotChoiceDeclarationField(field) || !fieldSlicing.slices || !field.type) return [];
|
|
6198
6428
|
const baseType = tsTypeFromIdentifier(field.type);
|
|
6199
6429
|
const pkgName = snapshot.identifier.package;
|
|
6200
6430
|
const choiceBaseNames = collectChoiceBaseNames(tsIndex, field.type);
|
|
6201
|
-
const isTypeDisc =
|
|
6202
|
-
return Object.entries(
|
|
6431
|
+
const isTypeDisc = isTypeDiscriminated(fieldSlicing);
|
|
6432
|
+
return Object.entries(fieldSlicing.slices).filter(([_, slice]) => Object.keys(slice.match ?? {}).length > 0).map(([sliceName, slice]) => {
|
|
6203
6433
|
const matchFields = Object.keys(slice.match ?? {});
|
|
6204
6434
|
const required = (slice.required ?? []).filter(
|
|
6205
6435
|
(name) => !matchFields.includes(name) && !choiceBaseNames.has(name)
|
|
@@ -6373,7 +6603,7 @@ var generateSliceGetters2 = (w, sliceDefs, snapshot) => {
|
|
|
6373
6603
|
};
|
|
6374
6604
|
|
|
6375
6605
|
// src/api/writer-generator/typescript/profile-validation.ts
|
|
6376
|
-
var
|
|
6606
|
+
var collectRegularFieldValidation2 = (errors, warnings, name, field, resolveRef, canonicalUrlExpr, tsIndex, fieldSlicing) => {
|
|
6377
6607
|
if (field.excluded) {
|
|
6378
6608
|
errors.push(`...validateExcluded(res, profileName, ${JSON.stringify(name)})`);
|
|
6379
6609
|
return;
|
|
@@ -6389,12 +6619,12 @@ var collectRegularFieldValidation = (errors, warnings, name, field, resolveRef,
|
|
|
6389
6619
|
}
|
|
6390
6620
|
if (field.mustSupport && !field.required)
|
|
6391
6621
|
warnings.push(`...validateMustSupport(res, profileName, ${JSON.stringify(name)})`);
|
|
6392
|
-
if (field.reference && field.reference.length > 0)
|
|
6622
|
+
if (field.reference && field.reference.resource.length > 0)
|
|
6393
6623
|
errors.push(
|
|
6394
|
-
`...validateReference(res, profileName, ${JSON.stringify(name)}, ${JSON.stringify(field.reference.map((ref) => resolveRef(ref).name))})`
|
|
6624
|
+
`...validateReference(res, profileName, ${JSON.stringify(name)}, ${JSON.stringify(field.reference.resource.map((ref) => resolveRef(ref).name))})`
|
|
6395
6625
|
);
|
|
6396
|
-
if (
|
|
6397
|
-
for (const [sliceName, slice] of Object.entries(
|
|
6626
|
+
if (fieldSlicing?.slices) {
|
|
6627
|
+
for (const [sliceName, slice] of Object.entries(fieldSlicing.slices)) {
|
|
6398
6628
|
const match = slice.match ?? {};
|
|
6399
6629
|
if (Object.keys(match).length === 0) continue;
|
|
6400
6630
|
if (slice.min !== void 0 || slice.max !== void 0) {
|
|
@@ -6432,25 +6662,23 @@ var generateValidateMethod2 = (w, tsIndex, snapshot) => {
|
|
|
6432
6662
|
const errors = [];
|
|
6433
6663
|
const warnings = [];
|
|
6434
6664
|
for (const [name, field] of Object.entries(fields)) {
|
|
6435
|
-
if (isChoiceInstanceField(field))
|
|
6436
|
-
const decl = fields[field.choiceOf];
|
|
6437
|
-
if (decl && isChoiceDeclarationField(decl) && decl.prohibited?.includes(name))
|
|
6438
|
-
errors.push(`...validateExcluded(res, profileName, ${JSON.stringify(name)})`);
|
|
6439
|
-
continue;
|
|
6440
|
-
}
|
|
6665
|
+
if (isChoiceInstanceField(field)) continue;
|
|
6441
6666
|
if (isChoiceDeclarationField(field)) {
|
|
6442
6667
|
if (field.required)
|
|
6443
6668
|
errors.push(`...validateChoiceRequired(res, profileName, ${JSON.stringify(field.choices)})`);
|
|
6669
|
+
if (field.prohibited?.length)
|
|
6670
|
+
errors.push(`...validateChoiceProhibited(res, profileName, ${JSON.stringify(field.prohibited)})`);
|
|
6444
6671
|
continue;
|
|
6445
6672
|
}
|
|
6446
|
-
|
|
6673
|
+
collectRegularFieldValidation2(
|
|
6447
6674
|
errors,
|
|
6448
6675
|
warnings,
|
|
6449
6676
|
name,
|
|
6450
6677
|
field,
|
|
6451
6678
|
tsIndex.findLastSpecializationByIdentifier,
|
|
6452
6679
|
canonicalUrlExpr,
|
|
6453
|
-
tsIndex
|
|
6680
|
+
tsIndex,
|
|
6681
|
+
snapshot.slicing?.[name]
|
|
6454
6682
|
);
|
|
6455
6683
|
}
|
|
6456
6684
|
for (const inheritedName of snapshot.inheritedRequiredFields ?? []) {
|
|
@@ -6544,7 +6772,7 @@ var collectProfileFactoryInfo2 = (tsIndex, snapshot) => {
|
|
|
6544
6772
|
continue;
|
|
6545
6773
|
}
|
|
6546
6774
|
if (isNotChoiceDeclarationField(field)) {
|
|
6547
|
-
const sliceNames = collectRequiredSliceNames2(field);
|
|
6775
|
+
const sliceNames = collectRequiredSliceNames2(field, snapshot.slicing?.[name]);
|
|
6548
6776
|
if (sliceNames) {
|
|
6549
6777
|
if (field.type) {
|
|
6550
6778
|
const tsType = fieldTsType(field, resolveRef, isFamilyType);
|
|
@@ -6644,6 +6872,7 @@ var generateProfileHelpersImport = (w, tsIndex, snapshot, sliceDefs, factoryInfo
|
|
|
6644
6872
|
"validateEnum",
|
|
6645
6873
|
"validateReference",
|
|
6646
6874
|
"validateChoiceRequired",
|
|
6875
|
+
"validateChoiceProhibited",
|
|
6647
6876
|
"validateMustSupport"
|
|
6648
6877
|
);
|
|
6649
6878
|
if (imports.length > 0) {
|
|
@@ -7666,6 +7895,10 @@ var APIBuilder = class {
|
|
|
7666
7895
|
assert4(this.options.typeSchema.treeShake === void 0, "treeShake option is already set");
|
|
7667
7896
|
this.options.typeSchema.treeShake = cfg.treeShake;
|
|
7668
7897
|
}
|
|
7898
|
+
if (cfg.treeShakeDefaults) {
|
|
7899
|
+
assert4(this.options.typeSchema.treeShakeDefaults === void 0, "treeShakeDefaults option is already set");
|
|
7900
|
+
this.options.typeSchema.treeShakeDefaults = cfg.treeShakeDefaults;
|
|
7901
|
+
}
|
|
7669
7902
|
if (cfg.promoteLogical) {
|
|
7670
7903
|
assert4(this.options.typeSchema.promoteLogical === void 0, "promoteLogical option is already set");
|
|
7671
7904
|
this.options.typeSchema.promoteLogical = cfg.promoteLogical;
|
|
@@ -7740,7 +7973,12 @@ var APIBuilder = class {
|
|
|
7740
7973
|
};
|
|
7741
7974
|
const tsIndexOpts = { register, irReport, logger: tsLogger };
|
|
7742
7975
|
let tsIndex = mkTypeSchemaIndex(typeSchemas, tsIndexOpts);
|
|
7743
|
-
if (this.options.typeSchema?.treeShake)
|
|
7976
|
+
if (this.options.typeSchema?.treeShake)
|
|
7977
|
+
tsIndex = treeShake(
|
|
7978
|
+
tsIndex,
|
|
7979
|
+
this.options.typeSchema.treeShake,
|
|
7980
|
+
this.options.typeSchema.treeShakeDefaults
|
|
7981
|
+
);
|
|
7744
7982
|
if (this.options.typeSchema?.promoteLogical)
|
|
7745
7983
|
tsIndex = promoteLogical(tsIndex, this.options.typeSchema.promoteLogical);
|
|
7746
7984
|
tsLogger.printTagSummary();
|