@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/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
- for (const [declName, declField] of Object.entries(result)) {
1202
- if (!isChoiceDeclarationField(declField) || declField.excluded) continue;
1203
- for (const cSchema of constraintSchemas) {
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 permitted = new Set(declField.excluded ? [] : declField.choices);
1217
- const prohibited = Object.entries(result).filter(
1218
- (e) => isChoiceInstanceField(e[1]) && e[1].choiceOf === declName
1219
- ).filter(([name]) => !permitted.has(name)).map(([name]) => name);
1220
- if (prohibited.length > 0) result[declName] = { ...declField, prohibited };
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(mergedFields, constraintSchemas);
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(w, ext, className, baseName, targetPath, valueField, extProfileInfo);
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, "Any", targetPath, extProfileInfo, () => {
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 || !field.slicing?.slices) return void 0;
1618
- if (field.slicing.discriminator?.some((d) => d.type === "type")) return void 0;
1619
- const names = Object.entries(field.slicing.slices).filter(([_, s]) => s.min !== void 0 && s.min >= 1 && s.match && Object.keys(s.match).length > 0).map(([name]) => name);
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 = (isTypeDiscriminated, rawMatch) => {
1652
- if (!isTypeDiscriminated || !rawMatch) return void 0;
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.fields).flatMap(([fieldName, field]) => {
1664
- if (!isNotChoiceDeclarationField(field) || !field.slicing?.slices || !field.type) return [];
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(field.slicing.slices).filter(([_, slice]) => Object.keys(slice.match ?? {}).length > 0).map(([sliceName, slice]) => {
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 isTypeDiscriminated = field.slicing?.discriminator?.some((d) => d.type === "type") ?? false;
1765
+ const typeDiscriminated = isTypeDiscriminated(fieldSlicing);
1680
1766
  const typeDiscriminatorResource = extractTypeDiscriminatorResource(
1681
- isTypeDiscriminated,
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(`merged = ${sliceDef.elementTypeName}(**merged)`);
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("set_array_slice(items, match, merged)");
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)}, merged)`);
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
- const base = pyTypeFromIdentifier(resolved);
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 tryPromoteChoice = (field, fields, params, promotedChoices) => {
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 = pyTypeFromIdentifier(choiceField.type) + (choiceField.array ? "[]" : "");
1845
- params.push({ name: choiceName, pyType, typeId: choiceField.type });
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 = pyTypeFromIdentifier(field.type) + (field.array ? "[]" : "");
2034
+ const pyType = pyChoiceInstanceType(field, tsIndex);
1926
2035
  const choiceSiblings = (choiceGroups.get(name) ?? []).filter((s) => s !== name && !promotedChoices.has(s));
1927
- choiceAccessors.push({ name, pyType, typeId: field.type, choiceSiblings });
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 collectValidateBody = (flatProfile, resolveRef, errorLines, warningLines, formatName2) => {
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.push(
2060
- `errors.extend(validate_choice_required(self._resource, profile_name, ${JSON.stringify(pyChoices)}))`
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
- if (field.excluded) {
2066
- helpers.add("validate_excluded");
2067
- errorLines.push(
2068
- `errors.extend(validate_excluded(self._resource, profile_name, ${JSON.stringify(pyName)}))`
2069
- );
2070
- continue;
2071
- }
2072
- if (field.required) {
2073
- helpers.add("validate_required");
2074
- errorLines.push(
2075
- `errors.extend(validate_required(self._resource, profile_name, ${JSON.stringify(pyName)}))`
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.valueConstraint) {
2079
- helpers.add("validate_fixed_value");
2080
- const value = JSON.stringify(field.valueConstraint.value);
2081
- errorLines.push(
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 (isNotChoiceDeclarationField(field)) {
2086
- if (field.enum) {
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 collectProhibitedChoiceValidation = (fields, name, pyName, helpers, errorLines) => {
2115
- const field = fields[name];
2116
- if (!field || !isChoiceInstanceField(field)) return;
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
- const min = slice.min ?? 0;
2129
- const max = slice.max ?? 0;
2130
- helpers.add("validate_slice_cardinality");
2131
- errorLines.push(
2132
- `errors.extend(validate_slice_cardinality(self._resource, profile_name, ${JSON.stringify(name)}, ${JSON.stringify(match)}, ${JSON.stringify(sliceName)}, ${min}, ${max}))`
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
- if (hasChildren) {
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.fields ?? {}).flatMap(([fieldName, field]) => {
3350
- if (!("slicing" in field) || !field.slicing?.slices) return [];
3351
- return Object.entries(field.slicing.slices).map(([sliceName, slice]) => ({
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, field] of Object.entries(profile.fields ?? {})) {
3366
- if (!("slicing" in field) || !field.slicing?.slices) continue;
3367
- for (const [sliceName, slice] of Object.entries(field.slicing.slices)) {
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: pkgIndex.pkg.name,
3575
- package_version: pkgIndex.pkg.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
- return element.refers.map((ref) => {
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
- return mkIdentifier(fs6);
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 void 0;
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.values(versions).sort((a, b) => b.sources.length - a.sources.length);
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 treeShake = (tsIndex, treeShake2) => {
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 name = normalizeFileName(`${ts.identifier.name}(${extractNameFromCanonical(ts.identifier.url)})`);
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
- if (Path5.extname(this.opts.typeSchemas) === ".ndjson") {
4702
- await this.writeNdjson(tsIndex.schemas, this.opts.typeSchemas, typeSchemaToJson);
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 = tsIndex.schemas.map((ts) => typeSchemaToJson(ts, true));
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(this.opts.typeSchemas, () => {
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 = JSON.stringify(entry.typeSchema);
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.values()].sort((a, b) => b.length - a.length);
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 resolved = field.reference.map((ref) => resolveRef ? resolveRef(ref) : ref);
5774
- const references = resolved.map((ref) => isFamilyType?.(ref) ? `string /* ${ref.name} */` : `"${ref.name}"`).join(" | ");
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
- if (!extensionField || isChoiceDeclarationField(extensionField) || !extensionField.slicing?.slices) return [];
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(extensionField.slicing.slices)) {
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 field of Object.values(snapshot.fields)) {
6164
- if (!isNotChoiceDeclarationField(field) || !field.slicing?.slices || !field.type) continue;
6165
- const isTypeDisc = field.slicing.discriminator?.some((d) => d.type === "type") ?? false;
6166
- for (const slice of Object.values(field.slicing.slices)) {
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 || !field.slicing?.slices) return void 0;
6186
- const isTypeDisc = field.slicing.discriminator?.some((d) => d.type === "type") ?? false;
6187
- if (isTypeDisc) return void 0;
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.fields).filter(([_, field]) => isNotChoiceDeclarationField(field) && field.slicing?.slices).flatMap(([fieldName, field]) => {
6197
- if (!isNotChoiceDeclarationField(field) || !field.slicing?.slices || !field.type) return [];
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 = field.slicing.discriminator?.some((d) => d.type === "type") ?? false;
6202
- return Object.entries(field.slicing.slices).filter(([_, slice]) => Object.keys(slice.match ?? {}).length > 0).map(([sliceName, slice]) => {
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 collectRegularFieldValidation = (errors, warnings, name, field, resolveRef, canonicalUrlExpr, tsIndex) => {
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 (field.slicing?.slices) {
6397
- for (const [sliceName, slice] of Object.entries(field.slicing.slices)) {
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
- collectRegularFieldValidation(
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) tsIndex = treeShake(tsIndex, 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();