@atomic-ehr/codegen 0.0.15 → 0.0.16

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
@@ -110,8 +110,9 @@ function mkLogger(opts = {}) {
110
110
  var mkCodegenLogger = (opts = {}) => mkLogger(opts);
111
111
 
112
112
  // src/api/writer-generator/utils.ts
113
+ var WORD_SPLIT_RE = /(?<=[a-z])(?=[A-Z])|[-_.\s]/;
113
114
  var words = (s) => {
114
- return s.split(/(?<=[a-z])(?=[A-Z])|[-_.\s]/).filter(Boolean);
115
+ return s.split(WORD_SPLIT_RE).filter(Boolean);
115
116
  };
116
117
  var kebabCase = (s) => {
117
118
  return words(s).map((s2) => s2.toLowerCase()).join("-");
@@ -294,9 +295,8 @@ var Writer = class extends FileSystemWriter {
294
295
  tokens = tokens.map((token) => {
295
296
  if (typeof token === "string") {
296
297
  return token;
297
- } else {
298
- return JSON.stringify(token, null, 2);
299
298
  }
299
+ return JSON.stringify(token, null, 2);
300
300
  });
301
301
  this.comment(...tokens);
302
302
  }
@@ -334,6 +334,7 @@ var Writer = class extends FileSystemWriter {
334
334
  this.line(`]${endTokens?.filter(Boolean).join(" ") ?? ""}`);
335
335
  }
336
336
  };
337
+ var LEADING_DIGIT_RE = /^\d/;
337
338
  var extractNameFromCanonical = (canonical, dropFragment = true) => {
338
339
  let localName = canonical.split("/").pop();
339
340
  if (!localName) return void 0;
@@ -341,7 +342,7 @@ var extractNameFromCanonical = (canonical, dropFragment = true) => {
341
342
  localName = localName.split("#")[0];
342
343
  }
343
344
  if (!localName) return void 0;
344
- if (/^\d/.test(localName)) {
345
+ if (LEADING_DIGIT_RE.test(localName)) {
345
346
  localName = `number_${localName}`;
346
347
  }
347
348
  return localName;
@@ -505,9 +506,8 @@ var resolveCSharpAssets = (fn) => {
505
506
  const __dirname = Path5__default.dirname(__filename);
506
507
  if (__filename.endsWith("dist/index.js")) {
507
508
  return Path5__default.resolve(__dirname, "..", "assets", "api", "writer-generator", "csharp", fn);
508
- } else {
509
- return Path5__default.resolve(__dirname, "../../../..", "assets", "api", "writer-generator", "csharp", fn);
510
509
  }
510
+ return Path5__default.resolve(__dirname, "../../../..", "assets", "api", "writer-generator", "csharp", fn);
511
511
  };
512
512
  var PRIMITIVE_TYPE_MAP = {
513
513
  boolean: "bool",
@@ -543,13 +543,14 @@ var formatClassName = (schema) => {
543
543
  var formatBaseClass = (schema) => {
544
544
  return schema.base ? `: ${schema.base.name}` : "";
545
545
  };
546
+ var LEADING_DIGIT_RE2 = /^\d/;
546
547
  var canonicalToName = (canonical, dropFragment = true) => {
547
548
  if (!canonical) return void 0;
548
549
  let localName = canonical.split("/").pop();
549
550
  if (!localName) return void 0;
550
551
  if (dropFragment && localName.includes("#")) localName = localName.split("#")[0];
551
552
  if (!localName) return void 0;
552
- if (/^\d/.test(localName)) {
553
+ if (LEADING_DIGIT_RE2.test(localName)) {
553
554
  localName = `number_${localName}`;
554
555
  }
555
556
  return formatName(localName);
@@ -781,6 +782,116 @@ var CSharp = class extends Writer {
781
782
  fs__default.copyFileSync(sourceFile, destFile);
782
783
  }
783
784
  };
785
+
786
+ // src/api/writer-generator/python/naming-utils.ts
787
+ var PRIMITIVE_TYPE_MAP2 = {
788
+ boolean: "bool",
789
+ instant: "str",
790
+ time: "str",
791
+ date: "str",
792
+ dateTime: "str",
793
+ decimal: "float",
794
+ integer: "int",
795
+ unsignedInt: "int",
796
+ positiveInt: "PositiveInt",
797
+ integer64: "int",
798
+ base64Binary: "str",
799
+ uri: "str",
800
+ url: "str",
801
+ canonical: "str",
802
+ oid: "str",
803
+ uuid: "str",
804
+ string: "str",
805
+ code: "str",
806
+ markdown: "str",
807
+ id: "str",
808
+ xhtml: "str"
809
+ };
810
+ var PYTHON_KEYWORDS = /* @__PURE__ */ new Set([
811
+ "False",
812
+ "None",
813
+ "True",
814
+ "and",
815
+ "as",
816
+ "assert",
817
+ "async",
818
+ "await",
819
+ "break",
820
+ "class",
821
+ "continue",
822
+ "def",
823
+ "del",
824
+ "elif",
825
+ "else",
826
+ "except",
827
+ "finally",
828
+ "for",
829
+ "from",
830
+ "global",
831
+ "if",
832
+ "import",
833
+ "in",
834
+ "is",
835
+ "lambda",
836
+ "nonlocal",
837
+ "not",
838
+ "or",
839
+ "pass",
840
+ "raise",
841
+ "return",
842
+ "try",
843
+ "while",
844
+ "with",
845
+ "yield"
846
+ ]);
847
+ var fixReservedWords = (name) => {
848
+ return PYTHON_KEYWORDS.has(name) ? `${name}_` : name;
849
+ };
850
+ var canonicalToName2 = (canonical, dropFragment = true) => {
851
+ if (!canonical) return void 0;
852
+ let localName = canonical.split("/").pop();
853
+ if (!localName) return void 0;
854
+ if (dropFragment && localName.includes("#")) {
855
+ localName = localName.split("#")[0];
856
+ }
857
+ if (!localName) return void 0;
858
+ if (/^\d/.test(localName)) {
859
+ localName = `number_${localName}`;
860
+ }
861
+ return snakeCase(localName);
862
+ };
863
+ var deriveResourceName = (id) => {
864
+ if (id.kind === "nested") {
865
+ const url = id.url;
866
+ const path = canonicalToName2(url, false);
867
+ if (!path) return "";
868
+ const [resourceName, fragment] = path.split("#");
869
+ const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
870
+ return pascalCase([resourceName, name].join(""));
871
+ }
872
+ return pascalCase(id.name);
873
+ };
874
+ var buildPyPackageName = (packageName) => {
875
+ const parts = packageName ? [snakeCase(packageName)] : [""];
876
+ return parts.join(".");
877
+ };
878
+ var pyFhirPackageByName = (rootPackageName, name) => [rootPackageName, buildPyPackageName(name)].join(".");
879
+ var pyFhirPackage = (rootPackageName, identifier) => pyFhirPackageByName(rootPackageName, identifier.package);
880
+ var pyPackage = (rootPackageName, identifier) => {
881
+ if (identifier.kind === "complex-type") {
882
+ return `${pyFhirPackage(rootPackageName, identifier)}.base`;
883
+ }
884
+ if (identifier.kind === "resource") {
885
+ return [pyFhirPackage(rootPackageName, identifier), snakeCase(identifier.name)].join(".");
886
+ }
887
+ return pyFhirPackage(rootPackageName, identifier);
888
+ };
889
+ var pyTypeFromIdentifier = (id) => {
890
+ if (isPrimitiveIdentifier(id)) return PRIMITIVE_TYPE_MAP2[id.name] ?? "str";
891
+ const prim = PRIMITIVE_TYPE_MAP2[id.name];
892
+ if (prim !== void 0) return prim;
893
+ return deriveResourceName(id);
894
+ };
784
895
  var groupByPackages = (typeSchemas) => {
785
896
  const grouped = {};
786
897
  for (const ts of typeSchemas) {
@@ -1202,180 +1313,1193 @@ var mkTypeSchemaIndex = (schemas, {
1202
1313
  allChoiceNames: field.choices
1203
1314
  };
1204
1315
  }
1205
- return void 0;
1206
- };
1207
- const isWithMetaField = (profile) => {
1208
- const genealogy = tryHierarchy(profile);
1209
- if (!genealogy) return false;
1210
- return genealogy.filter(isSpecializationTypeSchema).some((schema) => {
1211
- return schema.fields?.meta !== void 0;
1316
+ return void 0;
1317
+ };
1318
+ const isWithMetaField = (profile) => {
1319
+ const genealogy = tryHierarchy(profile);
1320
+ if (!genealogy) return false;
1321
+ return genealogy.filter(isSpecializationTypeSchema).some((schema) => {
1322
+ return schema.fields?.meta !== void 0;
1323
+ });
1324
+ };
1325
+ const entityTree = () => {
1326
+ const tree = {};
1327
+ for (const [pkgId, shemas] of Object.entries(groupByPackages(schemas))) {
1328
+ tree[pkgId] = {
1329
+ "primitive-type": {},
1330
+ "complex-type": {},
1331
+ resource: {},
1332
+ "value-set": {},
1333
+ nested: {},
1334
+ binding: {},
1335
+ profile: {},
1336
+ "profile-snapshot": {},
1337
+ logical: {}
1338
+ };
1339
+ for (const schema of shemas) {
1340
+ tree[pkgId][schema.identifier.kind][schema.identifier.url] = {};
1341
+ }
1342
+ }
1343
+ return tree;
1344
+ };
1345
+ const exportTree = async (filename) => {
1346
+ const tree = entityTree();
1347
+ const raw = filename.endsWith(".yaml") ? YAML.stringify(tree) : JSON.stringify(tree, void 0, 2);
1348
+ await fsPromises.mkdir(Path5.dirname(filename), { recursive: true });
1349
+ await fsPromises.writeFile(filename, raw);
1350
+ };
1351
+ return {
1352
+ _schemaIndex: index,
1353
+ schemas,
1354
+ schemasByPackage: groupByPackages(schemas),
1355
+ register,
1356
+ collectComplexTypes: () => schemas.filter(isComplexTypeTypeSchema),
1357
+ collectResources: () => schemas.filter(isResourceTypeSchema),
1358
+ collectLogicalModels: () => schemas.filter(isLogicalTypeSchema),
1359
+ collectProfiles: () => schemas.filter(isProfileTypeSchema),
1360
+ collectSnapshotProfiles,
1361
+ resolve: resolve6,
1362
+ resolveType,
1363
+ resolveByUrl,
1364
+ tryHierarchy,
1365
+ hierarchy,
1366
+ findLastSpecialization,
1367
+ findLastSpecializationByIdentifier,
1368
+ flatProfile,
1369
+ constrainedChoice,
1370
+ isWithMetaField,
1371
+ entityTree,
1372
+ exportTree,
1373
+ irReport: () => irReport,
1374
+ replaceSchemas: (newSchemas) => mkTypeSchemaIndex(newSchemas, { register, logger, irReport: { ...irReport } })
1375
+ };
1376
+ };
1377
+
1378
+ // src/api/writer-generator/python/profile-naming.ts
1379
+ var normalizePyName = (n) => {
1380
+ let out = n.replace(/\[x\]/g, "_x_").replace(/[- :./]/g, "_");
1381
+ if (PYTHON_KEYWORDS.has(out)) out = `${out}_`;
1382
+ if (/^\d/.test(out)) out = `_${out}`;
1383
+ return out;
1384
+ };
1385
+ var pySnakeName = (name) => {
1386
+ if (!name) return "";
1387
+ const cleaned = name.replace(/\[x\]/g, "").replace(/[:./]/g, "_");
1388
+ return snakeCase(cleaned);
1389
+ };
1390
+ var pyFieldName = (n, formatName2 = snakeCase) => {
1391
+ const cleaned = n.replace(/\[x\]/g, "").replace(/[:./]/g, "_");
1392
+ const out = formatName2(cleaned);
1393
+ return PYTHON_KEYWORDS.has(out) ? `${out}_` : out;
1394
+ };
1395
+ var pyProfileClassName = (schema) => {
1396
+ const name = pascalCase(normalizePyName(schema.identifier.name));
1397
+ if (schema.base.name === "Extension") {
1398
+ return name.endsWith("Extension") ? name : `${name}Extension`;
1399
+ }
1400
+ return name.endsWith("Profile") ? name : `${name}Profile`;
1401
+ };
1402
+ var pyProfileModuleName = (tsIndex, schema) => {
1403
+ const baseSchema = tsIndex.findLastSpecialization(schema);
1404
+ const baseName = snakeCase(normalizePyName(baseSchema.identifier.name));
1405
+ const profileName = snakeCase(normalizePyName(schema.identifier.name));
1406
+ return `${baseName}_${profileName}`;
1407
+ };
1408
+ var pySliceStaticName = (name) => {
1409
+ const cleaned = name.replace(/\[x]/g, "").replace(/[^a-zA-Z0-9_]/g, "_");
1410
+ return `_${snakeCase(cleaned)}_slice_match`;
1411
+ };
1412
+ var pyValueFieldName = (id, formatName2 = snakeCase) => formatName2(`value${pascalCase(normalizePyName(id.name))}`);
1413
+ var resolveProfileMethodBaseNames = (extensions, sliceDefs) => {
1414
+ const extensionsRecord = {};
1415
+ for (const ext of extensions) {
1416
+ if (!ext.url) continue;
1417
+ extensionsRecord[`${ext.url}:${ext.path}`] = snakeCase(ext.nameCandidates.recommended);
1418
+ }
1419
+ const slicesRecord = {};
1420
+ for (const s of sliceDefs) {
1421
+ slicesRecord[`${s.fieldName}:${s.sliceName}`] = snakeCase(s.nameCandidates.recommended);
1422
+ }
1423
+ const allBaseNames = /* @__PURE__ */ new Set([...Object.values(extensionsRecord), ...Object.values(slicesRecord)]);
1424
+ return { extensions: extensionsRecord, slices: slicesRecord, allBaseNames };
1425
+ };
1426
+
1427
+ // src/api/writer-generator/python/profile-extensions.ts
1428
+ var resolveExtensionProfile = (tsIndex, pkgName, ext) => {
1429
+ if (ext.profile) {
1430
+ const schema2 = tsIndex.resolve(ext.profile);
1431
+ if (schema2) {
1432
+ return {
1433
+ className: pyProfileClassName(schema2),
1434
+ moduleName: pyProfileModuleName(tsIndex, schema2)
1435
+ };
1436
+ }
1437
+ }
1438
+ if (!ext.url) return void 0;
1439
+ const schema = tsIndex.resolveByUrl(pkgName, ext.url);
1440
+ if (!schema || !isProfileTypeSchema(schema)) return void 0;
1441
+ if (schema.identifier.package !== pkgName) return void 0;
1442
+ return {
1443
+ className: pyProfileClassName(schema),
1444
+ moduleName: pyProfileModuleName(tsIndex, schema)
1445
+ };
1446
+ };
1447
+ var generateExtensionMethods = (w, tsIndex, flatProfile, className, extensionBaseNames) => {
1448
+ const pkgName = flatProfile.identifier.package;
1449
+ for (const ext of flatProfile.extensions ?? []) {
1450
+ if (!ext.url) continue;
1451
+ const baseName = extensionBaseNames[`${ext.url}:${ext.path}`] ?? snakeCase(ext.nameCandidates.recommended);
1452
+ const targetPath = ext.path.split(".").filter((segment) => segment !== "extension");
1453
+ const extProfileInfo = resolveExtensionProfile(tsIndex, pkgName, ext);
1454
+ if (ext.isComplex && ext.subExtensions) {
1455
+ generateComplexExtensionGetter(w, ext, baseName, targetPath, extProfileInfo);
1456
+ generateComplexExtensionSetter(w, ext, className, baseName, targetPath, extProfileInfo);
1457
+ } else if (ext.valueFieldTypes?.length === 1 && ext.valueFieldTypes[0]) {
1458
+ const valueType = ext.valueFieldTypes[0];
1459
+ const valueField = pyValueFieldName(valueType, w.nameFormatFunction);
1460
+ const pyType = pyTypeFromIdentifier(valueType);
1461
+ generateSingleValueExtensionGetter(w, ext, baseName, targetPath, valueField, pyType, extProfileInfo);
1462
+ generateSingleValueExtensionSetter(w, ext, className, baseName, targetPath, valueField, extProfileInfo);
1463
+ } else {
1464
+ generateGenericExtensionGetter(w, ext, baseName, targetPath, extProfileInfo);
1465
+ generateGenericExtensionSetter(w, ext, className, baseName, targetPath, extProfileInfo);
1466
+ }
1467
+ }
1468
+ };
1469
+ var emitExtLookup = (w, ext, targetPath) => {
1470
+ if (targetPath.length === 0) {
1471
+ w.line(`exts = getattr(self._resource, "extension", None) or []`);
1472
+ } else {
1473
+ w.line(
1474
+ `target = ensure_path(self._resource.model_dump(by_alias=True, exclude_none=True) if hasattr(self._resource, "model_dump") else self._resource, ${JSON.stringify(targetPath)})`
1475
+ );
1476
+ w.line(`exts = target.get("extension", []) if isinstance(target, dict) else []`);
1477
+ }
1478
+ w.line(`ext = next((e for e in exts if is_extension(e, ${JSON.stringify(ext.url)})), None)`);
1479
+ };
1480
+ var emitExtPush = (w, targetPath, extExpr) => {
1481
+ if (targetPath.length === 0) {
1482
+ w.line(`push_extension(self._resource, ${extExpr})`);
1483
+ } else {
1484
+ w.line(`target = ensure_path(self._resource, ${JSON.stringify(targetPath)})`);
1485
+ w.line(`push_extension(target, ${extExpr})`);
1486
+ }
1487
+ };
1488
+ var emitGetterOverloads = (w, methodName, flatPyType, extProfileInfo) => {
1489
+ const profileClass = extProfileInfo?.className;
1490
+ w.line("@overload");
1491
+ w.line(`def ${methodName}(self) -> ${flatPyType} | None: ...`);
1492
+ w.line("@overload");
1493
+ w.line(`def ${methodName}(self, mode: Literal["raw"]) -> Extension | None: ...`);
1494
+ if (profileClass) {
1495
+ w.line("@overload");
1496
+ w.line(`def ${methodName}(self, mode: Literal["profile"]) -> ${profileClass} | None: ...`);
1497
+ }
1498
+ const modeType = profileClass ? `Literal["raw", "profile"] | None` : `Literal["raw"] | None`;
1499
+ const returnUnion = profileClass ? `${flatPyType} | Extension | ${profileClass} | None` : `${flatPyType} | Extension | None`;
1500
+ w.line(`def ${methodName}(self, mode: ${modeType} = None) -> ${returnUnion}:`);
1501
+ };
1502
+ var emitGetterModeDispatch = (w, extProfileInfo) => {
1503
+ w.line("ext_obj = ext if not isinstance(ext, dict) else Extension(**ext)");
1504
+ w.line(`if mode == "raw":`);
1505
+ w.indentBlock(() => w.line("return ext_obj"));
1506
+ if (extProfileInfo) {
1507
+ w.line(`if mode == "profile":`);
1508
+ w.indentBlock(() => w.line(`return ${extProfileInfo.className}.apply(ext_obj)`));
1509
+ }
1510
+ };
1511
+ var emitSetterDispatchPreamble = (w, ext, targetPath, extProfileInfo) => {
1512
+ let startedChain = false;
1513
+ if (extProfileInfo) {
1514
+ w.line(`if isinstance(value, ${extProfileInfo.className}):`);
1515
+ w.indentBlock(() => emitExtPush(w, targetPath, "value.to_resource()"));
1516
+ startedChain = true;
1517
+ }
1518
+ const keyword = startedChain ? "elif" : "if";
1519
+ w.line(`${keyword} is_extension(value):`);
1520
+ w.indentBlock(() => {
1521
+ w.line(`if _get_key(value, "url") != ${JSON.stringify(ext.url)}:`);
1522
+ w.indentBlock(
1523
+ () => w.line(`raise ValueError(f"Expected extension url '${ext.url}', got {_get_key(value, 'url')!r}")`)
1524
+ );
1525
+ emitExtPush(w, targetPath, "value");
1526
+ });
1527
+ };
1528
+ var buildSetterParamType = (flatType, extProfileInfo) => {
1529
+ const parts = [];
1530
+ if (extProfileInfo) parts.push(extProfileInfo.className);
1531
+ parts.push("Extension", flatType);
1532
+ return `"${parts.join(" | ")}"`;
1533
+ };
1534
+ var generateExtensionGetter = (w, ext, baseName, flatPyType, targetPath, extProfileInfo, emitFlatReturn) => {
1535
+ emitGetterOverloads(w, `get_${baseName}`, flatPyType, extProfileInfo);
1536
+ w.indentBlock(() => {
1537
+ emitExtLookup(w, ext, targetPath);
1538
+ w.line("if ext is None:");
1539
+ w.indentBlock(() => w.line("return None"));
1540
+ emitGetterModeDispatch(w, extProfileInfo);
1541
+ emitFlatReturn();
1542
+ });
1543
+ w.line();
1544
+ };
1545
+ var generateComplexExtensionGetter = (w, ext, baseName, targetPath, extProfileInfo) => {
1546
+ generateExtensionGetter(w, ext, baseName, "dict[str, Any]", targetPath, extProfileInfo, () => {
1547
+ const configItems = (ext.subExtensions ?? []).map((sub) => {
1548
+ const valueField = sub.valueFieldType ? pyValueFieldName(sub.valueFieldType, w.nameFormatFunction) : "value";
1549
+ const isArray = sub.max === "*";
1550
+ return `{"name": ${JSON.stringify(sub.url)}, "valueField": ${JSON.stringify(valueField)}, "isArray": ${isArray ? "True" : "False"}}`;
1551
+ });
1552
+ w.line(`config = [${configItems.join(", ")}]`);
1553
+ w.line("return extract_complex_extension(ext, config)");
1554
+ });
1555
+ };
1556
+ var generateExtensionSetter = (w, ext, className, baseName, flatParamType, targetPath, extProfileInfo, emitElseBody) => {
1557
+ const paramType = buildSetterParamType(flatParamType, extProfileInfo);
1558
+ w.line(`def set_${baseName}(self, value: ${paramType}) -> "${className}":`);
1559
+ w.indentBlock(() => {
1560
+ emitSetterDispatchPreamble(w, ext, targetPath, extProfileInfo);
1561
+ w.line("else:");
1562
+ w.indentBlock(emitElseBody);
1563
+ w.line("return self");
1564
+ });
1565
+ w.line();
1566
+ };
1567
+ var generateComplexExtensionSetter = (w, ext, className, baseName, targetPath, extProfileInfo) => {
1568
+ generateExtensionSetter(w, ext, className, baseName, "dict[str, Any]", targetPath, extProfileInfo, () => {
1569
+ w.line("sub_extensions = []");
1570
+ for (const sub of ext.subExtensions ?? []) {
1571
+ const valueField = sub.valueFieldType ? pyValueFieldName(sub.valueFieldType, w.nameFormatFunction) : "value";
1572
+ if (sub.max === "*") {
1573
+ w.line(`for item in value.get(${JSON.stringify(sub.url)}, []):`);
1574
+ w.indentBlock(() => {
1575
+ w.line(
1576
+ `sub_extensions.append({"url": ${JSON.stringify(sub.url)}, ${JSON.stringify(valueField)}: item})`
1577
+ );
1578
+ });
1579
+ } else {
1580
+ w.line(`if value.get(${JSON.stringify(sub.url)}) is not None:`);
1581
+ w.indentBlock(() => {
1582
+ w.line(
1583
+ `sub_extensions.append({"url": ${JSON.stringify(sub.url)}, ${JSON.stringify(valueField)}: value[${JSON.stringify(sub.url)}]})`
1584
+ );
1585
+ });
1586
+ }
1587
+ }
1588
+ const extObj = `Extension(url=${JSON.stringify(ext.url)}, extension=sub_extensions)`;
1589
+ emitExtPush(w, targetPath, extObj);
1590
+ });
1591
+ };
1592
+ var generateSingleValueExtensionGetter = (w, ext, baseName, targetPath, valueField, pyType, extProfileInfo) => {
1593
+ generateExtensionGetter(w, ext, baseName, pyType, targetPath, extProfileInfo, () => {
1594
+ w.line(`return cast('${pyType} | None', get_extension_value(ext, ${JSON.stringify(valueField)}))`);
1595
+ });
1596
+ };
1597
+ var generateSingleValueExtensionSetter = (w, ext, className, baseName, targetPath, valueField, extProfileInfo) => {
1598
+ generateExtensionSetter(w, ext, className, baseName, "Any", targetPath, extProfileInfo, () => {
1599
+ emitExtPush(w, targetPath, `Extension(url=${JSON.stringify(ext.url)}, ${valueField}=value)`);
1600
+ });
1601
+ };
1602
+ var generateGenericExtensionGetter = (w, ext, baseName, targetPath, extProfileInfo) => {
1603
+ generateExtensionGetter(w, ext, baseName, "dict[str, Any]", targetPath, extProfileInfo, () => {
1604
+ w.line(
1605
+ 'return cast("dict[str, Any] | None", ext if isinstance(ext, dict) else ext.model_dump(by_alias=True, exclude_none=True))'
1606
+ );
1607
+ });
1608
+ };
1609
+ var generateGenericExtensionSetter = (w, ext, className, baseName, targetPath, extProfileInfo) => {
1610
+ generateExtensionSetter(w, ext, className, baseName, "dict[str, Any]", targetPath, extProfileInfo, () => {
1611
+ emitExtPush(w, targetPath, `{"url": ${JSON.stringify(ext.url)}, **value}`);
1612
+ });
1613
+ };
1614
+
1615
+ // 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);
1620
+ return names.length > 0 ? names : void 0;
1621
+ };
1622
+ var generateStaticSliceFields = (w, sliceDefs) => {
1623
+ for (const sliceDef of sliceDefs) {
1624
+ const staticName = pySliceStaticName(sliceDef.sliceName);
1625
+ w.line(`${staticName}: dict[str, Any] = ${JSON.stringify(sliceDef.match)}`);
1626
+ }
1627
+ if (sliceDefs.length > 0) w.line();
1628
+ };
1629
+ var normalizeMatchForPython = (tsIndex, match, schema) => {
1630
+ if (!schema || !("fields" in schema) || !schema.fields) return match;
1631
+ const result = {};
1632
+ for (const [key, value] of Object.entries(match)) {
1633
+ const fieldDef = schema.fields[key];
1634
+ if (!fieldDef || !isNotChoiceDeclarationField(fieldDef)) {
1635
+ result[key] = value;
1636
+ continue;
1637
+ }
1638
+ const nestedSchema = fieldDef.type ? tsIndex.resolveType(fieldDef.type) : void 0;
1639
+ const normalizeOne = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? normalizeMatchForPython(tsIndex, v, nestedSchema) : v;
1640
+ if (Array.isArray(value)) {
1641
+ result[key] = value.map(normalizeOne);
1642
+ } else if (value !== null && typeof value === "object") {
1643
+ const normalized = normalizeOne(value);
1644
+ result[key] = fieldDef.array ? [normalized] : normalized;
1645
+ } else {
1646
+ result[key] = value;
1647
+ }
1648
+ }
1649
+ return result;
1650
+ };
1651
+ var extractTypeDiscriminatorResource = (isTypeDiscriminated, rawMatch) => {
1652
+ if (!isTypeDiscriminated || !rawMatch) return void 0;
1653
+ for (const val of Object.values(rawMatch)) {
1654
+ if (val !== null && typeof val === "object" && !Array.isArray(val)) {
1655
+ const rt = val.resourceType;
1656
+ if (typeof rt === "string") return rt;
1657
+ }
1658
+ }
1659
+ return void 0;
1660
+ };
1661
+ var collectSliceDefs = (tsIndex, flatProfile) => {
1662
+ const pkgName = flatProfile.identifier.package;
1663
+ return Object.entries(flatProfile.fields).flatMap(([fieldName, field]) => {
1664
+ if (!isNotChoiceDeclarationField(field) || !field.slicing?.slices || !field.type) return [];
1665
+ const choiceBaseNames = /* @__PURE__ */ new Set();
1666
+ const baseSchema = tsIndex.resolveType(field.type);
1667
+ if (baseSchema && "fields" in baseSchema && baseSchema.fields) {
1668
+ for (const [n, f] of Object.entries(baseSchema.fields)) {
1669
+ if (isChoiceDeclarationField(f)) choiceBaseNames.add(n);
1670
+ }
1671
+ }
1672
+ return Object.entries(field.slicing.slices).filter(([_, slice]) => Object.keys(slice.match ?? {}).length > 0).map(([sliceName, slice]) => {
1673
+ const matchFields = Object.keys(slice.match ?? {});
1674
+ const required = (slice.required ?? []).filter(
1675
+ (name) => !matchFields.includes(name) && !choiceBaseNames.has(name)
1676
+ );
1677
+ const cc = slice.elements ? tsIndex.constrainedChoice(pkgName, field.type, slice.elements) : void 0;
1678
+ const constrainedChoice = cc && !isPrimitiveIdentifier(cc.variantType) ? cc : void 0;
1679
+ const isTypeDiscriminated = field.slicing?.discriminator?.some((d) => d.type === "type") ?? false;
1680
+ const typeDiscriminatorResource = extractTypeDiscriminatorResource(
1681
+ isTypeDiscriminated,
1682
+ slice.match
1683
+ );
1684
+ return {
1685
+ fieldName,
1686
+ sliceName,
1687
+ match: normalizeMatchForPython(tsIndex, slice.match ?? {}, baseSchema),
1688
+ required,
1689
+ array: Boolean(field.array),
1690
+ max: slice.max ?? 0,
1691
+ constrainedChoice,
1692
+ elementTypeName: field.type && !isPrimitiveIdentifier(field.type) ? pyTypeFromIdentifier(field.type) : void 0,
1693
+ elementTypeId: field.type && !isPrimitiveIdentifier(field.type) ? field.type : void 0,
1694
+ isTypeDiscriminated,
1695
+ typeDiscriminatorResource,
1696
+ nameCandidates: slice.nameCandidates
1697
+ };
1698
+ });
1699
+ });
1700
+ };
1701
+ var sliceElementRetType = (sliceDef) => sliceDef.elementTypeName && sliceDef.typeDiscriminatorResource ? `${sliceDef.elementTypeName}[${sliceDef.typeDiscriminatorResource}]` : sliceDef.elementTypeName ?? "Any";
1702
+ var generateSliceGetters = (w, sliceDefs, sliceBaseNames) => {
1703
+ for (const sliceDef of sliceDefs) {
1704
+ const baseName = sliceBaseNames[`${sliceDef.fieldName}:${sliceDef.sliceName}`] ?? sliceDef.nameCandidates.recommended;
1705
+ const staticName = pySliceStaticName(sliceDef.sliceName);
1706
+ const fieldName = pyFieldName(sliceDef.fieldName, w.nameFormatFunction);
1707
+ const matchKeys = JSON.stringify(Object.keys(sliceDef.match));
1708
+ if (sliceDef.isTypeDiscriminated) {
1709
+ const retType = sliceElementRetType(sliceDef);
1710
+ const isUnbounded = sliceDef.array && sliceDef.max === 0;
1711
+ if (isUnbounded) {
1712
+ w.line(`def get_${baseName}(self, mode: str | None = None) -> list[${retType}] | None:`);
1713
+ w.indentBlock(() => {
1714
+ w.line(`match = self.__class__.${staticName}`);
1715
+ w.line(
1716
+ `result = get_array_slices(getattr(self._resource, ${JSON.stringify(fieldName)}, None), match)`
1717
+ );
1718
+ w.line(`return cast('list[${retType}] | None', result or None)`);
1719
+ });
1720
+ } else {
1721
+ w.line(`def get_${baseName}(self, mode: str | None = None) -> ${retType} | None:`);
1722
+ w.indentBlock(() => {
1723
+ w.line(`match = self.__class__.${staticName}`);
1724
+ w.line(
1725
+ `return cast('${retType} | None', get_array_slice(getattr(self._resource, ${JSON.stringify(fieldName)}, None), match))`
1726
+ );
1727
+ });
1728
+ }
1729
+ } else {
1730
+ const flatRetType = "dict[str, Any]";
1731
+ const rawRetType = sliceDef.elementTypeName ?? "Any";
1732
+ w.line("@overload");
1733
+ w.line(`def get_${baseName}(self) -> ${flatRetType} | None: ...`);
1734
+ w.line("@overload");
1735
+ w.line(`def get_${baseName}(self, mode: Literal["raw"]) -> ${rawRetType} | None: ...`);
1736
+ w.line(
1737
+ `def get_${baseName}(self, mode: Literal["raw"] | None = None) -> ${flatRetType} | ${rawRetType} | None:`
1738
+ );
1739
+ w.indentBlock(() => {
1740
+ w.line(`match = self.__class__.${staticName}`);
1741
+ if (sliceDef.array) {
1742
+ w.line(
1743
+ `item = get_array_slice(getattr(self._resource, ${JSON.stringify(fieldName)}, None), match)`
1744
+ );
1745
+ } else {
1746
+ w.line(`item = getattr(self._resource, ${JSON.stringify(fieldName)}, None)`);
1747
+ w.line("if item is None or not matches_value(item, match):");
1748
+ w.indentBlock(() => {
1749
+ w.line("return None");
1750
+ });
1751
+ }
1752
+ w.line('if mode == "raw":');
1753
+ w.indentBlock(() => {
1754
+ w.line(`return cast('${rawRetType} | None', item)`);
1755
+ });
1756
+ w.line(
1757
+ "item_dict = item if isinstance(item, dict) else item.model_dump(by_alias=True, exclude_none=True)"
1758
+ );
1759
+ if (sliceDef.constrainedChoice) {
1760
+ const variant = JSON.stringify(sliceDef.constrainedChoice.variant);
1761
+ w.line(`return unwrap_slice_choice(item_dict, ${matchKeys}, ${variant})`);
1762
+ } else {
1763
+ w.line(`return strip_match_keys(item_dict, ${matchKeys})`);
1764
+ }
1765
+ });
1766
+ }
1767
+ w.line();
1768
+ }
1769
+ };
1770
+ var generateSliceSetters = (w, className, sliceDefs, sliceBaseNames) => {
1771
+ for (const sliceDef of sliceDefs) {
1772
+ const baseName = sliceBaseNames[`${sliceDef.fieldName}:${sliceDef.sliceName}`] ?? sliceDef.nameCandidates.recommended;
1773
+ const staticName = pySliceStaticName(sliceDef.sliceName);
1774
+ const fieldName = pyFieldName(sliceDef.fieldName, w.nameFormatFunction);
1775
+ if (sliceDef.isTypeDiscriminated) {
1776
+ const retType = sliceElementRetType(sliceDef);
1777
+ const isUnbounded = sliceDef.array && sliceDef.max === 0;
1778
+ if (isUnbounded) {
1779
+ w.line(`def set_${baseName}(self, values: list[${retType}]) -> "${className}":`);
1780
+ w.indentBlock(() => {
1781
+ w.line(`match = self.__class__.${staticName}`);
1782
+ w.line(`items = list(getattr(self._resource, ${JSON.stringify(fieldName)}, None) or [])`);
1783
+ w.line("set_array_slices(items, match, values)");
1784
+ w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, items)`);
1785
+ w.line("return self");
1786
+ });
1787
+ } else {
1788
+ w.line(`def set_${baseName}(self, value: ${retType} | None = None) -> "${className}":`);
1789
+ w.indentBlock(() => {
1790
+ w.line(`match = self.__class__.${staticName}`);
1791
+ w.line(`items = getattr(self._resource, ${JSON.stringify(fieldName)}, None) or []`);
1792
+ w.line("set_array_slice(items, match, value)");
1793
+ w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, items)`);
1794
+ w.line("return self");
1795
+ });
1796
+ }
1797
+ } else {
1798
+ const inputOptional = sliceDef.required.length === 0;
1799
+ const sig = inputOptional ? `def set_${baseName}(self, value: dict[str, Any] | None = None) -> "${className}":` : `def set_${baseName}(self, value: dict[str, Any]) -> "${className}":`;
1800
+ w.line(sig);
1801
+ w.indentBlock(() => {
1802
+ w.line(`match = self.__class__.${staticName}`);
1803
+ const inputExpr = inputOptional ? "(value or {})" : "value";
1804
+ if (sliceDef.constrainedChoice) {
1805
+ const variant = JSON.stringify(sliceDef.constrainedChoice.variant);
1806
+ w.line(`wrapped = wrap_slice_choice(${inputExpr}, ${variant})`);
1807
+ w.line("merged = apply_slice_match(wrapped, match)");
1808
+ } else {
1809
+ w.line(`merged = apply_slice_match(${inputExpr}, match)`);
1810
+ }
1811
+ if (sliceDef.elementTypeName) {
1812
+ w.line(`merged = ${sliceDef.elementTypeName}(**merged)`);
1813
+ }
1814
+ if (sliceDef.array) {
1815
+ w.line(`items = getattr(self._resource, ${JSON.stringify(fieldName)}, None) or []`);
1816
+ w.line("set_array_slice(items, match, merged)");
1817
+ w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, items)`);
1818
+ } else {
1819
+ w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, merged)`);
1820
+ }
1821
+ w.line("return self");
1822
+ });
1823
+ }
1824
+ w.line();
1825
+ }
1826
+ };
1827
+
1828
+ // src/api/writer-generator/python/profile-factory.ts
1829
+ var fieldPyType = (field, resolveRef) => {
1830
+ const resolved = resolveRef ? resolveRef(field.type) : field.type;
1831
+ const base = pyTypeFromIdentifier(resolved);
1832
+ if (base === "str" && field.enum && !field.enum.isOpen && field.enum.values.length > 0) {
1833
+ const literal = `Literal[${field.enum.values.map((v) => JSON.stringify(v)).join(", ")}]`;
1834
+ return field.array ? `list[${literal}]` : literal;
1835
+ }
1836
+ return field.array ? `list[${base}]` : base;
1837
+ };
1838
+ var tryPromoteChoice = (field, fields, params, promotedChoices) => {
1839
+ if (!isChoiceDeclarationField(field) || !field.required || field.choices.length !== 1) return;
1840
+ const choiceName = field.choices[0];
1841
+ if (!choiceName) return;
1842
+ const choiceField = fields[choiceName];
1843
+ if (!choiceField || !isChoiceInstanceField(choiceField)) return;
1844
+ const pyType = pyTypeFromIdentifier(choiceField.type) + (choiceField.array ? "[]" : "");
1845
+ params.push({ name: choiceName, pyType, typeId: choiceField.type });
1846
+ promotedChoices.add(choiceName);
1847
+ };
1848
+ var collectBaseRequiredParams = (tsIndex, flatProfile, resolveRef, params, coveredNames) => {
1849
+ const covered = new Set(coveredNames);
1850
+ const baseSchema = tsIndex.resolveType(flatProfile.base);
1851
+ if (!baseSchema || !("fields" in baseSchema) || !baseSchema.fields) return;
1852
+ for (const [name, field] of Object.entries(baseSchema.fields)) {
1853
+ if (covered.has(name)) continue;
1854
+ if (!field.required) continue;
1855
+ if (isChoiceInstanceField(field)) continue;
1856
+ if (isChoiceDeclarationField(field)) continue;
1857
+ if (isNotChoiceDeclarationField(field) && field.type) {
1858
+ const pyType = fieldPyType(field, resolveRef);
1859
+ params.push({ name, pyType, typeId: field.type });
1860
+ }
1861
+ }
1862
+ };
1863
+ var collectProfileFactoryInfo = (tsIndex, flatProfile) => {
1864
+ const autoFields = [];
1865
+ const sliceAutoFields = [];
1866
+ const params = [];
1867
+ const autoAccessors = [];
1868
+ const pendingChoiceInstances = [];
1869
+ const fields = flatProfile.fields;
1870
+ const promotedChoices = /* @__PURE__ */ new Set();
1871
+ const resolveRef = tsIndex.findLastSpecializationByIdentifier;
1872
+ const choiceGroups = /* @__PURE__ */ new Map();
1873
+ for (const [, field] of Object.entries(fields)) {
1874
+ if (isChoiceDeclarationField(field)) {
1875
+ for (const choice of field.choices) choiceGroups.set(choice, field.choices);
1876
+ }
1877
+ }
1878
+ if (isResourceIdentifier(flatProfile.base)) {
1879
+ autoFields.push({ name: "resourceType", value: JSON.stringify(flatProfile.base.name) });
1880
+ }
1881
+ for (const [name, field] of Object.entries(fields)) {
1882
+ if (field.excluded) continue;
1883
+ if (isChoiceInstanceField(field)) {
1884
+ pendingChoiceInstances.push([name, field]);
1885
+ continue;
1886
+ }
1887
+ if (isChoiceDeclarationField(field)) {
1888
+ tryPromoteChoice(field, fields, params, promotedChoices);
1889
+ continue;
1890
+ }
1891
+ if (field.valueConstraint) {
1892
+ const value = JSON.stringify(field.valueConstraint.value);
1893
+ autoFields.push({ name, value: field.array ? `[${value}]` : value });
1894
+ if (isNotChoiceDeclarationField(field) && field.type) {
1895
+ const pyType = fieldPyType(field, resolveRef);
1896
+ autoAccessors.push({ name, pyType, typeId: field.type });
1897
+ }
1898
+ continue;
1899
+ }
1900
+ if (isNotChoiceDeclarationField(field)) {
1901
+ const sliceNames = collectRequiredSliceNames(field);
1902
+ if (sliceNames) {
1903
+ if (field.type) {
1904
+ const pyType = fieldPyType(field, resolveRef);
1905
+ sliceAutoFields.push({ name, pyType, typeId: field.type, sliceNames });
1906
+ autoAccessors.push({ name, pyType, typeId: field.type });
1907
+ }
1908
+ continue;
1909
+ }
1910
+ }
1911
+ if (field.required) {
1912
+ const pyType = fieldPyType(field, resolveRef);
1913
+ params.push({ name, pyType, typeId: field.type });
1914
+ }
1915
+ }
1916
+ collectBaseRequiredParams(tsIndex, flatProfile, resolveRef, params, [
1917
+ ...autoFields.map((f) => f.name),
1918
+ ...sliceAutoFields.map((f) => f.name),
1919
+ ...params.map((f) => f.name),
1920
+ ...promotedChoices
1921
+ ]);
1922
+ const choiceAccessors = [];
1923
+ for (const [name, field] of pendingChoiceInstances) {
1924
+ if (promotedChoices.has(name)) continue;
1925
+ const pyType = pyTypeFromIdentifier(field.type) + (field.array ? "[]" : "");
1926
+ const choiceSiblings = (choiceGroups.get(name) ?? []).filter((s) => s !== name && !promotedChoices.has(s));
1927
+ choiceAccessors.push({ name, pyType, typeId: field.type, choiceSiblings });
1928
+ }
1929
+ return { autoFields, sliceAutoFields, params, accessors: [...autoAccessors, ...choiceAccessors] };
1930
+ };
1931
+ var buildParamSignature = (factoryInfo, formatName2) => {
1932
+ const parts = [];
1933
+ for (const f of factoryInfo.sliceAutoFields) {
1934
+ parts.push(`${pyFieldName(f.name, formatName2)}: ${f.pyType} | None = None`);
1935
+ }
1936
+ for (const p of factoryInfo.params) {
1937
+ parts.push(`${pyFieldName(p.name, formatName2)}: ${p.pyType}`);
1938
+ }
1939
+ if (parts.length === 0) return "";
1940
+ return `*, ${parts.join(", ")}`;
1941
+ };
1942
+ var buildCallArgs = (factoryInfo, formatName2) => {
1943
+ const parts = [];
1944
+ for (const f of factoryInfo.sliceAutoFields) {
1945
+ const name = pyFieldName(f.name, formatName2);
1946
+ parts.push(`${name}=${name}`);
1947
+ }
1948
+ for (const p of factoryInfo.params) {
1949
+ const name = pyFieldName(p.name, formatName2);
1950
+ parts.push(`${name}=${name}`);
1951
+ }
1952
+ return parts.join(", ");
1953
+ };
1954
+ var generateCreateResource = (w, baseTypeName, annotatedBaseTypeName, isResourceBase, hasParams, factoryInfo) => {
1955
+ const fmt = w.nameFormatFunction;
1956
+ w.line("@classmethod");
1957
+ if (hasParams) {
1958
+ w.line(`def create_resource(cls, ${buildParamSignature(factoryInfo, fmt)}) -> ${annotatedBaseTypeName}:`);
1959
+ } else {
1960
+ w.line(`def create_resource(cls) -> ${annotatedBaseTypeName}:`);
1961
+ }
1962
+ w.indentBlock(() => {
1963
+ for (const f of factoryInfo.sliceAutoFields) {
1964
+ const fieldName = pyFieldName(f.name, fmt);
1965
+ const matchRefs = f.sliceNames.map((s) => `cls.${pySliceStaticName(s)}`);
1966
+ if (matchRefs.length === 1) {
1967
+ w.line(`${fieldName}_with_defaults = ensure_slice_defaults(list(${fieldName} or []), ${matchRefs[0]})`);
1968
+ } else {
1969
+ w.line(`${fieldName}_with_defaults = ensure_slice_defaults(`);
1970
+ w.indentBlock(() => {
1971
+ w.line(`list(${fieldName} or []),`);
1972
+ for (const ref of matchRefs) w.line(`${ref},`);
1973
+ });
1974
+ w.line(")");
1975
+ }
1976
+ }
1977
+ if (factoryInfo.sliceAutoFields.length > 0) w.line();
1978
+ const buildArgs = [];
1979
+ for (const f of factoryInfo.autoFields) {
1980
+ buildArgs.push(`${pyFieldName(f.name, fmt)}=${f.value}`);
1981
+ }
1982
+ for (const f of factoryInfo.sliceAutoFields) {
1983
+ buildArgs.push(`${pyFieldName(f.name, fmt)}=${pyFieldName(f.name, fmt)}_with_defaults`);
1984
+ }
1985
+ for (const p of factoryInfo.params) {
1986
+ buildArgs.push(`${pyFieldName(p.name, fmt)}=${pyFieldName(p.name, fmt)}`);
1987
+ }
1988
+ if (isResourceBase) {
1989
+ buildArgs.push(`meta={"profile": [cls.canonical_url]}`);
1990
+ }
1991
+ if (buildArgs.length <= 2) {
1992
+ w.line(`return build_resource(${baseTypeName}, ${buildArgs.join(", ")})`);
1993
+ } else {
1994
+ w.line(`return build_resource(`);
1995
+ w.indentBlock(() => {
1996
+ w.line(`${baseTypeName},`);
1997
+ for (const arg of buildArgs) {
1998
+ w.line(`${arg},`);
1999
+ }
2000
+ });
2001
+ w.line(")");
2002
+ }
2003
+ });
2004
+ };
2005
+ var generateFieldAccessors = (w, className, factoryInfo, extSliceMethodBaseNames) => {
2006
+ const fmt = w.nameFormatFunction;
2007
+ for (const p of factoryInfo.params) {
2008
+ const fieldName = pyFieldName(p.name, fmt);
2009
+ const methodSuffix = pySnakeName(p.name);
2010
+ w.line(`def get_${methodSuffix}(self) -> ${p.pyType} | None:`);
2011
+ w.indentBlock(() => {
2012
+ w.line(`return cast('${p.pyType} | None', getattr(self._resource, ${JSON.stringify(fieldName)}, None))`);
2013
+ });
2014
+ w.line();
2015
+ w.line(`def set_${methodSuffix}(self, value: ${p.pyType}) -> "${className}":`);
2016
+ w.indentBlock(() => {
2017
+ w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, value)`);
2018
+ w.line("return self");
2019
+ });
2020
+ w.line();
2021
+ }
2022
+ for (const a of factoryInfo.accessors) {
2023
+ const methodSuffix = pySnakeName(a.name);
2024
+ if (extSliceMethodBaseNames.has(methodSuffix)) continue;
2025
+ const fieldName = pyFieldName(a.name, fmt);
2026
+ w.line(`def get_${methodSuffix}(self) -> ${a.pyType} | None:`);
2027
+ w.indentBlock(() => {
2028
+ w.line(`return cast('${a.pyType} | None', getattr(self._resource, ${JSON.stringify(fieldName)}, None))`);
2029
+ });
2030
+ w.line();
2031
+ w.line(`def set_${methodSuffix}(self, value: ${a.pyType}) -> "${className}":`);
2032
+ w.indentBlock(() => {
2033
+ if (a.choiceSiblings?.length) {
2034
+ for (const sibling of a.choiceSiblings) {
2035
+ w.line(`setattr(self._resource, ${JSON.stringify(pyFieldName(sibling, fmt))}, None)`);
2036
+ }
2037
+ }
2038
+ w.line(`setattr(self._resource, ${JSON.stringify(fieldName)}, value)`);
2039
+ w.line("return self");
2040
+ });
2041
+ w.line();
2042
+ }
2043
+ };
2044
+
2045
+ // src/api/writer-generator/python/profile-validation.ts
2046
+ var collectValidateBody = (flatProfile, resolveRef, errorLines, warningLines, formatName2) => {
2047
+ const helpers = /* @__PURE__ */ new Set();
2048
+ const fields = flatProfile.fields;
2049
+ for (const [name, field] of Object.entries(fields)) {
2050
+ const pyName = pyFieldName(name, formatName2);
2051
+ if (isChoiceInstanceField(field)) {
2052
+ collectProhibitedChoiceValidation(fields, name, pyName, helpers, errorLines);
2053
+ continue;
2054
+ }
2055
+ if (isChoiceDeclarationField(field)) {
2056
+ if (field.required) {
2057
+ helpers.add("validate_choice_required");
2058
+ 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
+ );
2062
+ }
2063
+ continue;
2064
+ }
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)}))`
2076
+ );
2077
+ }
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
+ );
2084
+ }
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
+ }
2110
+ }
2111
+ }
2112
+ return helpers;
2113
+ };
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;
2126
+ const match = slice.match ?? {};
2127
+ 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
+ );
2134
+ }
2135
+ };
2136
+
2137
+ // src/api/writer-generator/python/profile.ts
2138
+ var modulePathForTypeId = (rootPackageName, typeId) => {
2139
+ const pkg = pyFhirPackageByName(rootPackageName, typeId.package);
2140
+ if (isResourceIdentifier(typeId)) return `${pkg}.${snakeCase(typeId.name)}`;
2141
+ if (isNestedIdentifier(typeId)) {
2142
+ const path = canonicalToName2(typeId.url, false);
2143
+ const parentName = path?.split("#")[0];
2144
+ return parentName ? `${pkg}.${snakeCase(parentName)}` : `${pkg}.base`;
2145
+ }
2146
+ return `${pkg}.base`;
2147
+ };
2148
+ var addExactTypeImport = (typeImports, rootPackageName, skipName, typeId) => {
2149
+ if (isPrimitiveIdentifier(typeId) || PRIMITIVE_TYPE_MAP2[typeId.name] !== void 0) return;
2150
+ const name = deriveResourceName(typeId);
2151
+ if (!name || name === skipName) return;
2152
+ const modulePath = modulePathForTypeId(rootPackageName, typeId);
2153
+ const names = typeImports.get(modulePath) ?? /* @__PURE__ */ new Set();
2154
+ names.add(name);
2155
+ typeImports.set(modulePath, names);
2156
+ };
2157
+ var addTypeImport = (typeImports, rootPackageName, skipName, resolveRef, typeId) => {
2158
+ const ids = [typeId];
2159
+ const resolved = resolveRef(typeId);
2160
+ if (resolved !== typeId) ids.push(resolved);
2161
+ for (const id of ids) {
2162
+ if (isPrimitiveIdentifier(id) || PRIMITIVE_TYPE_MAP2[id.name] !== void 0) continue;
2163
+ const name = deriveResourceName(id);
2164
+ if (name === skipName) continue;
2165
+ const modulePath = modulePathForTypeId(rootPackageName, id);
2166
+ let names = typeImports.get(modulePath);
2167
+ if (!names) {
2168
+ names = /* @__PURE__ */ new Set();
2169
+ typeImports.set(modulePath, names);
2170
+ }
2171
+ names.add(name);
2172
+ }
2173
+ };
2174
+ var collectHelperImports = (isResourceBase, factoryInfo, sliceDefs, extensions, validationHelpers) => {
2175
+ const imports = ["build_resource"];
2176
+ if (isResourceBase) imports.push("ensure_profile");
2177
+ if (factoryInfo.sliceAutoFields.length > 0) imports.push("ensure_slice_defaults");
2178
+ if (sliceDefs.length > 0) {
2179
+ const hasNonTyped = sliceDefs.some((s) => !s.isTypeDiscriminated);
2180
+ const hasTypedBounded = sliceDefs.some((s) => s.isTypeDiscriminated && !(s.array && s.max === 0));
2181
+ const hasTypedUnbounded = sliceDefs.some((s) => s.isTypeDiscriminated && s.array && s.max === 0);
2182
+ if (hasNonTyped) imports.push("apply_slice_match", "matches_value", "strip_match_keys");
2183
+ if (hasTypedBounded || hasNonTyped) imports.push("get_array_slice", "set_array_slice");
2184
+ if (hasTypedUnbounded) imports.push("get_array_slices", "set_array_slices");
2185
+ if (sliceDefs.some((s) => s.constrainedChoice)) imports.push("wrap_slice_choice", "unwrap_slice_choice");
2186
+ }
2187
+ if (extensions.length > 0) {
2188
+ imports.push("_get_key", "is_extension", "get_extension_value", "push_extension");
2189
+ if (extensions.some((ext) => ext.isComplex && ext.subExtensions)) imports.push("extract_complex_extension");
2190
+ if (extensions.some((ext) => ext.path.split(".").some((s) => s !== "extension"))) imports.push("ensure_path");
2191
+ }
2192
+ imports.push(...validationHelpers);
2193
+ imports.sort();
2194
+ return imports;
2195
+ };
2196
+ var collectTypeImports = (rootPackageName, baseTypeName, resolveRef, factoryInfo, sliceDefs, extensions, schemas) => {
2197
+ const typeImports = /* @__PURE__ */ new Map();
2198
+ for (const p of factoryInfo.params) addTypeImport(typeImports, rootPackageName, baseTypeName, resolveRef, p.typeId);
2199
+ for (const f of factoryInfo.sliceAutoFields)
2200
+ addTypeImport(typeImports, rootPackageName, baseTypeName, resolveRef, f.typeId);
2201
+ for (const a of factoryInfo.accessors)
2202
+ addTypeImport(typeImports, rootPackageName, baseTypeName, resolveRef, a.typeId);
2203
+ for (const s of sliceDefs) {
2204
+ if (s.elementTypeId) addExactTypeImport(typeImports, rootPackageName, baseTypeName, s.elementTypeId);
2205
+ if (!s.isTypeDiscriminated) continue;
2206
+ if (!s.typeDiscriminatorResource) continue;
2207
+ const resourceId = schemas.find(
2208
+ (schema) => schema.identifier.kind === "resource" && schema.identifier.name === s.typeDiscriminatorResource
2209
+ )?.identifier;
2210
+ if (resourceId) addTypeImport(typeImports, rootPackageName, baseTypeName, resolveRef, resourceId);
2211
+ }
2212
+ for (const ext of extensions) {
2213
+ if (ext.isComplex && ext.subExtensions) continue;
2214
+ if (ext.valueFieldTypes?.length === 1 && ext.valueFieldTypes[0])
2215
+ addExactTypeImport(typeImports, rootPackageName, baseTypeName, ext.valueFieldTypes[0]);
2216
+ }
2217
+ return typeImports;
2218
+ };
2219
+ var collectExtProfileImports = (tsIndex, flatProfile, extensions) => {
2220
+ const extProfileImports = /* @__PURE__ */ new Map();
2221
+ for (const ext of extensions) {
2222
+ if (!ext.url) continue;
2223
+ const info = resolveExtensionProfile(tsIndex, flatProfile.identifier.package, ext);
2224
+ if (info && !extProfileImports.has(info.className)) extProfileImports.set(info.className, info);
2225
+ }
2226
+ return extProfileImports;
2227
+ };
2228
+ var emitModuleImports = (w, flatProfile, isResourceBase, extensions, factoryInfo, typeImports, extProfileImports, helperImports, sliceDefs) => {
2229
+ w.line("from __future__ import annotations");
2230
+ w.line();
2231
+ const usesLiteral = [...factoryInfo.params, ...factoryInfo.accessors, ...factoryInfo.sliceAutoFields].some(
2232
+ (f) => f.pyType.includes("Literal[")
2233
+ );
2234
+ const hasNonTypedSlice = sliceDefs.some((s) => !s.isTypeDiscriminated);
2235
+ const needsOverload = extensions.length > 0 || hasNonTypedSlice;
2236
+ const needsAny = extensions.length > 0 || sliceDefs.length > 0;
2237
+ const needsCast = factoryInfo.params.length > 0 || factoryInfo.accessors.length > 0 || sliceDefs.length > 0 || extensions.length > 0;
2238
+ const typingNames = [];
2239
+ if (needsAny) typingNames.push("Any");
2240
+ if (needsCast) typingNames.push("cast");
2241
+ if (needsOverload || usesLiteral) typingNames.push("Literal");
2242
+ if (needsOverload) typingNames.push("overload");
2243
+ if (typingNames.length > 0) {
2244
+ w.pyImportFrom("typing", ...[...typingNames].sort());
2245
+ w.line();
2246
+ }
2247
+ const baseTypeName = flatProfile.base.name;
2248
+ const basePkg = pyFhirPackageByName(w.opts.rootPackageName, flatProfile.base.package);
2249
+ if (isResourceBase) {
2250
+ w.pyImportFrom(`${basePkg}.${snakeCase(baseTypeName)}`, baseTypeName);
2251
+ } else {
2252
+ w.pyImportFrom(`${basePkg}.base`, baseTypeName);
2253
+ }
2254
+ if (extensions.length > 0) w.pyImportFrom(`${basePkg}.base`, "Extension");
2255
+ for (const [modulePath, names] of [...typeImports.entries()].sort(([a], [b]) => a.localeCompare(b))) {
2256
+ w.pyImportFrom(modulePath, ...[...names].sort());
2257
+ }
2258
+ for (const [extClassName, info] of [...extProfileImports.entries()].sort(([a], [b]) => a.localeCompare(b))) {
2259
+ w.pyImportFrom(`.${info.moduleName}`, extClassName);
2260
+ }
2261
+ w.pyImportFrom(`${w.opts.rootPackageName}.profile_helpers`, ...helperImports);
2262
+ w.line();
2263
+ w.line();
2264
+ };
2265
+ var generateFromResourceMethod = (w, annotatedBaseTypeName, className, isResourceBase) => {
2266
+ w.line("@classmethod");
2267
+ w.line(`def from_resource(cls, resource: ${annotatedBaseTypeName}) -> "${className}":`);
2268
+ w.indentBlock(() => {
2269
+ if (isResourceBase) {
2270
+ w.line('meta = getattr(resource, "meta", None)');
2271
+ w.line('profiles = getattr(meta, "profile", None) if meta is not None else None');
2272
+ w.line("if profiles is None or cls.canonical_url not in profiles:");
2273
+ w.indentBlock(() => {
2274
+ w.line(`raise ValueError(f"${className}: meta.profile must include {cls.canonical_url}")`);
2275
+ });
2276
+ }
2277
+ w.line("profile = cls(resource)");
2278
+ w.line("result = profile.validate()");
2279
+ w.line('if result["errors"]:');
2280
+ w.indentBlock(() => w.line('raise ValueError("; ".join(result["errors"]))'));
2281
+ w.line("return profile");
2282
+ });
2283
+ w.line();
2284
+ };
2285
+ var generateApplyMethod = (w, annotatedBaseTypeName, className, isResourceBase) => {
2286
+ w.line("@classmethod");
2287
+ w.line(`def apply(cls, resource: ${annotatedBaseTypeName}) -> "${className}":`);
2288
+ w.indentBlock(() => {
2289
+ if (isResourceBase) w.line("ensure_profile(resource, cls.canonical_url)");
2290
+ w.line("return cls(resource)");
2291
+ });
2292
+ w.line();
2293
+ };
2294
+ var generateCreateMethod = (w, className, hasParams, factoryInfo) => {
2295
+ w.line("@classmethod");
2296
+ if (hasParams) {
2297
+ w.line(`def create(cls, ${buildParamSignature(factoryInfo, w.nameFormatFunction)}) -> "${className}":`);
2298
+ w.indentBlock(
2299
+ () => w.line(`return cls.apply(cls.create_resource(${buildCallArgs(factoryInfo, w.nameFormatFunction)}))`)
2300
+ );
2301
+ } else {
2302
+ w.line(`def create(cls) -> "${className}":`);
2303
+ w.indentBlock(() => w.line("return cls.apply(cls.create_resource())"));
2304
+ }
2305
+ w.line();
2306
+ };
2307
+ var generateValidateMethod = (w, className, errorLines, warningLines) => {
2308
+ w.line("def validate(self) -> dict[str, list[str]]:");
2309
+ w.indentBlock(() => {
2310
+ w.line(`profile_name = "${className}"`);
2311
+ w.line("errors: list[str] = []");
2312
+ w.line("warnings: list[str] = []");
2313
+ for (const expr of errorLines) w.line(expr);
2314
+ for (const expr of warningLines) w.line(expr);
2315
+ w.line('return {"errors": errors, "warnings": warnings}');
2316
+ });
2317
+ };
2318
+ var generateClassBody = (ctx) => {
2319
+ const {
2320
+ w,
2321
+ tsIndex,
2322
+ flatProfile,
2323
+ baseTypeName,
2324
+ annotatedBaseTypeName,
2325
+ className,
2326
+ isResourceBase,
2327
+ errorLines,
2328
+ warningLines,
2329
+ factoryInfo,
2330
+ sliceDefs,
2331
+ resolvedNames
2332
+ } = ctx;
2333
+ const hasParams = factoryInfo.params.length > 0 || factoryInfo.sliceAutoFields.length > 0;
2334
+ w.line(`def __init__(self, resource: ${annotatedBaseTypeName}) -> None:`);
2335
+ w.indentBlock(() => w.line("self._resource = resource"));
2336
+ w.line();
2337
+ generateFromResourceMethod(w, annotatedBaseTypeName, className, isResourceBase);
2338
+ generateApplyMethod(w, annotatedBaseTypeName, className, isResourceBase);
2339
+ generateCreateResource(w, baseTypeName, annotatedBaseTypeName, isResourceBase, hasParams, factoryInfo);
2340
+ w.line();
2341
+ generateCreateMethod(w, className, hasParams, factoryInfo);
2342
+ w.line(`def to_resource(self) -> ${annotatedBaseTypeName}:`);
2343
+ w.indentBlock(() => w.line("return self._resource"));
2344
+ w.line();
2345
+ if (factoryInfo.params.length > 0 || factoryInfo.accessors.length > 0)
2346
+ generateFieldAccessors(w, className, factoryInfo, resolvedNames.allBaseNames);
2347
+ const extensions = flatProfile.extensions ?? [];
2348
+ if (extensions.length > 0) generateExtensionMethods(w, tsIndex, flatProfile, className, resolvedNames.extensions);
2349
+ if (sliceDefs.length > 0) {
2350
+ generateSliceGetters(w, sliceDefs, resolvedNames.slices);
2351
+ generateSliceSetters(w, className, sliceDefs, resolvedNames.slices);
2352
+ }
2353
+ generateValidateMethod(w, className, errorLines, warningLines);
2354
+ };
2355
+ var generateProfileModule = (w, tsIndex, flatProfile) => {
2356
+ const className = pyProfileClassName(flatProfile);
2357
+ const baseTypeName = flatProfile.base.name;
2358
+ const isResourceBase = isResourceIdentifier(flatProfile.base);
2359
+ const canonicalUrl = flatProfile.identifier.url ?? "";
2360
+ const factoryInfo = collectProfileFactoryInfo(tsIndex, flatProfile);
2361
+ const sliceDefs = collectSliceDefs(tsIndex, flatProfile);
2362
+ const typedResources = [
2363
+ ...new Set(
2364
+ sliceDefs.filter((s) => s.isTypeDiscriminated && s.typeDiscriminatorResource).map((s) => s.typeDiscriminatorResource)
2365
+ )
2366
+ ];
2367
+ const annotatedBaseTypeName = typedResources.length > 0 ? `${baseTypeName}[${typedResources.join(" | ")}, Resource]` : baseTypeName;
2368
+ const extensions = flatProfile.extensions ?? [];
2369
+ const resolvedNames = resolveProfileMethodBaseNames(extensions, sliceDefs);
2370
+ const errorLines = [];
2371
+ const warningLines = [];
2372
+ const validationHelpers = collectValidateBody(
2373
+ flatProfile,
2374
+ tsIndex.findLastSpecializationByIdentifier,
2375
+ errorLines,
2376
+ warningLines,
2377
+ w.nameFormatFunction
2378
+ );
2379
+ const helperImports = collectHelperImports(isResourceBase, factoryInfo, sliceDefs, extensions, validationHelpers);
2380
+ const typeImports = collectTypeImports(
2381
+ w.opts.rootPackageName,
2382
+ baseTypeName,
2383
+ tsIndex.findLastSpecializationByIdentifier,
2384
+ factoryInfo,
2385
+ sliceDefs,
2386
+ extensions,
2387
+ tsIndex.schemas
2388
+ );
2389
+ const extProfileImports = collectExtProfileImports(tsIndex, flatProfile, extensions);
2390
+ if (typedResources.length > 0) {
2391
+ const basePkg = pyFhirPackageByName(w.opts.rootPackageName, flatProfile.base.package);
2392
+ const resourceModule = `${basePkg}.resource`;
2393
+ const names = typeImports.get(resourceModule) ?? /* @__PURE__ */ new Set();
2394
+ names.add("Resource");
2395
+ typeImports.set(resourceModule, names);
2396
+ }
2397
+ emitModuleImports(
2398
+ w,
2399
+ flatProfile,
2400
+ isResourceBase,
2401
+ extensions,
2402
+ factoryInfo,
2403
+ typeImports,
2404
+ extProfileImports,
2405
+ helperImports,
2406
+ sliceDefs
2407
+ );
2408
+ w.line(`class ${className}:`);
2409
+ w.indentBlock(() => {
2410
+ if (flatProfile.description) {
2411
+ w.line(`"""${flatProfile.description}`);
2412
+ w.line();
2413
+ w.line(`CanonicalURL: ${canonicalUrl}`);
2414
+ w.line(`"""`);
2415
+ w.line();
2416
+ }
2417
+ w.line(`canonical_url: str = ${JSON.stringify(canonicalUrl)}`);
2418
+ w.line();
2419
+ generateStaticSliceFields(w, sliceDefs);
2420
+ generateClassBody({
2421
+ w,
2422
+ tsIndex,
2423
+ flatProfile,
2424
+ baseTypeName,
2425
+ annotatedBaseTypeName,
2426
+ className,
2427
+ isResourceBase,
2428
+ factoryInfo,
2429
+ sliceDefs,
2430
+ resolvedNames,
2431
+ errorLines,
2432
+ warningLines
2433
+ });
2434
+ });
2435
+ w.line();
2436
+ };
2437
+ var generateProfilesInit = (w, tsIndex, profiles) => {
2438
+ w.cat("__init__.py", () => {
2439
+ w.generateDisclaimer();
2440
+ const seen = /* @__PURE__ */ new Set();
2441
+ for (const profile of profiles) {
2442
+ const className = pyProfileClassName(profile);
2443
+ const moduleName = pyProfileModuleName(tsIndex, profile);
2444
+ if (seen.has(className)) continue;
2445
+ seen.add(className);
2446
+ w.pyImportFrom(`.${moduleName}`, className);
2447
+ }
2448
+ w.line();
2449
+ w.squareBlock(["__all__", "="], () => {
2450
+ for (const className of [...seen].sort()) w.line(`'${className}',`);
1212
2451
  });
1213
- };
1214
- const entityTree = () => {
1215
- const tree = {};
1216
- for (const [pkgId, shemas] of Object.entries(groupByPackages(schemas))) {
1217
- tree[pkgId] = {
1218
- "primitive-type": {},
1219
- "complex-type": {},
1220
- resource: {},
1221
- "value-set": {},
1222
- nested: {},
1223
- binding: {},
1224
- profile: {},
1225
- "profile-snapshot": {},
1226
- logical: {}
1227
- };
1228
- for (const schema of shemas) {
1229
- tree[pkgId][schema.identifier.kind][schema.identifier.url] = {};
1230
- }
2452
+ });
2453
+ };
2454
+ var generateNewProfiles = (w, tsIndex, profiles) => {
2455
+ if (profiles.length === 0) return;
2456
+ w.cd("profiles", () => {
2457
+ for (const profile of profiles) {
2458
+ const moduleName = pyProfileModuleName(tsIndex, profile);
2459
+ w.cat(`${moduleName}.py`, () => {
2460
+ w.generateDisclaimer();
2461
+ generateProfileModule(w, tsIndex, profile);
2462
+ });
1231
2463
  }
1232
- return tree;
1233
- };
1234
- const exportTree = async (filename) => {
1235
- const tree = entityTree();
1236
- const raw = filename.endsWith(".yaml") ? YAML.stringify(tree) : JSON.stringify(tree, void 0, 2);
1237
- await fsPromises.mkdir(Path5.dirname(filename), { recursive: true });
1238
- await fsPromises.writeFile(filename, raw);
1239
- };
1240
- return {
1241
- _schemaIndex: index,
1242
- schemas,
1243
- schemasByPackage: groupByPackages(schemas),
1244
- register,
1245
- collectComplexTypes: () => schemas.filter(isComplexTypeTypeSchema),
1246
- collectResources: () => schemas.filter(isResourceTypeSchema),
1247
- collectLogicalModels: () => schemas.filter(isLogicalTypeSchema),
1248
- collectProfiles: () => schemas.filter(isProfileTypeSchema),
1249
- collectSnapshotProfiles,
1250
- resolve: resolve6,
1251
- resolveType,
1252
- resolveByUrl,
1253
- tryHierarchy,
1254
- hierarchy,
1255
- findLastSpecialization,
1256
- findLastSpecializationByIdentifier,
1257
- flatProfile,
1258
- constrainedChoice,
1259
- isWithMetaField,
1260
- entityTree,
1261
- exportTree,
1262
- irReport: () => irReport,
1263
- replaceSchemas: (newSchemas) => mkTypeSchemaIndex(newSchemas, { register, logger, irReport: { ...irReport } })
1264
- };
2464
+ generateProfilesInit(w, tsIndex, profiles);
2465
+ });
1265
2466
  };
1266
2467
 
1267
- // src/api/writer-generator/python.ts
1268
- var PRIMITIVE_TYPE_MAP2 = {
1269
- boolean: "bool",
1270
- instant: "str",
1271
- time: "str",
1272
- date: "str",
1273
- dateTime: "str",
1274
- decimal: "float",
1275
- integer: "int",
1276
- unsignedInt: "int",
1277
- positiveInt: "PositiveInt",
1278
- integer64: "int",
1279
- base64Binary: "str",
1280
- uri: "str",
1281
- url: "str",
1282
- canonical: "str",
1283
- oid: "str",
1284
- uuid: "str",
1285
- string: "str",
1286
- code: "str",
1287
- markdown: "str",
1288
- id: "str",
1289
- xhtml: "str"
2468
+ // src/api/writer-generator/python/writer.ts
2469
+ var resolvePyAssets = (fn) => {
2470
+ const __dirname = Path5.dirname(fileURLToPath(import.meta.url));
2471
+ const __filename = fileURLToPath(import.meta.url);
2472
+ if (__filename.endsWith("dist/index.js")) {
2473
+ return Path5.resolve(__dirname, "..", "assets", "api", "writer-generator", "python", fn);
2474
+ }
2475
+ return Path5.resolve(__dirname, "../../../..", "assets", "api", "writer-generator", "python", fn);
1290
2476
  };
1291
2477
  var AVAILABLE_STRING_FORMATS = {
1292
2478
  snake_case: snakeCase,
1293
2479
  PascalCase: pascalCase,
1294
2480
  camelCase
1295
2481
  };
1296
- var PYTHON_KEYWORDS = /* @__PURE__ */ new Set([
1297
- "False",
1298
- "None",
1299
- "True",
1300
- "and",
1301
- "as",
1302
- "assert",
1303
- "async",
1304
- "await",
1305
- "break",
1306
- "class",
1307
- "continue",
1308
- "def",
1309
- "del",
1310
- "elif",
1311
- "else",
1312
- "except",
1313
- "finally",
1314
- "for",
1315
- "from",
1316
- "global",
1317
- "if",
1318
- "import",
1319
- "in",
1320
- "is",
1321
- "lambda",
1322
- "nonlocal",
1323
- "not",
1324
- "or",
1325
- "pass",
1326
- "raise",
1327
- "return",
1328
- "try",
1329
- "while",
1330
- "with",
1331
- "yield",
1332
- "List"
1333
- ]);
1334
2482
  var MAX_IMPORT_LINE_LENGTH = 100;
1335
2483
  var GENERIC_FIELD_REWRITES = {
1336
2484
  Coding: { code: "T" },
1337
2485
  CodeableConcept: { coding: "Coding[T]" }
1338
2486
  };
2487
+ var leafOf2 = (path) => path[path.length - 1] ?? "";
2488
+ var collectResourceGenericTypeVars = (schema) => {
2489
+ const all = /* @__PURE__ */ new Map();
2490
+ const addParams = (s) => {
2491
+ for (const p of s.generic?.params ?? []) {
2492
+ if (!all.has(p.typeVar)) all.set(p.typeVar, p.constraint.name);
2493
+ }
2494
+ };
2495
+ addParams(schema);
2496
+ for (const nested of schema.nested ?? []) addParams(nested);
2497
+ return Array.from(all.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([typeVar, constraint]) => ({ typeVar, constraint }));
2498
+ };
1339
2499
  var pyEnumType = (enumDef) => {
1340
2500
  const values = enumDef.values.map((e) => `"${e}"`).join(", ");
1341
2501
  return enumDef.isOpen ? `Literal[${values}] | str` : `Literal[${values}]`;
1342
2502
  };
1343
- var fixReservedWords = (name) => {
1344
- return PYTHON_KEYWORDS.has(name) ? `${name}_` : name;
1345
- };
1346
- var canonicalToName2 = (canonical, dropFragment = true) => {
1347
- if (!canonical) return void 0;
1348
- let localName = canonical.split("/").pop();
1349
- if (!localName) return void 0;
1350
- if (dropFragment && localName.includes("#")) {
1351
- localName = localName.split("#")[0];
1352
- }
1353
- if (!localName) return void 0;
1354
- if (/^\d/.test(localName)) {
1355
- localName = `number_${localName}`;
1356
- }
1357
- return snakeCase(localName);
1358
- };
1359
- var deriveResourceName = (id) => {
1360
- if (id.kind === "nested") {
1361
- const url = id.url;
1362
- const path = canonicalToName2(url, false);
1363
- if (!path) return "";
1364
- const [resourceName, fragment] = path.split("#");
1365
- const name = uppercaseFirstLetterOfEach((fragment ?? "").split(".")).join("");
1366
- return pascalCase([resourceName, name].join(""));
1367
- }
1368
- return pascalCase(id.name);
1369
- };
1370
- var resolvePyAssets = (fn) => {
1371
- const __dirname = Path5.dirname(fileURLToPath(import.meta.url));
1372
- const __filename = fileURLToPath(import.meta.url);
1373
- if (__filename.endsWith("dist/index.js")) {
1374
- return Path5.resolve(__dirname, "..", "assets", "api", "writer-generator", "python", fn);
1375
- } else {
1376
- return Path5.resolve(__dirname, "../../..", "assets", "api", "writer-generator", "python", fn);
1377
- }
1378
- };
1379
2503
  var Python = class extends Writer {
1380
2504
  nameFormatFunction;
1381
2505
  tsIndex;
@@ -1384,19 +2508,29 @@ var Python = class extends Writer {
1384
2508
  constructor(options) {
1385
2509
  super({ ...options, resolveAssets: options.resolveAssets ?? resolvePyAssets });
1386
2510
  this.nameFormatFunction = this.getFieldFormatFunction(options.fieldFormat);
1387
- this.forFhirpyClient = options.fhirpyClient ?? false;
2511
+ this.forFhirpyClient = this.resolveClient(options);
1388
2512
  this.fieldFormat = options.fieldFormat;
1389
2513
  }
2514
+ /** Resolve which client integration to emit. `client` wins; `fhirpyClient` is the deprecated fallback; default is fhirpy. */
2515
+ resolveClient(options) {
2516
+ if (options.client !== void 0) return options.client === "fhirpy";
2517
+ if (options.fhirpyClient !== void 0) {
2518
+ this.logger()?.warn('python: `fhirpyClient` is deprecated; use `client: "fhirpy" | "none"` instead.');
2519
+ return options.fhirpyClient;
2520
+ }
2521
+ return true;
2522
+ }
1390
2523
  async generate(tsIndex) {
1391
2524
  this.tsIndex = tsIndex;
1392
2525
  const groups = {
1393
2526
  groupedComplexTypes: groupByPackages(tsIndex.collectComplexTypes()),
1394
2527
  groupedResources: groupByPackages(tsIndex.collectResources())
1395
2528
  };
1396
- this.generateRootPackages(groups);
1397
- this.generateSDKPackages(groups);
2529
+ const hasProfiles = (this.opts.generateProfile ?? false) && tsIndex.collectSnapshotProfiles().length > 0;
2530
+ this.generateRootPackages(groups, hasProfiles);
2531
+ this.generateSDKPackages(tsIndex, groups);
1398
2532
  }
1399
- generateRootPackages(groups) {
2533
+ generateRootPackages(groups, hasProfiles) {
1400
2534
  this.generateRootInitFile(groups);
1401
2535
  if (this.forFhirpyClient) {
1402
2536
  if (this.fieldFormat === "camelCase") {
@@ -1405,20 +2539,24 @@ var Python = class extends Writer {
1405
2539
  this.copyAssets(resolvePyAssets("fhirpy_base_model.py"), "fhirpy_base_model.py");
1406
2540
  }
1407
2541
  }
2542
+ if (hasProfiles) {
2543
+ this.copyAssets(resolvePyAssets("profile_helpers.py"), "profile_helpers.py");
2544
+ }
1408
2545
  this.copyAssets(resolvePyAssets("requirements.txt"), "requirements.txt");
1409
2546
  }
1410
- generateSDKPackages(groups) {
2547
+ generateSDKPackages(tsIndex, groups) {
1411
2548
  this.generateComplexTypesPackages(groups.groupedComplexTypes);
1412
- this.generateResourcePackages(groups);
2549
+ this.generateResourcePackages(tsIndex, groups);
1413
2550
  }
1414
2551
  generateComplexTypesPackages(groupedComplexTypes) {
1415
2552
  for (const [packageName, packageComplexTypes] of Object.entries(groupedComplexTypes)) {
1416
2553
  this.cd(`/${snakeCase(packageName)}`, () => {
1417
- this.generateBasePy(packageComplexTypes);
2554
+ this.generateBasePy(packageName, packageComplexTypes);
1418
2555
  });
1419
2556
  }
1420
2557
  }
1421
- generateResourcePackages(groups) {
2558
+ generateResourcePackages(tsIndex, groups) {
2559
+ const profilesByPackage = this.opts.generateProfile ? groupByPackages(tsIndex.collectSnapshotProfiles()) : {};
1422
2560
  for (const [packageName, packageResources] of Object.entries(groups.groupedResources)) {
1423
2561
  this.cd(`/${snakeCase(packageName)}`, () => {
1424
2562
  this.generateResourcePackageContent(
@@ -1426,13 +2564,27 @@ var Python = class extends Writer {
1426
2564
  packageResources,
1427
2565
  groups.groupedComplexTypes[packageName] || []
1428
2566
  );
2567
+ const packageProfiles = profilesByPackage[packageName];
2568
+ if (packageProfiles && packageProfiles.length > 0) {
2569
+ generateNewProfiles(this, tsIndex, packageProfiles);
2570
+ }
2571
+ });
2572
+ }
2573
+ for (const [packageName, packageProfiles] of Object.entries(profilesByPackage)) {
2574
+ if (groups.groupedResources[packageName]) continue;
2575
+ if (!packageProfiles || packageProfiles.length === 0) continue;
2576
+ this.cd(`/${snakeCase(packageName)}`, () => {
2577
+ generateNewProfiles(this, tsIndex, packageProfiles);
1429
2578
  });
1430
2579
  }
1431
2580
  }
1432
2581
  generateResourcePackageContent(packageName, packageResources, packageComplexTypes) {
1433
- const pyPackageName = this.pyFhirPackageByName(packageName);
2582
+ const pyPackageName = pyFhirPackageByName(this.opts.rootPackageName, packageName);
1434
2583
  this.generateResourcePackageInit(pyPackageName, packageResources, packageComplexTypes);
1435
- this.generateResourceFamilies(packageResources);
2584
+ const hasAnyResourceGenericParams = packageResources.some((s) => collectResourceGenericTypeVars(s).length > 0);
2585
+ if (hasAnyResourceGenericParams) {
2586
+ this.copyAssets(resolvePyAssets("resource_preprocessor.py"), "resource_preprocessor.py");
2587
+ }
1436
2588
  for (const schema of packageResources) {
1437
2589
  this.generateResourceModule(schema);
1438
2590
  }
@@ -1443,13 +2595,14 @@ var Python = class extends Writer {
1443
2595
  this.generateDisclaimer();
1444
2596
  const pydanticModels = this.collectAndImportAllModels(groups);
1445
2597
  this.generateModelRebuilds(pydanticModels);
2598
+ this.importProfileRegistrations(groups);
1446
2599
  });
1447
2600
  });
1448
2601
  }
1449
2602
  collectAndImportAllModels(groups) {
1450
2603
  const models = [];
1451
2604
  for (const packageName of Object.keys(groups.groupedResources)) {
1452
- const fullPyPackageName = this.pyFhirPackageByName(packageName);
2605
+ const fullPyPackageName = pyFhirPackageByName(this.opts.rootPackageName, packageName);
1453
2606
  models.push(...this.importComplexTypes(fullPyPackageName, groups.groupedComplexTypes[packageName]));
1454
2607
  models.push(...this.importResources(fullPyPackageName, false, groups.groupedResources[packageName]));
1455
2608
  }
@@ -1461,7 +2614,15 @@ var Python = class extends Writer {
1461
2614
  this.line(`${modelName}.model_rebuild()`);
1462
2615
  }
1463
2616
  }
1464
- generateBasePy(packageComplexTypes) {
2617
+ importProfileRegistrations(groups) {
2618
+ if (!this.opts.generateProfile) return;
2619
+ this.line();
2620
+ for (const packageName of Object.keys(groups.groupedResources)) {
2621
+ const profilesPackage = `${pyFhirPackageByName(this.opts.rootPackageName, packageName)}.profiles`;
2622
+ this.line(`import ${profilesPackage} # noqa: F401`);
2623
+ }
2624
+ }
2625
+ generateBasePy(_packageName, packageComplexTypes) {
1465
2626
  const hasGenericTypes = packageComplexTypes.some((s) => s.identifier.name in GENERIC_FIELD_REWRITES);
1466
2627
  this.cat("base.py", () => {
1467
2628
  this.generateDisclaimer();
@@ -1498,20 +2659,16 @@ var Python = class extends Writer {
1498
2659
  this.line();
1499
2660
  return baseTypes;
1500
2661
  }
1501
- buildImportLine(remaining, maxImportLineLength) {
2662
+ buildImportLine(entities, start, maxLen) {
1502
2663
  let line = "";
1503
- while (remaining.length > 0 && line.length < maxImportLineLength) {
1504
- const entity = remaining.shift();
1505
- if (!entity) throw new Error("Unexpected empty entity");
1506
- if (line.length > 0) {
1507
- line += ", ";
1508
- }
1509
- line += entity;
1510
- }
1511
- if (remaining.length > 0) {
1512
- line += ", \\";
2664
+ let i = start;
2665
+ while (i < entities.length && line.length < maxLen) {
2666
+ if (line.length > 0) line += ", ";
2667
+ line += entities[i];
2668
+ i++;
1513
2669
  }
1514
- return line;
2670
+ if (i < entities.length) line += ", \\";
2671
+ return { line, next: i };
1515
2672
  }
1516
2673
  importResources(fullPyPackageName, importEmptyResources, packageResources) {
1517
2674
  if (!packageResources || packageResources.length === 0) return [];
@@ -1527,12 +2684,7 @@ var Python = class extends Writer {
1527
2684
  const moduleName = `${fullPyPackageName}.${snakeCase(resource.identifier.name)}`;
1528
2685
  const importNames = this.collectResourceImportNames(resource);
1529
2686
  this.pyImportFrom(moduleName, ...importNames);
1530
- const names = [...importNames];
1531
- if (this.shouldImportResourceFamily(resource)) {
1532
- const familyName = `${resource.identifier.name}Family`;
1533
- this.pyImportFrom(`${fullPyPackageName}.resource_families`, familyName);
1534
- }
1535
- return names;
2687
+ return [...importNames];
1536
2688
  }
1537
2689
  collectResourceImportNames(resource) {
1538
2690
  const names = [deriveResourceName(resource.identifier)];
@@ -1542,9 +2694,6 @@ var Python = class extends Writer {
1542
2694
  }
1543
2695
  return names;
1544
2696
  }
1545
- shouldImportResourceFamily(resource) {
1546
- return resource.identifier.kind === "resource" && (resource.typeFamily?.resources?.length ?? 0) > 0;
1547
- }
1548
2697
  generateExportsDeclaration(packageComplexTypes, allResourceNames) {
1549
2698
  this.squareBlock(["__all__", "="], () => {
1550
2699
  const allExports = [
@@ -1557,12 +2706,22 @@ var Python = class extends Writer {
1557
2706
  });
1558
2707
  }
1559
2708
  generateResourceModule(schema) {
2709
+ const typeVars = collectResourceGenericTypeVars(schema);
2710
+ const hasResourceGenericParams = typeVars.length > 0;
1560
2711
  this.cat(`${snakeCase(schema.identifier.name)}.py`, () => {
1561
2712
  this.generateDisclaimer();
1562
- this.generateDefaultImports(false);
2713
+ this.generateDefaultImports(false, hasResourceGenericParams, true);
1563
2714
  this.generateFhirBaseModelImport();
1564
2715
  this.line();
1565
2716
  this.generateDependenciesImports(schema);
2717
+ if (hasResourceGenericParams) {
2718
+ const pyFhirPackage2 = pyFhirPackageByName(this.opts.rootPackageName, schema.identifier.package);
2719
+ this.pyImportFrom(`${pyFhirPackage2}.resource_preprocessor`, "preprocess_resource_fields");
2720
+ this.line();
2721
+ for (const { typeVar, constraint } of typeVars) {
2722
+ this.line(`${typeVar} = TypeVar('${typeVar}', bound=${constraint}, default=${constraint})`);
2723
+ }
2724
+ }
1566
2725
  this.line();
1567
2726
  this.generateNestedTypes(schema);
1568
2727
  this.line();
@@ -1587,6 +2746,11 @@ var Python = class extends Writer {
1587
2746
  if (schema.base) bases.push(schema.base.name);
1588
2747
  bases.push(...this.injectSuperClasses(schema.identifier.url));
1589
2748
  if (schema.identifier.name in GENERIC_FIELD_REWRITES) bases.push("Generic[T]");
2749
+ const params = schema.generic?.params ?? [];
2750
+ if (params.length > 0) {
2751
+ const typeVars = params.map((p) => p.typeVar).join(", ");
2752
+ bases.push(`Generic[${typeVars}]`);
2753
+ }
1590
2754
  return bases;
1591
2755
  }
1592
2756
  generateClassBody(schema) {
@@ -1598,10 +2762,26 @@ var Python = class extends Writer {
1598
2762
  if (isResourceTypeSchema(schema)) {
1599
2763
  this.generateResourceTypeField(schema);
1600
2764
  }
1601
- this.generateFields(schema, schema.identifier.name);
2765
+ this.generateFields(schema);
2766
+ if (this.opts.generateProfile && schema.identifier.name === "Extension") {
2767
+ this.generateExtensionEqualityMethods();
2768
+ }
1602
2769
  if (isResourceTypeSchema(schema)) {
1603
2770
  this.generateResourceMethods(schema);
1604
2771
  }
2772
+ if ((schema.generic?.params?.length ?? 0) > 0) {
2773
+ this.generateResourcePreprocessorMethod(schema);
2774
+ }
2775
+ }
2776
+ generateResourcePreprocessorMethod(schema) {
2777
+ const pyFhirPackage2 = pyFhirPackageByName(this.opts.rootPackageName, schema.identifier.package);
2778
+ this.line();
2779
+ this.line("@model_validator(mode='before')");
2780
+ this.line("@classmethod");
2781
+ this.line("def _preprocess_resources(cls, data: Any) -> Any:");
2782
+ this.line(" if isinstance(data, dict):");
2783
+ this.line(` return preprocess_resource_fields(data, "${pyFhirPackage2}")`);
2784
+ this.line(" return data");
1605
2785
  }
1606
2786
  generateModelConfig() {
1607
2787
  const extraMode = this.opts.allowExtraFields ? "allow" : "forbid";
@@ -1625,12 +2805,12 @@ var Python = class extends Writer {
1625
2805
  });
1626
2806
  this.line(")");
1627
2807
  }
1628
- generateFields(schema, schemaName) {
2808
+ generateFields(schema) {
1629
2809
  const sortedFields = Object.entries(schema.fields ?? []).sort(([a], [b]) => a.localeCompare(b));
1630
2810
  const withExtensions = this.shouldAddPrimitiveExtensions(schema);
1631
2811
  for (const [fieldName, field] of sortedFields) {
1632
2812
  if ("choices" in field && field.choices) continue;
1633
- const fieldInfo = this.buildFieldInfo(fieldName, field, schemaName);
2813
+ const fieldInfo = this.buildFieldInfo(fieldName, field, schema);
1634
2814
  this.line(`${fieldInfo.name}: ${fieldInfo.type}${fieldInfo.defaultValue}`);
1635
2815
  if (withExtensions && "type" in field && isPrimitiveIdentifier(field.type)) {
1636
2816
  this.addPrimitiveExtensionField(fieldName, field.array ?? false);
@@ -1647,23 +2827,24 @@ var Python = class extends Writer {
1647
2827
  return false;
1648
2828
  }
1649
2829
  addPrimitiveExtensionField(fieldName, isArray) {
1650
- const pyFieldName = this.nameFormatFunction(`${fieldName}Extension`);
2830
+ const pyFieldName2 = this.nameFormatFunction(`${fieldName}Extension`);
1651
2831
  const alias = `_${fieldName}`;
1652
2832
  const typeExpr = isArray ? "PyList[Element | None] | None" : "Element | None";
1653
2833
  const aliasSpec = `alias="${alias}", serialization_alias="${alias}"`;
1654
- this.line(`${pyFieldName}: ${typeExpr} = Field(None, ${aliasSpec})`);
2834
+ this.line(`${pyFieldName2}: ${typeExpr} = Field(None, ${aliasSpec})`);
1655
2835
  }
1656
- buildFieldInfo(fieldName, field, schemaName) {
1657
- const pyFieldName = fixReservedWords(this.nameFormatFunction(fieldName));
1658
- const fieldType = this.determineFieldType(field, fieldName, schemaName);
2836
+ buildFieldInfo(fieldName, field, schema) {
2837
+ const pyFieldName2 = fixReservedWords(this.nameFormatFunction(fieldName));
2838
+ const fieldType = this.determineFieldType(field, fieldName, schema);
1659
2839
  const defaultValue = this.getFieldDefaultValue(field, fieldName);
1660
2840
  return {
1661
- name: pyFieldName,
2841
+ name: pyFieldName2,
1662
2842
  type: fieldType,
1663
2843
  defaultValue
1664
2844
  };
1665
2845
  }
1666
- determineFieldType(field, fieldName, schemaName) {
2846
+ determineFieldType(field, fieldName, schema) {
2847
+ const schemaName = schema.identifier.name;
1667
2848
  let fieldType = field ? this.getBaseFieldType(field) : "";
1668
2849
  const rewrite = GENERIC_FIELD_REWRITES[schemaName]?.[fieldName];
1669
2850
  if (rewrite) {
@@ -1672,6 +2853,27 @@ var Python = class extends Writer {
1672
2853
  if (!field.required) fieldType = `${fieldType} | None`;
1673
2854
  return fieldType;
1674
2855
  }
2856
+ const params = schema.generic?.params ?? [];
2857
+ const directParam = params.find((p) => leafOf2(p.path) === fieldName);
2858
+ if (directParam) {
2859
+ fieldType = directParam.typeVar;
2860
+ if (field.array) fieldType = `PyList[${fieldType}]`;
2861
+ if (!field.required) fieldType = `${fieldType} | None`;
2862
+ return fieldType;
2863
+ }
2864
+ if ("type" in field && field.type && params.length > 0) {
2865
+ assert4(this.tsIndex !== void 0);
2866
+ const target = this.tsIndex.resolveType(field.type);
2867
+ if (target && (isNestedTypeSchema(target) || isSpecializationTypeSchema(target))) {
2868
+ const nestedParams = target.generic?.params ?? [];
2869
+ if (nestedParams.length > 0) {
2870
+ const args = nestedParams.map(
2871
+ (np) => params.find((p) => leafOf2(p.path) === leafOf2(np.path))?.typeVar ?? np.typeVar
2872
+ );
2873
+ fieldType = `${fieldType}[${args.join(", ")}]`;
2874
+ }
2875
+ }
2876
+ }
1675
2877
  if ("enum" in field && field.enum) {
1676
2878
  const baseTypeName = "type" in field ? field.type.name : "";
1677
2879
  if (baseTypeName in GENERIC_FIELD_REWRITES) {
@@ -1703,19 +2905,30 @@ var Python = class extends Writer {
1703
2905
  }
1704
2906
  return ` = Field(${aliasSpec})`;
1705
2907
  }
1706
- generateResourceMethods(schema) {
1707
- const className = schema.identifier.name.toString();
2908
+ generateResourceMethods(_schema) {
1708
2909
  this.line();
1709
2910
  this.line("def model_post_init(self, __context: Any) -> None:");
1710
- this.line(' self.__pydantic_fields_set__.add("resource_type")');
2911
+ this.line(` self.__pydantic_fields_set__.add("${this.nameFormatFunction("resourceType")}")`);
1711
2912
  this.line();
1712
2913
  this.line("def to_json(self, indent: int | None = None) -> str:");
1713
2914
  this.line(" return self.model_dump_json(exclude_unset=True, exclude_none=True, indent=indent)");
1714
2915
  this.line();
1715
2916
  this.line("@classmethod");
1716
- this.line(`def from_json(cls, json: str) -> ${className}:`);
2917
+ this.line("def from_json(cls, json: str) -> Self:");
1717
2918
  this.line(" return cls.model_validate_json(json)");
1718
2919
  }
2920
+ generateExtensionEqualityMethods() {
2921
+ this.line();
2922
+ this.line("def __eq__(self, other: object) -> bool:");
2923
+ this.line(" if not isinstance(other, Extension):");
2924
+ this.line(" return NotImplemented");
2925
+ this.line(
2926
+ " return self.model_dump(by_alias=True, exclude_none=True) == other.model_dump(by_alias=True, exclude_none=True)"
2927
+ );
2928
+ this.line();
2929
+ this.line("def __hash__(self) -> int:");
2930
+ this.line(" return hash(self.url)");
2931
+ }
1719
2932
  generateNestedTypes(schema) {
1720
2933
  if (!schema.nested) return;
1721
2934
  this.line();
@@ -1723,17 +2936,20 @@ var Python = class extends Writer {
1723
2936
  this.generateType(subtype);
1724
2937
  }
1725
2938
  }
1726
- generateDefaultImports(includeGenericImports) {
2939
+ generateDefaultImports(includeGenericImports, includeResourceGenericImports = false, includeResourceMethods = false) {
1727
2940
  this.pyImportFrom("__future__", "annotations");
1728
- this.pyImportFrom("pydantic", "BaseModel", "ConfigDict", "Field", "PositiveInt");
2941
+ const pydanticImports = ["BaseModel", "ConfigDict", "Field", "PositiveInt"];
2942
+ if (includeResourceGenericImports) pydanticImports.push("model_validator");
2943
+ this.pyImportFrom("pydantic", ...pydanticImports.sort());
1729
2944
  const typingImports = ["Any", "List as PyList", "Literal"];
1730
- if (includeGenericImports) {
2945
+ if (includeGenericImports || includeResourceGenericImports) {
1731
2946
  typingImports.push("Generic");
1732
2947
  }
1733
2948
  this.pyImportFrom("typing", ...typingImports.sort());
1734
- if (includeGenericImports) {
1735
- this.pyImportFrom("typing_extensions", "TypeVar");
1736
- }
2949
+ const typingExtImports = [];
2950
+ if (includeGenericImports || includeResourceGenericImports) typingExtImports.push("TypeVar");
2951
+ if (includeResourceMethods) typingExtImports.push("Self");
2952
+ if (typingExtImports.length > 0) this.pyImportFrom("typing_extensions", ...typingExtImports.sort());
1737
2953
  }
1738
2954
  generateDependenciesImports(schema) {
1739
2955
  if (!schema.dependencies || schema.dependencies.length === 0) return;
@@ -1749,134 +2965,58 @@ var Python = class extends Writer {
1749
2965
  const elementUrl = "http://hl7.org/fhir/StructureDefinition/Element";
1750
2966
  const element = this.tsIndex.resolveByUrl(schema.identifier.package, elementUrl);
1751
2967
  if (!element) return;
1752
- const pyPackage = this.pyPackage(element.identifier);
1753
- this.pyImportFrom(pyPackage, "Element");
2968
+ const pyPkg = pyPackage(this.opts.rootPackageName, element.identifier);
2969
+ this.pyImportFrom(pyPkg, "Element");
1754
2970
  }
1755
2971
  importComplexTypeDependencies(dependencies) {
1756
2972
  const complexTypeDeps = dependencies.filter((dep) => dep.kind === "complex-type");
1757
2973
  const depsByPackage = this.groupDependenciesByPackage(complexTypeDeps);
1758
- for (const [pyPackage, names] of Object.entries(depsByPackage)) {
1759
- this.pyImportFrom(pyPackage, ...names.sort());
2974
+ for (const [pyPackage2, names] of Object.entries(depsByPackage)) {
2975
+ this.pyImportFrom(pyPackage2, ...names.sort());
1760
2976
  }
1761
2977
  }
1762
2978
  importResourceDependencies(dependencies) {
1763
2979
  const resourceDeps = dependencies.filter((dep) => dep.kind === "resource");
1764
2980
  for (const dep of resourceDeps) {
1765
2981
  this.pyImportType(dep);
1766
- const familyName = `${pascalCase(dep.name)}Family`;
1767
- const familyPackage = `${this.pyFhirPackage(dep)}.resource_families`;
1768
- this.pyImportFrom(familyPackage, familyName);
1769
2982
  }
1770
2983
  }
1771
2984
  groupDependenciesByPackage(dependencies) {
1772
2985
  const grouped = {};
1773
2986
  for (const dep of dependencies) {
1774
- const pyPackage = this.pyPackage(dep);
1775
- if (!grouped[pyPackage]) {
1776
- grouped[pyPackage] = [];
2987
+ const pyPkg = pyPackage(this.opts.rootPackageName, dep);
2988
+ if (!grouped[pyPkg]) {
2989
+ grouped[pyPkg] = [];
1777
2990
  }
1778
- grouped[pyPackage].push(dep.name);
2991
+ grouped[pyPkg].push(dep.name);
1779
2992
  }
1780
2993
  return grouped;
1781
2994
  }
1782
- pyImportFrom(pyPackage, ...entities) {
1783
- const oneLine = `from ${pyPackage} import ${entities.join(", ")}`;
2995
+ pyImportFrom(pyPackage2, ...entities) {
2996
+ const oneLine = `from ${pyPackage2} import ${entities.join(", ")}`;
1784
2997
  if (this.shouldUseSingleLineImport(oneLine, entities)) {
1785
2998
  this.line(oneLine);
1786
2999
  } else {
1787
- this.writeMultiLineImport(pyPackage, entities);
3000
+ this.writeMultiLineImport(pyPackage2, entities);
1788
3001
  }
1789
3002
  }
1790
3003
  shouldUseSingleLineImport(oneLine, entities) {
1791
3004
  return oneLine.length <= MAX_IMPORT_LINE_LENGTH || entities.length === 1;
1792
3005
  }
1793
- writeMultiLineImport(pyPackage, entities) {
1794
- this.line(`from ${pyPackage} import (\\`);
3006
+ writeMultiLineImport(pyPackage2, entities) {
3007
+ this.line(`from ${pyPackage2} import (`);
1795
3008
  this.indentBlock(() => {
1796
- const remaining = [...entities];
1797
- while (remaining.length > 0) {
1798
- const line = this.buildImportLine(remaining, MAX_IMPORT_LINE_LENGTH);
3009
+ let i = 0;
3010
+ while (i < entities.length) {
3011
+ const { line, next } = this.buildImportLine(entities, i, MAX_IMPORT_LINE_LENGTH);
1799
3012
  this.line(line);
3013
+ i = next;
1800
3014
  }
1801
3015
  });
1802
3016
  this.line(")");
1803
3017
  }
1804
3018
  pyImportType(identifier) {
1805
- this.pyImportFrom(this.pyPackage(identifier), pascalCase(identifier.name));
1806
- }
1807
- generateResourceFamilies(packageResources) {
1808
- assert4(this.tsIndex !== void 0);
1809
- const packages = (
1810
- //this.helper.getPackages(packageResources, this.opts.rootPackageName);
1811
- Object.keys(groupByPackages(packageResources)).map(
1812
- (pkgName) => `${this.opts.rootPackageName}.${pkgName.replaceAll(".", "_")}`
1813
- )
1814
- );
1815
- const families = {};
1816
- for (const resource of this.tsIndex.collectResources()) {
1817
- const children = (resource.typeFamily?.resources ?? []).map((c) => c.name);
1818
- if (children.length > 0) {
1819
- const familyName = `${resource.identifier.name}Family`;
1820
- families[familyName] = children;
1821
- }
1822
- }
1823
- const exportList = Object.keys(families);
1824
- if (exportList.length === 0) return;
1825
- this.buildResourceFamiliesFile(packages, families, exportList);
1826
- }
1827
- buildResourceFamiliesFile(packages, families, exportList) {
1828
- this.cat("resource_families.py", () => {
1829
- this.generateDisclaimer();
1830
- this.includeResourceFamilyValidator();
1831
- this.line();
1832
- this.generateFamilyDefinitions(packages, families);
1833
- this.generateFamilyExports(exportList);
1834
- });
1835
- }
1836
- includeResourceFamilyValidator() {
1837
- const content = fs__default.readFileSync(resolvePyAssets("resource_family_validator.py"), "utf-8");
1838
- this.line(content);
1839
- }
1840
- generateFamilyDefinitions(packages, families) {
1841
- this.line(`packages = [${packages.map((p) => `'${p}'`).join(", ")}]`);
1842
- this.line();
1843
- for (const [familyName, resources] of Object.entries(families)) {
1844
- this.generateFamilyDefinition(familyName, resources);
1845
- }
1846
- }
1847
- generateFamilyDefinition(familyName, resources) {
1848
- const listName = `${familyName}_resources`;
1849
- this.line(
1850
- `${listName} = [${resources.map((r) => `'${r}'`).sort().join(", ")}]`
1851
- );
1852
- this.line();
1853
- this.line(`def validate_and_downcast_${familyName}(v: Any) -> Any:`);
1854
- this.line(` return validate_and_downcast(v, packages, ${listName})`);
1855
- this.line();
1856
- this.line(`type ${familyName} = Annotated[Any, BeforeValidator(validate_and_downcast_${familyName})]`);
1857
- this.line();
1858
- }
1859
- generateFamilyExports(exportList) {
1860
- this.line(`__all__ = [${exportList.map((e) => `'${e}'`).join(", ")}]`);
1861
- }
1862
- buildPyPackageName(packageName) {
1863
- const parts = packageName ? [snakeCase(packageName)] : [""];
1864
- return parts.join(".");
1865
- }
1866
- pyFhirPackage(identifier) {
1867
- return this.pyFhirPackageByName(identifier.package);
1868
- }
1869
- pyFhirPackageByName(name) {
1870
- return [this.opts.rootPackageName, this.buildPyPackageName(name)].join(".");
1871
- }
1872
- pyPackage(identifier) {
1873
- if (identifier.kind === "complex-type") {
1874
- return `${this.pyFhirPackage(identifier)}.base`;
1875
- }
1876
- if (identifier.kind === "resource") {
1877
- return [this.pyFhirPackage(identifier), snakeCase(identifier.name)].join(".");
1878
- }
1879
- return this.pyFhirPackage(identifier);
3019
+ this.pyImportFrom(pyPackage(this.opts.rootPackageName, identifier), pascalCase(identifier.name));
1880
3020
  }
1881
3021
  getFieldFormatFunction(format2) {
1882
3022
  if (!AVAILABLE_STRING_FORMATS[format2]) {
@@ -1950,11 +3090,13 @@ function mkIdentifier(fhirSchema) {
1950
3090
  if (fhirSchema.kind === "logical") return { kind: "logical", ...fields };
1951
3091
  return { kind: "resource", ...fields };
1952
3092
  }
3093
+ var VALUE_SET_NAME_SPLIT_RE = /[-_]/;
3094
+ var OPAQUE_VALUE_SET_ID_RE = /^[a-zA-Z0-9_-]{20,}$/;
1953
3095
  var getValueSetName = (url) => {
1954
3096
  const urlParts = url.split("/");
1955
3097
  const lastSegment = urlParts[urlParts.length - 1];
1956
3098
  if (lastSegment && lastSegment.length > 0) {
1957
- return lastSegment.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
3099
+ return lastSegment.split(VALUE_SET_NAME_SPLIT_RE).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
1958
3100
  }
1959
3101
  return url;
1960
3102
  };
@@ -1968,7 +3110,7 @@ function mkValueSetIdentifierByUrl(register, pkg, fullValueSetUrl) {
1968
3110
  },
1969
3111
  id: fullValueSetUrl};
1970
3112
  const valueSet = register.resolveVs(pkg, valueSetUrl) || valuesSetFallback;
1971
- const valueSetName = valueSet?.id && !/^[a-zA-Z0-9_-]{20,}$/.test(valueSet.id) ? valueSet.id : valueSetNameFallback;
3113
+ const valueSetName = valueSet?.id && !OPAQUE_VALUE_SET_ID_RE.test(valueSet.id) ? valueSet.id : valueSetNameFallback;
1972
3114
  return {
1973
3115
  kind: "value-set",
1974
3116
  package: valueSet.package_meta.name,
@@ -2240,6 +3382,7 @@ var isValueSet = (resource) => {
2240
3382
  };
2241
3383
 
2242
3384
  // src/typeschema/register.ts
3385
+ var BARE_RESOURCE_NAME_RE = /^[a-zA-Z0-9]+$/;
2243
3386
  var readPackageDependencies = async (manager, packageMeta2) => {
2244
3387
  const packageJSON = await manager.packageJson(packageMeta2.name);
2245
3388
  if (!packageJSON) return [];
@@ -2264,6 +3407,7 @@ var mkPackageAwareResolver = async (manager, pkg, deep, acc, logger) => {
2264
3407
  logger?.info(`${" ".repeat(deep * 2)}+ ${pkgId}`);
2265
3408
  if (acc[pkgId]) return acc[pkgId];
2266
3409
  const index = mkEmptyPkgIndex(pkg);
3410
+ acc[pkgId] = index;
2267
3411
  for (const resource of await manager.search({ package: pkg })) {
2268
3412
  const rawUrl = resource.url;
2269
3413
  if (!rawUrl) continue;
@@ -2284,7 +3428,6 @@ var mkPackageAwareResolver = async (manager, pkg, deep, acc, logger) => {
2284
3428
  for (const resolutionOptions of Object.values(index.canonicalResolution)) {
2285
3429
  resolutionOptions.sort((a, b) => a.deep - b.deep);
2286
3430
  }
2287
- acc[pkgId] = index;
2288
3431
  return index;
2289
3432
  };
2290
3433
  var enrichResolver = (resolver, logger) => {
@@ -2299,8 +3442,8 @@ var enrichResolver = (resolver, logger) => {
2299
3442
  const resource = resolition.resource;
2300
3443
  const resourcePkg = resolition.pkg;
2301
3444
  if (isStructureDefinition(resource)) {
2302
- const fs7 = fhirschema.translate(resource);
2303
- const rfs = enrichFHIRSchema(fs7, resourcePkg);
3445
+ const fs6 = fhirschema.translate(resource);
3446
+ const rfs = enrichFHIRSchema(fs6, resourcePkg);
2304
3447
  counter++;
2305
3448
  resolver[pkgId].fhirSchemas[rfs.url] = rfs;
2306
3449
  }
@@ -2333,12 +3476,12 @@ var registerFromManager = async (manager, { logger, focusedPackages }) => {
2333
3476
  }
2334
3477
  }
2335
3478
  for (const idx of Object.values(resolver)) {
2336
- const fs7 = idx.fhirSchemas[canonicalUrl];
2337
- if (fs7 && fs7.package_meta.name === pkg.name) return fs7;
3479
+ const fs6 = idx.fhirSchemas[canonicalUrl];
3480
+ if (fs6 && fs6.package_meta.name === pkg.name) return fs6;
2338
3481
  }
2339
3482
  for (const idx of Object.values(resolver)) {
2340
- const fs7 = idx.fhirSchemas[canonicalUrl];
2341
- if (fs7) return fs7;
3483
+ const fs6 = idx.fhirSchemas[canonicalUrl];
3484
+ if (fs6) return fs6;
2342
3485
  }
2343
3486
  return void 0;
2344
3487
  };
@@ -2362,29 +3505,29 @@ var registerFromManager = async (manager, { logger, focusedPackages }) => {
2362
3505
  };
2363
3506
  const ensureSpecializationCanonicalUrl = (name) => {
2364
3507
  if (name.includes("|")) name = name.split("|")[0];
2365
- if (name.match(/^[a-zA-Z0-9]+$/)) {
3508
+ if (BARE_RESOURCE_NAME_RE.test(name)) {
2366
3509
  return `http://hl7.org/fhir/StructureDefinition/${name}`;
2367
3510
  }
2368
3511
  return name;
2369
3512
  };
2370
3513
  const resolveFsGenealogy = (pkg, canonicalUrl) => {
2371
- let fs7 = resolveFs(pkg, canonicalUrl);
2372
- if (fs7 === void 0) throw new Error(`Failed to resolve FHIR Schema: '${canonicalUrl}'`);
2373
- const genealogy = [fs7];
2374
- while (fs7?.base) {
2375
- const pkg2 = fs7.package_meta;
2376
- const baseUrl = ensureSpecializationCanonicalUrl(fs7.base);
2377
- fs7 = resolveFs(pkg2, baseUrl);
2378
- if (fs7 === void 0)
3514
+ let fs6 = resolveFs(pkg, canonicalUrl);
3515
+ if (fs6 === void 0) throw new Error(`Failed to resolve FHIR Schema: '${canonicalUrl}'`);
3516
+ const genealogy = [fs6];
3517
+ while (fs6?.base) {
3518
+ const pkg2 = fs6.package_meta;
3519
+ const baseUrl = ensureSpecializationCanonicalUrl(fs6.base);
3520
+ fs6 = resolveFs(pkg2, baseUrl);
3521
+ if (fs6 === void 0)
2379
3522
  throw new Error(
2380
3523
  `Failed to resolve FHIR Schema base for '${canonicalUrl}'. Problem: '${baseUrl}' from '${packageMetaToFhir(pkg2)}'`
2381
3524
  );
2382
- genealogy.push(fs7);
3525
+ genealogy.push(fs6);
2383
3526
  }
2384
3527
  return genealogy;
2385
3528
  };
2386
3529
  const resolveFsSpecializations = (pkg, canonicalUrl) => {
2387
- return resolveFsGenealogy(pkg, canonicalUrl).filter((fs7) => fs7.derivation === "specialization");
3530
+ return resolveFsGenealogy(pkg, canonicalUrl).filter((fs6) => fs6.derivation === "specialization");
2388
3531
  };
2389
3532
  const resolveElementSnapshot = (fhirSchema, path) => {
2390
3533
  const geneology = resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url);
@@ -2479,9 +3622,9 @@ var registerFromPackageMetas = async (packageMetas, conf) => {
2479
3622
  var resolveFsElementGenealogy = (genealogy, path) => {
2480
3623
  const [top, ...rest] = path;
2481
3624
  if (top === void 0) return [];
2482
- return genealogy.map((fs7) => {
2483
- if (!fs7.elements) return void 0;
2484
- let elem = fs7.elements?.[top];
3625
+ return genealogy.map((fs6) => {
3626
+ if (!fs6.elements) return void 0;
3627
+ let elem = fs6.elements?.[top];
2485
3628
  for (const k of rest) {
2486
3629
  elem = elem?.elements?.[k];
2487
3630
  }
@@ -2504,7 +3647,7 @@ var hasStructuralElements = (register, fhirSchema, path) => {
2504
3647
  if (elemType) {
2505
3648
  const typeUrl = register.ensureSpecializationCanonicalUrl(elemType);
2506
3649
  const typeGenealogy = register.resolveFsGenealogy(fhirSchema.package_meta, typeUrl);
2507
- const keys = typeGenealogy.flatMap((fs7) => Object.keys(fs7.elements ?? {}));
3650
+ const keys = typeGenealogy.flatMap((fs6) => Object.keys(fs6.elements ?? {}));
2508
3651
  if (keys.length > 0) typeKeys = new Set(keys);
2509
3652
  }
2510
3653
  for (const elem of elemGens) {
@@ -2519,19 +3662,19 @@ var isNestedElement = (register, fhirSchema, path, snapshot, raw) => {
2519
3662
  if (!raw?.elements || raw.choiceOf !== void 0) return false;
2520
3663
  return hasStructuralElements(register, fhirSchema, path);
2521
3664
  };
2522
- var collectNestedPaths = (fs7) => {
2523
- if (!fs7.elements) return /* @__PURE__ */ new Set();
3665
+ var collectNestedPaths = (fs6) => {
3666
+ if (!fs6.elements) return /* @__PURE__ */ new Set();
2524
3667
  return new Set(
2525
- collectNestedElements(fs7, [], fs7.elements).filter(([_, el]) => el.elements && Object.keys(el.elements).length > 0).map(([path]) => path.join("."))
3668
+ collectNestedElements(fs6, [], fs6.elements).filter(([_, el]) => el.elements && Object.keys(el.elements).length > 0).map(([path]) => path.join("."))
2526
3669
  );
2527
3670
  };
2528
3671
  function mkNestedIdentifier(register, fhirSchema, path) {
2529
3672
  const nestedTypeOrigins = {};
2530
3673
  const genealogy = fhirSchema.derivation === "constraint" ? register.resolveFsSpecializations(fhirSchema.package_meta, fhirSchema.url) : register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url);
2531
- for (const fs7 of [...genealogy].reverse()) {
2532
- const paths = collectNestedPaths(fs7);
3674
+ for (const fs6 of [...genealogy].reverse()) {
3675
+ const paths = collectNestedPaths(fs6);
2533
3676
  for (const p of paths) {
2534
- nestedTypeOrigins[p] = `${fs7.url}#${p}`;
3677
+ nestedTypeOrigins[p] = `${fs6.url}#${p}`;
2535
3678
  }
2536
3679
  }
2537
3680
  const nestedName = path.join(".");
@@ -2666,10 +3809,10 @@ function isRequired(register, fhirSchema, path) {
2666
3809
  const fieldName = path[path.length - 1];
2667
3810
  if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
2668
3811
  const parentPath = path.slice(0, -1);
2669
- const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((fs7) => {
2670
- if (parentPath.length === 0) return fs7.required || [];
2671
- if (!fs7.elements) return [];
2672
- let elem = fs7;
3812
+ const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((fs6) => {
3813
+ if (parentPath.length === 0) return fs6.required || [];
3814
+ if (!fs6.elements) return [];
3815
+ let elem = fs6;
2673
3816
  for (const k of parentPath) {
2674
3817
  elem = elem?.elements?.[k];
2675
3818
  }
@@ -2681,10 +3824,10 @@ function isExcluded(register, fhirSchema, path) {
2681
3824
  const fieldName = path[path.length - 1];
2682
3825
  if (!fieldName) throw new Error(`Internal error: fieldName is missing for path ${path.join("/")}`);
2683
3826
  const parentPath = path.slice(0, -1);
2684
- const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((fs7) => {
2685
- if (parentPath.length === 0) return fs7.excluded || [];
2686
- if (!fs7.elements) return [];
2687
- let elem = fs7;
3827
+ const requires = register.resolveFsGenealogy(fhirSchema.package_meta, fhirSchema.url).flatMap((fs6) => {
3828
+ if (parentPath.length === 0) return fs6.excluded || [];
3829
+ if (!fs6.elements) return [];
3830
+ let elem = fs6;
2688
3831
  for (const k of parentPath) {
2689
3832
  elem = elem?.elements?.[k];
2690
3833
  }
@@ -2696,9 +3839,9 @@ var buildReferences = (register, fhirSchema, element) => {
2696
3839
  if (!element.refers) return void 0;
2697
3840
  return element.refers.map((ref) => {
2698
3841
  const curl = register.ensureSpecializationCanonicalUrl(ref);
2699
- const fs7 = register.resolveFs(fhirSchema.package_meta, curl);
2700
- if (!fs7) throw new Error(`Failed to resolve fs for ${curl}`);
2701
- return mkIdentifier(fs7);
3842
+ const fs6 = register.resolveFs(fhirSchema.package_meta, curl);
3843
+ if (!fs6) throw new Error(`Failed to resolve fs for ${curl}`);
3844
+ return mkIdentifier(fs6);
2702
3845
  });
2703
3846
  };
2704
3847
  var extractSliceFieldNames = (schema) => {
@@ -2848,7 +3991,8 @@ function buildFieldType(register, fhirSchema, path, element, logger) {
2848
3991
  if (element.elementReference) {
2849
3992
  const refPath = element.elementReference.slice(1).filter((_, i) => i % 2 === 1);
2850
3993
  return mkNestedIdentifier(register, fhirSchema, refPath);
2851
- } else if (element.type) {
3994
+ }
3995
+ if (element.type) {
2852
3996
  const url = register.ensureSpecializationCanonicalUrl(element.type);
2853
3997
  const fieldFs = register.resolveFs(fhirSchema.package_meta, url);
2854
3998
  if (!fieldFs) {
@@ -2864,17 +4008,18 @@ function buildFieldType(register, fhirSchema, path, element, logger) {
2864
4008
  );
2865
4009
  }
2866
4010
  return mkIdentifier(fieldFs);
2867
- } else if (element.choices) {
2868
- return void 0;
2869
- } else if (fhirSchema.derivation === "constraint") {
4011
+ }
4012
+ if (element.choices) {
2870
4013
  return void 0;
2871
- } else {
2872
- logger?.dryWarn(
2873
- "#fieldTypeNotFound",
2874
- `Can't recognize element type: <${fhirSchema.url}>.${path.join(".")} (pkg: '${packageMetaToFhir(fhirSchema.package_meta)}'): missing type info`
2875
- );
4014
+ }
4015
+ if (fhirSchema.derivation === "constraint") {
2876
4016
  return void 0;
2877
4017
  }
4018
+ logger?.dryWarn(
4019
+ "#fieldTypeNotFound",
4020
+ `Can't recognize element type: <${fhirSchema.url}>.${path.join(".")} (pkg: '${packageMetaToFhir(fhirSchema.package_meta)}'): missing type info`
4021
+ );
4022
+ return void 0;
2878
4023
  }
2879
4024
  var mkField = (register, fhirSchema, path, element, logger, rawElement) => {
2880
4025
  let binding;
@@ -3526,13 +4671,13 @@ var typeSchemaToJson = (ts, pretty) => {
3526
4671
  genContent: () => JSON.stringify(ts, null, pretty ? 2 : void 0)
3527
4672
  };
3528
4673
  };
3529
- var fhirSchemaToJson = (fs7, pretty) => {
3530
- const pkgPath = normalizeFileName(fs7.package_meta.name);
3531
- const name = normalizeFileName(`${fs7.name}(${extractNameFromCanonical(fs7.url)})`);
4674
+ var fhirSchemaToJson = (fs6, pretty) => {
4675
+ const pkgPath = normalizeFileName(fs6.package_meta.name);
4676
+ const name = normalizeFileName(`${fs6.name}(${extractNameFromCanonical(fs6.url)})`);
3532
4677
  const baseName = Path5.join(pkgPath, name);
3533
4678
  return {
3534
4679
  filename: baseName,
3535
- genContent: () => JSON.stringify(fs7, null, pretty ? 2 : void 0)
4680
+ genContent: () => JSON.stringify(fs6, null, pretty ? 2 : void 0)
3536
4681
  };
3537
4682
  };
3538
4683
  var structureDefinitionToJson = (sd, pretty) => {
@@ -3554,7 +4699,7 @@ var IntrospectionWriter = class extends FileSystemWriter {
3554
4699
  }
3555
4700
  if (this.opts.typeSchemas) {
3556
4701
  if (Path5.extname(this.opts.typeSchemas) === ".ndjson") {
3557
- this.writeNdjson(tsIndex.schemas, this.opts.typeSchemas, typeSchemaToJson);
4702
+ await this.writeNdjson(tsIndex.schemas, this.opts.typeSchemas, typeSchemaToJson);
3558
4703
  } else {
3559
4704
  const items = tsIndex.schemas.map((ts) => typeSchemaToJson(ts, true));
3560
4705
  const seenFilenames = /* @__PURE__ */ new Set();
@@ -3602,16 +4747,16 @@ var IntrospectionWriter = class extends FileSystemWriter {
3602
4747
  const outputPath = this.opts.fhirSchemas;
3603
4748
  const allFs = tsIndex.register.allFs();
3604
4749
  const seenUrls = /* @__PURE__ */ new Set();
3605
- const fhirSchemas = allFs.filter((fs7) => {
3606
- if (seenUrls.has(fs7.url)) return false;
3607
- seenUrls.add(fs7.url);
4750
+ const fhirSchemas = allFs.filter((fs6) => {
4751
+ if (seenUrls.has(fs6.url)) return false;
4752
+ seenUrls.add(fs6.url);
3608
4753
  return true;
3609
4754
  });
3610
4755
  if (Path5.extname(outputPath) === ".ndjson") {
3611
- this.writeNdjson(fhirSchemas, outputPath, fhirSchemaToJson);
4756
+ await this.writeNdjson(fhirSchemas, outputPath, fhirSchemaToJson);
3612
4757
  } else {
3613
- this.writeJsonFiles(
3614
- fhirSchemas.map((fs7) => fhirSchemaToJson(fs7, true)),
4758
+ await this.writeJsonFiles(
4759
+ fhirSchemas.map((fs6) => fhirSchemaToJson(fs6, true)),
3615
4760
  outputPath
3616
4761
  );
3617
4762
  }
@@ -3627,9 +4772,9 @@ var IntrospectionWriter = class extends FileSystemWriter {
3627
4772
  return true;
3628
4773
  });
3629
4774
  if (Path5.extname(outputPath) === ".ndjson") {
3630
- this.writeNdjson(structureDefinitions, outputPath, structureDefinitionToJson);
4775
+ await this.writeNdjson(structureDefinitions, outputPath, structureDefinitionToJson);
3631
4776
  } else {
3632
- this.writeJsonFiles(
4777
+ await this.writeJsonFiles(
3633
4778
  structureDefinitions.map((sd) => structureDefinitionToJson(sd, true)),
3634
4779
  outputPath
3635
4780
  );
@@ -3680,7 +4825,7 @@ var IntrospectionWriter = class extends FileSystemWriter {
3680
4825
  // src/typeschema/ir/report.ts
3681
4826
  var generateSkippedPackagesSection = (lines, skippedPackages) => {
3682
4827
  lines.push("## Skipped Packages", "");
3683
- for (const pkg of skippedPackages) {
4828
+ for (const pkg of [...skippedPackages].sort()) {
3684
4829
  lines.push(`- ${pkg}`);
3685
4830
  }
3686
4831
  lines.push("");
@@ -3741,7 +4886,7 @@ var generateCollisionVersionLines = (versions) => {
3741
4886
  const sourceList = v.entries.map((e) => {
3742
4887
  const name = extractNameFromCanonical(e.sourceCanonical) ?? e.sourceCanonical;
3743
4888
  return `${name} (${e.sourcePackage})`;
3744
- }).join(", ");
4889
+ }).sort().join(", ");
3745
4890
  const mark = v.mark ? versionMarkLabel[v.mark] : "";
3746
4891
  return ` - Version ${version++}${mark}: ${sourceList}`;
3747
4892
  });
@@ -3843,6 +4988,7 @@ var DebugMixinProvider = class {
3843
4988
  constructor(mode) {
3844
4989
  this.mode = mode;
3845
4990
  }
4991
+ mode;
3846
4992
  apply(target) {
3847
4993
  return this._addDebug(target);
3848
4994
  }
@@ -3880,6 +5026,7 @@ var LambdaMixinProvider = class {
3880
5026
  upperCase: () => (text, render) => render(text).toUpperCase()
3881
5027
  };
3882
5028
  }
5029
+ nameGenerator;
3883
5030
  lambda;
3884
5031
  apply(target) {
3885
5032
  return {
@@ -3897,6 +5044,10 @@ var NameGenerator = class {
3897
5044
  this.nameTransformations = nameTransformations;
3898
5045
  this.unsaveCharacterPattern = unsaveCharacterPattern;
3899
5046
  }
5047
+ keywords;
5048
+ typeMap;
5049
+ nameTransformations;
5050
+ unsaveCharacterPattern;
3900
5051
  _replaceUnsaveChars(name) {
3901
5052
  const pattern = this.unsaveCharacterPattern instanceof RegExp ? this.unsaveCharacterPattern : new RegExp(this.unsaveCharacterPattern, "g");
3902
5053
  return name.replace(pattern, "_");
@@ -4066,6 +5217,9 @@ var ViewModelFactory = class {
4066
5217
  this.nameGenerator = nameGenerator;
4067
5218
  this.filterPred = filterPred;
4068
5219
  }
5220
+ tsIndex;
5221
+ nameGenerator;
5222
+ filterPred;
4069
5223
  arrayMixinProvider = new ListElementInformationMixinProvider();
4070
5224
  createUtility() {
4071
5225
  return this._createForRoot();
@@ -4329,7 +5483,7 @@ function loadMustacheGeneratorConfig(templatePath, logger) {
4329
5483
  if (parsed && typeof parsed === "object") {
4330
5484
  return parsed;
4331
5485
  }
4332
- } catch (_e) {
5486
+ } catch {
4333
5487
  }
4334
5488
  return {};
4335
5489
  }
@@ -4638,8 +5792,9 @@ var extractValueField = (elements) => {
4638
5792
  if (!elements) return void 0;
4639
5793
  return elements.find((e) => e.startsWith("value") && e !== "value");
4640
5794
  };
5795
+ var VALUE_PREFIX_RE = /^value/;
4641
5796
  var valueFieldToTsType = (valueField) => {
4642
- const fhirName = valueField.replace(/^value/, "");
5797
+ const fhirName = valueField.replace(VALUE_PREFIX_RE, "");
4643
5798
  const primitives = {
4644
5799
  String: "string",
4645
5800
  Boolean: "boolean",
@@ -4684,7 +5839,7 @@ var collectSubExtensionSlices = (extProfile) => {
4684
5839
  }
4685
5840
  return result;
4686
5841
  };
4687
- var resolveExtensionProfile = (tsIndex, pkgName, url) => {
5842
+ var resolveExtensionProfile2 = (tsIndex, pkgName, url) => {
4688
5843
  const schema = tsIndex.resolveByUrl(pkgName, url);
4689
5844
  if (!schema || !isProfileTypeSchema(schema)) return void 0;
4690
5845
  if (schema.identifier.package !== pkgName) return void 0;
@@ -4757,7 +5912,7 @@ var generateExtensionGetterOverloads = (w, ext, targetPath, methodName, inputTyp
4757
5912
  }
4758
5913
  );
4759
5914
  };
4760
- var generateComplexExtensionSetter = (w, info) => {
5915
+ var generateComplexExtensionSetter2 = (w, info) => {
4761
5916
  const { ext, snapshot, setMethodName, targetPath, extProfileInfo } = info;
4762
5917
  const tsProfileName = tsResourceName(snapshot.identifier);
4763
5918
  const inputTypeName = tsExtensionFlatTypeName(tsProfileName, ext.name);
@@ -4820,7 +5975,7 @@ var generateComplexExtensionSetter = (w, info) => {
4820
5975
  });
4821
5976
  }
4822
5977
  };
4823
- var generateComplexExtensionGetter = (w, info) => {
5978
+ var generateComplexExtensionGetter2 = (w, info) => {
4824
5979
  const { ext, snapshot, getMethodName, targetPath, extProfileInfo } = info;
4825
5980
  const tsProfileName = tsResourceName(snapshot.identifier);
4826
5981
  const inputTypeName = tsExtensionFlatTypeName(tsProfileName, ext.name);
@@ -4836,7 +5991,7 @@ var generateComplexExtensionGetter = (w, info) => {
4836
5991
  w.line(`return extractComplexExtension<${inputType}>(ext, config)`);
4837
5992
  });
4838
5993
  };
4839
- var generateSingleValueExtensionSetter = (w, tsIndex, info) => {
5994
+ var generateSingleValueExtensionSetter2 = (w, tsIndex, info) => {
4840
5995
  const { ext, setMethodName, targetPath, extProfileInfo } = info;
4841
5996
  const firstValueType = ext.valueFieldTypes?.[0];
4842
5997
  if (!firstValueType) return;
@@ -4844,7 +5999,7 @@ var generateSingleValueExtensionSetter = (w, tsIndex, info) => {
4844
5999
  const valueField = tsValueFieldName(firstValueType);
4845
6000
  const useUpsert = ext.max === "1";
4846
6001
  if (extProfileInfo) {
4847
- const extFactoryInfo = collectProfileFactoryInfo(tsIndex, extProfileInfo.snapshot);
6002
+ const extFactoryInfo = collectProfileFactoryInfo2(tsIndex, extProfileInfo.snapshot);
4848
6003
  const extValueParam = extFactoryInfo.params.find((p) => p.name === valueField);
4849
6004
  const resolvedValueType = extValueParam?.tsType ?? valueType;
4850
6005
  const paramType = `${extProfileInfo.className} | Extension | ${resolvedValueType}`;
@@ -4873,7 +6028,7 @@ var generateSingleValueExtensionSetter = (w, tsIndex, info) => {
4873
6028
  });
4874
6029
  }
4875
6030
  };
4876
- var generateSingleValueExtensionGetter = (w, info) => {
6031
+ var generateSingleValueExtensionGetter2 = (w, info) => {
4877
6032
  const { ext, getMethodName, targetPath, extProfileInfo } = info;
4878
6033
  const firstValueType = ext.valueFieldTypes?.[0];
4879
6034
  if (!firstValueType) return;
@@ -4883,7 +6038,7 @@ var generateSingleValueExtensionGetter = (w, info) => {
4883
6038
  w.line(`return getExtensionValue<${valueType}>(ext, "${valueField}")`);
4884
6039
  });
4885
6040
  };
4886
- var generateGenericExtensionSetter = (w, info) => {
6041
+ var generateGenericExtensionSetter2 = (w, info) => {
4887
6042
  const { ext, setMethodName, targetPath } = info;
4888
6043
  const useUpsert = ext.max === "1";
4889
6044
  w.curlyBlock(["public", setMethodName, `(value: Omit<Extension, "url"> | Extension): this`], () => {
@@ -4899,7 +6054,7 @@ var generateGenericExtensionSetter = (w, info) => {
4899
6054
  w.line("return this");
4900
6055
  });
4901
6056
  };
4902
- var generateGenericExtensionGetter = (w, info) => {
6057
+ var generateGenericExtensionGetter2 = (w, info) => {
4903
6058
  const { ext, getMethodName, targetPath } = info;
4904
6059
  w.curlyBlock(["public", getMethodName, "(): Extension | undefined"], () => {
4905
6060
  if (targetPath.length === 0) {
@@ -4912,12 +6067,12 @@ var generateGenericExtensionGetter = (w, info) => {
4912
6067
  }
4913
6068
  });
4914
6069
  };
4915
- var generateExtensionMethods = (w, tsIndex, snapshot) => {
6070
+ var generateExtensionMethods2 = (w, tsIndex, snapshot) => {
4916
6071
  for (const ext of snapshot.extensions ?? []) {
4917
6072
  if (!ext.url) continue;
4918
6073
  const baseName = ext.nameCandidates.recommended;
4919
6074
  const targetPath = ext.path.split(".").filter((segment) => segment !== "extension");
4920
- const extProfileInfo = resolveExtensionProfile(tsIndex, snapshot.identifier.package, ext.url);
6075
+ const extProfileInfo = resolveExtensionProfile2(tsIndex, snapshot.identifier.package, ext.url);
4921
6076
  const info = {
4922
6077
  ext,
4923
6078
  snapshot,
@@ -4927,17 +6082,17 @@ var generateExtensionMethods = (w, tsIndex, snapshot) => {
4927
6082
  extProfileInfo
4928
6083
  };
4929
6084
  if (ext.isComplex && ext.subExtensions) {
4930
- generateComplexExtensionSetter(w, info);
6085
+ generateComplexExtensionSetter2(w, info);
4931
6086
  w.line();
4932
- generateComplexExtensionGetter(w, info);
6087
+ generateComplexExtensionGetter2(w, info);
4933
6088
  } else if (ext.valueFieldTypes?.length === 1 && ext.valueFieldTypes[0]) {
4934
- generateSingleValueExtensionSetter(w, tsIndex, info);
6089
+ generateSingleValueExtensionSetter2(w, tsIndex, info);
4935
6090
  w.line();
4936
- generateSingleValueExtensionGetter(w, info);
6091
+ generateSingleValueExtensionGetter2(w, info);
4937
6092
  } else {
4938
- generateGenericExtensionSetter(w, info);
6093
+ generateGenericExtensionSetter2(w, info);
4939
6094
  w.line();
4940
- generateGenericExtensionGetter(w, info);
6095
+ generateGenericExtensionGetter2(w, info);
4941
6096
  }
4942
6097
  w.line();
4943
6098
  }
@@ -5026,7 +6181,7 @@ var collectTypesFromSlices = (tsIndex, snapshot, addType) => {
5026
6181
  }
5027
6182
  }
5028
6183
  };
5029
- var collectRequiredSliceNames = (field) => {
6184
+ var collectRequiredSliceNames2 = (field) => {
5030
6185
  if (!field.array || !field.slicing?.slices) return void 0;
5031
6186
  const isTypeDisc = field.slicing.discriminator?.some((d) => d.type === "type") ?? false;
5032
6187
  if (isTypeDisc) return void 0;
@@ -5038,7 +6193,7 @@ var collectRequiredSliceNames = (field) => {
5038
6193
  }).map(([name]) => name);
5039
6194
  return names.length > 0 ? names : void 0;
5040
6195
  };
5041
- var collectSliceDefs = (tsIndex, snapshot) => Object.entries(snapshot.fields).filter(([_, field]) => isNotChoiceDeclarationField(field) && field.slicing?.slices).flatMap(([fieldName, field]) => {
6196
+ var collectSliceDefs2 = (tsIndex, snapshot) => Object.entries(snapshot.fields).filter(([_, field]) => isNotChoiceDeclarationField(field) && field.slicing?.slices).flatMap(([fieldName, field]) => {
5042
6197
  if (!isNotChoiceDeclarationField(field) || !field.slicing?.slices || !field.type) return [];
5043
6198
  const baseType = tsTypeFromIdentifier(field.type);
5044
6199
  const pkgName = snapshot.identifier.package;
@@ -5069,7 +6224,7 @@ var collectSliceDefs = (tsIndex, snapshot) => Object.entries(snapshot.fields).fi
5069
6224
  };
5070
6225
  });
5071
6226
  });
5072
- var generateSliceSetters = (w, sliceDefs, snapshot) => {
6227
+ var generateSliceSetters2 = (w, sliceDefs, snapshot) => {
5073
6228
  const profileClassName = tsProfileClassName(snapshot);
5074
6229
  const tsProfileName = tsResourceName(snapshot.identifier);
5075
6230
  for (const sliceDef of sliceDefs) {
@@ -5133,7 +6288,7 @@ var generateSliceSetters = (w, sliceDefs, snapshot) => {
5133
6288
  w.line();
5134
6289
  }
5135
6290
  };
5136
- var generateSliceGetters = (w, sliceDefs, snapshot) => {
6291
+ var generateSliceGetters2 = (w, sliceDefs, snapshot) => {
5137
6292
  const profileClassName = tsProfileClassName(snapshot);
5138
6293
  const tsProfileName = tsResourceName(snapshot.identifier);
5139
6294
  const defaultMode = w.opts.sliceGetterDefault ?? "flat";
@@ -5266,7 +6421,7 @@ var collectRegularFieldValidation = (errors, warnings, name, field, resolveRef,
5266
6421
  }
5267
6422
  }
5268
6423
  };
5269
- var generateValidateMethod = (w, tsIndex, snapshot) => {
6424
+ var generateValidateMethod2 = (w, tsIndex, snapshot) => {
5270
6425
  const fields = snapshot.fields;
5271
6426
  const profileName = snapshot.identifier.name;
5272
6427
  const canonicalUrl = snapshot.identifier.url;
@@ -5343,7 +6498,7 @@ var collectChoiceAccessors = (snapshot, promotedChoices) => {
5343
6498
  }));
5344
6499
  return { accessors, choiceClearMethods };
5345
6500
  };
5346
- var tryPromoteChoice = (field, fields, params, promotedChoices, resolveRef, isFamilyType) => {
6501
+ var tryPromoteChoice2 = (field, fields, params, promotedChoices, resolveRef, isFamilyType) => {
5347
6502
  if (!isChoiceDeclarationField(field) || !field.required || field.choices.length !== 1) return;
5348
6503
  const choiceName = field.choices[0];
5349
6504
  if (!choiceName) return;
@@ -5358,7 +6513,7 @@ var mkIsFamilyType = (tsIndex) => (ref) => {
5358
6513
  if (!schema || !("typeFamily" in schema)) return false;
5359
6514
  return (schema.typeFamily?.resources?.length ?? 0) > 0;
5360
6515
  };
5361
- var collectProfileFactoryInfo = (tsIndex, snapshot) => {
6516
+ var collectProfileFactoryInfo2 = (tsIndex, snapshot) => {
5362
6517
  const autoFields = [];
5363
6518
  const sliceAutoFields = [];
5364
6519
  const params = [];
@@ -5375,7 +6530,7 @@ var collectProfileFactoryInfo = (tsIndex, snapshot) => {
5375
6530
  if (field.excluded) continue;
5376
6531
  if (isChoiceInstanceField(field)) continue;
5377
6532
  if (isChoiceDeclarationField(field)) {
5378
- tryPromoteChoice(field, fields, params, promotedChoices, resolveRef, isFamilyType);
6533
+ tryPromoteChoice2(field, fields, params, promotedChoices, resolveRef, isFamilyType);
5379
6534
  continue;
5380
6535
  }
5381
6536
  if (field.valueConstraint) {
@@ -5389,7 +6544,7 @@ var collectProfileFactoryInfo = (tsIndex, snapshot) => {
5389
6544
  continue;
5390
6545
  }
5391
6546
  if (isNotChoiceDeclarationField(field)) {
5392
- const sliceNames = collectRequiredSliceNames(field);
6547
+ const sliceNames = collectRequiredSliceNames2(field);
5393
6548
  if (sliceNames) {
5394
6549
  if (field.type) {
5395
6550
  const tsType = fieldTsType(field, resolveRef, isFamilyType);
@@ -5409,7 +6564,7 @@ var collectProfileFactoryInfo = (tsIndex, snapshot) => {
5409
6564
  params.push({ name, tsType, typeId: field.type });
5410
6565
  }
5411
6566
  }
5412
- collectBaseRequiredParams(
6567
+ collectBaseRequiredParams2(
5413
6568
  tsIndex,
5414
6569
  snapshot,
5415
6570
  resolveRef,
@@ -5426,7 +6581,7 @@ var collectProfileFactoryInfo = (tsIndex, snapshot) => {
5426
6581
  const accessors = [...autoAccessors, ...choiceAccessors];
5427
6582
  return { autoFields, sliceAutoFields, params, accessors, choiceClearMethods, fixedFields };
5428
6583
  };
5429
- var collectBaseRequiredParams = (tsIndex, snapshot, resolveRef, params, coveredNames, isFamilyType) => {
6584
+ var collectBaseRequiredParams2 = (tsIndex, snapshot, resolveRef, params, coveredNames, isFamilyType) => {
5430
6585
  const covered = new Set(coveredNames);
5431
6586
  const baseSchema = tsIndex.resolveType(snapshot.base);
5432
6587
  if (!baseSchema || !("fields" in baseSchema) || !baseSchema.fields) return;
@@ -5516,7 +6671,7 @@ var generateProfileImports = (w, tsIndex, snapshot) => {
5516
6671
  collectTypesFromSlices(tsIndex, snapshot, addType);
5517
6672
  const needsExtensionType = collectTypesFromExtensions(tsIndex, snapshot, addType);
5518
6673
  collectTypesFromFlatInput(tsIndex, snapshot, addType);
5519
- const factoryInfo = collectProfileFactoryInfo(tsIndex, snapshot);
6674
+ const factoryInfo = collectProfileFactoryInfo2(tsIndex, snapshot);
5520
6675
  for (const param of factoryInfo.params) addType(param.typeId);
5521
6676
  for (const f of factoryInfo.sliceAutoFields) addType(f.typeId);
5522
6677
  for (const accessor of factoryInfo.accessors) addType(accessor.typeId);
@@ -5542,7 +6697,7 @@ var generateProfileImports = (w, tsIndex, snapshot) => {
5542
6697
  const extProfileImports = /* @__PURE__ */ new Map();
5543
6698
  for (const ext of snapshot.extensions ?? []) {
5544
6699
  if (!ext.url) continue;
5545
- const info = resolveExtensionProfile(tsIndex, snapshot.identifier.package, ext.url);
6700
+ const info = resolveExtensionProfile2(tsIndex, snapshot.identifier.package, ext.url);
5546
6701
  if (!info) continue;
5547
6702
  if (!extProfileImports.has(info.className)) {
5548
6703
  const hasFlatInput = collectSubExtensionSlices(info.snapshot).length > 0;
@@ -5557,7 +6712,7 @@ var generateProfileImports = (w, tsIndex, snapshot) => {
5557
6712
  }
5558
6713
  if (extProfileImports.size > 0) w.line();
5559
6714
  };
5560
- var generateStaticSliceFields = (w, sliceDefs) => {
6715
+ var generateStaticSliceFields2 = (w, sliceDefs) => {
5561
6716
  for (const sliceDef of sliceDefs) {
5562
6717
  const staticName = `${tsSliceStaticName(sliceDef.sliceName)}SliceMatch`;
5563
6718
  const json = JSON.stringify(sliceDef.match);
@@ -5779,7 +6934,7 @@ var generateFactoryMethods = (w, tsIndex, snapshot, factoryInfo) => {
5779
6934
  });
5780
6935
  w.line();
5781
6936
  };
5782
- var generateFieldAccessors = (w, factoryInfo) => {
6937
+ var generateFieldAccessors2 = (w, factoryInfo) => {
5783
6938
  w.line("// Field accessors");
5784
6939
  for (const p of factoryInfo.params) {
5785
6940
  const methodBaseName = uppercaseFirstLetter(p.name);
@@ -5821,7 +6976,7 @@ var generateInlineExtensionInputTypes = (w, tsIndex, snapshot) => {
5821
6976
  const complexExtensions = (snapshot.extensions ?? []).filter((ext) => ext.isComplex && ext.subExtensions);
5822
6977
  for (const ext of complexExtensions) {
5823
6978
  if (!ext.url) continue;
5824
- const extProfileInfo = resolveExtensionProfile(tsIndex, snapshot.identifier.package, ext.url);
6979
+ const extProfileInfo = resolveExtensionProfile2(tsIndex, snapshot.identifier.package, ext.url);
5825
6980
  const hasFlatInput = extProfileInfo ? collectSubExtensionSlices(extProfileInfo.snapshot).length > 0 : false;
5826
6981
  if (hasFlatInput) continue;
5827
6982
  const typeName = tsExtensionFlatTypeName(tsProfileName, ext.name);
@@ -5927,8 +7082,8 @@ var generateFlatInputType = (w, snapshot) => {
5927
7082
  var generateProfileClass = (w, tsIndex, snapshot) => {
5928
7083
  const tsBaseResourceName = tsTypeFromIdentifier(snapshot.base);
5929
7084
  const profileClassName = tsProfileClassName(snapshot);
5930
- const sliceDefs = collectSliceDefs(tsIndex, snapshot);
5931
- const factoryInfo = collectProfileFactoryInfo(tsIndex, snapshot);
7085
+ const sliceDefs = collectSliceDefs2(tsIndex, snapshot);
7086
+ const factoryInfo = collectProfileFactoryInfo2(tsIndex, snapshot);
5932
7087
  generateInlineExtensionInputTypes(w, tsIndex, snapshot);
5933
7088
  generateSliceInputTypes(w, snapshot, sliceDefs);
5934
7089
  generateProfileHelpersImport(w, tsIndex, snapshot, sliceDefs, factoryInfo);
@@ -5939,18 +7094,18 @@ var generateProfileClass = (w, tsIndex, snapshot) => {
5939
7094
  w.curlyBlock(["export", "class", profileClassName], () => {
5940
7095
  w.lineSM(`static readonly canonicalUrl = ${JSON.stringify(canonicalUrl)}`);
5941
7096
  w.line();
5942
- generateStaticSliceFields(w, sliceDefs);
7097
+ generateStaticSliceFields2(w, sliceDefs);
5943
7098
  w.lineSM(`private resource: ${tsBaseResourceName}`);
5944
7099
  w.line();
5945
7100
  generateFactoryMethods(w, tsIndex, snapshot, factoryInfo);
5946
- generateFieldAccessors(w, factoryInfo);
7101
+ generateFieldAccessors2(w, factoryInfo);
5947
7102
  w.line("// Extensions");
5948
- generateExtensionMethods(w, tsIndex, snapshot);
7103
+ generateExtensionMethods2(w, tsIndex, snapshot);
5949
7104
  w.line("// Slices");
5950
- generateSliceSetters(w, sliceDefs, snapshot);
5951
- generateSliceGetters(w, sliceDefs, snapshot);
7105
+ generateSliceSetters2(w, sliceDefs, snapshot);
7106
+ generateSliceGetters2(w, sliceDefs, snapshot);
5952
7107
  w.line("// Validation");
5953
- generateValidateMethod(w, tsIndex, snapshot);
7108
+ generateValidateMethod2(w, tsIndex, snapshot);
5954
7109
  });
5955
7110
  w.line();
5956
7111
  };
@@ -5964,7 +7119,7 @@ var resolveTsAssets = (fn) => {
5964
7119
  }
5965
7120
  return Path5.resolve(__dirname, "../../../..", "assets", "api", "writer-generator", "typescript", fn);
5966
7121
  };
5967
- var leafOf2 = (path) => path[path.length - 1] ?? "";
7122
+ var leafOf3 = (path) => path[path.length - 1] ?? "";
5968
7123
  var TS_HARDCODED_GENERIC_NAMES = /* @__PURE__ */ new Set(["Reference", "Coding", "CodeableConcept"]);
5969
7124
  var TypeScript = class extends Writer {
5970
7125
  constructor(options) {
@@ -6107,11 +7262,11 @@ var TypeScript = class extends Writer {
6107
7262
  const targetParams = isNestedTypeSchema(target) || isSpecializationTypeSchema(target) ? target.generic?.params : void 0;
6108
7263
  if (targetParams?.length) {
6109
7264
  const args = targetParams.map(
6110
- (tp) => params.find((q) => leafOf2(q.path) === leafOf2(tp.path))?.typeVar ?? tp.typeVar
7265
+ (tp) => params.find((q) => leafOf3(q.path) === leafOf3(tp.path))?.typeVar ?? tp.typeVar
6111
7266
  );
6112
7267
  nestedArgsByField[tsName] = `<${args.join(", ")}>`;
6113
7268
  } else if (isSpecializationTypeSchema(target) && (target.typeFamily?.resources?.length ?? 0) > 0) {
6114
- const p = params.find((q) => leafOf2(q.path) === fieldName);
7269
+ const p = params.find((q) => leafOf3(q.path) === fieldName);
6115
7270
  if (p) fieldMap[tsName] = p.typeVar;
6116
7271
  }
6117
7272
  }
@@ -6432,7 +7587,7 @@ var APIBuilder = class {
6432
7587
  const defaultPyOpts = {
6433
7588
  ...defaultWriterOpts,
6434
7589
  rootPackageName: "fhir_types",
6435
- fieldFormat: "snake_case",
7590
+ fieldFormat: "camelCase",
6436
7591
  primitiveTypeExtension: false
6437
7592
  };
6438
7593
  const opts = {
@@ -6550,7 +7705,7 @@ var APIBuilder = class {
6550
7705
  };
6551
7706
  this.logger.debug(`Starting generation with ${this.generators.length} generators`);
6552
7707
  try {
6553
- if (this.options.cleanOutput) cleanup(this.options, this.logger);
7708
+ if (this.options.cleanOutput) await cleanup(this.options, this.logger);
6554
7709
  let register;
6555
7710
  if (this.prebuiltRegister) {
6556
7711
  this.logger.info("Using prebuilt register");