@treeviz/gedcom-parser 2.0.8 → 2.0.10

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.
Files changed (37) hide show
  1. package/dist/classes/index.js +627 -159
  2. package/dist/classes/indi.d.ts.map +1 -1
  3. package/dist/cli/index.js +627 -159
  4. package/dist/constants/index.js +626 -158
  5. package/dist/factories/index.js +626 -158
  6. package/dist/index.js +628 -160
  7. package/dist/kinship-translator/index.d.ts +1 -0
  8. package/dist/kinship-translator/index.d.ts.map +1 -1
  9. package/dist/kinship-translator/index.js +627 -159
  10. package/dist/kinship-translator/kinship-translator.basic.d.ts +11 -0
  11. package/dist/kinship-translator/kinship-translator.basic.d.ts.map +1 -1
  12. package/dist/kinship-translator/kinship-translator.d.ts.map +1 -1
  13. package/dist/kinship-translator/kinship-translator.de.d.ts +2 -1
  14. package/dist/kinship-translator/kinship-translator.de.d.ts.map +1 -1
  15. package/dist/kinship-translator/kinship-translator.en.d.ts +2 -1
  16. package/dist/kinship-translator/kinship-translator.en.d.ts.map +1 -1
  17. package/dist/kinship-translator/kinship-translator.es.d.ts +2 -1
  18. package/dist/kinship-translator/kinship-translator.es.d.ts.map +1 -1
  19. package/dist/kinship-translator/kinship-translator.fr.d.ts +2 -1
  20. package/dist/kinship-translator/kinship-translator.fr.d.ts.map +1 -1
  21. package/dist/kinship-translator/kinship-translator.hu.d.ts +8 -1
  22. package/dist/kinship-translator/kinship-translator.hu.d.ts.map +1 -1
  23. package/dist/kinship-translator/kinship-translator.interface.d.ts +1 -0
  24. package/dist/kinship-translator/kinship-translator.interface.d.ts.map +1 -1
  25. package/dist/kinship-translator/kinship-translator.ru.d.ts +18 -0
  26. package/dist/kinship-translator/kinship-translator.ru.d.ts.map +1 -0
  27. package/dist/kinship-translator/patterns.es.d.ts.map +1 -1
  28. package/dist/kinship-translator/patterns.ru.d.ts +2 -0
  29. package/dist/kinship-translator/patterns.ru.d.ts.map +1 -0
  30. package/dist/kinship-translator/translators.d.ts +1 -0
  31. package/dist/kinship-translator/translators.d.ts.map +1 -1
  32. package/dist/kinship-translator/types.d.ts +1 -1
  33. package/dist/kinship-translator/types.d.ts.map +1 -1
  34. package/dist/utils/cache.d.ts +14 -1
  35. package/dist/utils/cache.d.ts.map +1 -1
  36. package/dist/utils/index.js +628 -160
  37. package/package.json +1 -1
@@ -48,6 +48,44 @@ var KinshipTranslatorBasic = class {
48
48
  }
49
49
  return this.pathN?.indi;
50
50
  }
51
+ /**
52
+ * True when the path goes through a common ancestor whose two children
53
+ * (the person we came from and the person we go to) share fewer than two
54
+ * biological parents — i.e. they are half-siblings, so every collateral
55
+ * relative on this path is a half-aunt/half-cousin/... too.
56
+ *
57
+ * Direct ancestors/descendants and paths that already use a
58
+ * step/adopted/foster edge are never half-blood.
59
+ */
60
+ get isHalfBlood() {
61
+ const path = this.path;
62
+ if (!path || path.length < 3) {
63
+ return false;
64
+ }
65
+ if (path.some(
66
+ (item) => item.relation && item.relation !== "biological" /* BIOLOGICAL */
67
+ )) {
68
+ return false;
69
+ }
70
+ let peakIndex = -1;
71
+ for (let i = 1; i < path.length; i++) {
72
+ if (path[i].kinship === "parent") {
73
+ peakIndex = i;
74
+ }
75
+ }
76
+ if (peakIndex <= 0 || peakIndex >= path.length - 1) {
77
+ return false;
78
+ }
79
+ if (path[peakIndex + 1].kinship !== "child") {
80
+ return false;
81
+ }
82
+ const siblingA = path[peakIndex - 1].indi;
83
+ const siblingB = path[peakIndex + 1].indi;
84
+ const parentsA = siblingA.getBiologicalParents();
85
+ const parentsB = siblingB.getBiologicalParents();
86
+ const inter = parentsA.intersection(parentsB);
87
+ return inter.length === 1 && (parentsA.length > 1 || parentsB.length > 1);
88
+ }
51
89
  indirect() {
52
90
  return "";
53
91
  }
@@ -75,6 +113,9 @@ var KinshipTranslatorBasic = class {
75
113
  relationType(relation) {
76
114
  return relation ?? "";
77
115
  }
116
+ halfBlood(relation) {
117
+ return relation ?? "";
118
+ }
78
119
  of(relation) {
79
120
  return relation ?? "";
80
121
  }
@@ -153,7 +194,8 @@ __export(translators_exports, {
153
194
  en: () => KinshipTranslatorEn,
154
195
  es: () => KinshipTranslatorEs,
155
196
  fr: () => KinshipTranslatorFr,
156
- hu: () => KinshipTranslatorHU
197
+ hu: () => KinshipTranslatorHU,
198
+ ru: () => KinshipTranslatorRu
157
199
  });
158
200
 
159
201
  // src/utils/ordinalize.ts
@@ -482,14 +524,34 @@ var KinshipTranslatorHU = class extends KinshipTranslatorBasic {
482
524
  return `${prefix.replace(/nagy$/, "")}unoka`;
483
525
  }
484
526
  sibling() {
485
- const parents1 = this.person1?.getBiologicalParents();
486
- const parentsN = this.personN?.getBiologicalParents();
487
- const inter = parents1?.intersection(parentsN);
488
- if (!inter || inter.length < 2) {
489
- return "f\xE9ltestv\xE9r";
490
- }
491
527
  return "testv\xE9r";
492
528
  }
529
+ halfBlood(relation) {
530
+ if (!relation || !this.isHalfBlood) {
531
+ return relation ?? "";
532
+ }
533
+ const [head, ...rest] = relation.split(" ");
534
+ if (!head) {
535
+ return relation;
536
+ }
537
+ const prefixed = this.prefixHalf(head);
538
+ return [prefixed, ...rest].join(" ");
539
+ }
540
+ /**
541
+ * AkH. 139: compounds of more than two members stay closed up to 6
542
+ * syllables; longer ones are hyphenated at the main boundary. A head
543
+ * that is already hyphenated also takes a hyphenated half- prefix.
544
+ */
545
+ prefixHalf(head) {
546
+ if (head.includes("-") || !/[aáeéiíoóöőuúüű]/i.test(head)) {
547
+ return `f\xE9l-${head}`;
548
+ }
549
+ const syllables = (head.match(/[aáeéiíoóöőuúüű]/gi) ?? []).length + 1;
550
+ if (syllables > 6) {
551
+ return `f\xE9l-${head}`;
552
+ }
553
+ return `f\xE9l${head}`;
554
+ }
493
555
  spouse() {
494
556
  if (this.personN?.isMale()) {
495
557
  return "f\xE9rj";
@@ -688,20 +750,22 @@ var KinshipTranslatorEn = class extends KinshipTranslatorBasic {
688
750
  return `${prefix}child`;
689
751
  }
690
752
  sibling() {
691
- const parents1 = this.person1?.getBiologicalParents();
692
- const parentsN = this.personN?.getBiologicalParents();
693
- const inter = parents1?.intersection(parentsN);
694
- let prefix = "";
695
- if (!inter || inter.length < 2) {
696
- prefix = "half-";
697
- }
698
753
  if (this.personN?.isMale()) {
699
- return `${prefix}brother`;
754
+ return "brother";
700
755
  }
701
756
  if (this.personN?.isFemale()) {
702
- return `${prefix}sister`;
757
+ return "sister";
703
758
  }
704
- return `${prefix}sibling`;
759
+ return "sibling";
760
+ }
761
+ halfBlood(relation) {
762
+ if (!relation || !this.isHalfBlood) {
763
+ return relation ?? "";
764
+ }
765
+ if (relation.includes(" ")) {
766
+ return `half ${relation}`;
767
+ }
768
+ return `half-${relation}`;
705
769
  }
706
770
  spouse() {
707
771
  if (this.personN?.isMale()) {
@@ -883,20 +947,19 @@ var KinshipTranslatorFr = class extends KinshipTranslatorBasic {
883
947
  return `${prefix}enfant`;
884
948
  }
885
949
  sibling() {
886
- const parents1 = this.person1?.getBiologicalParents();
887
- const parentsN = this.personN?.getBiologicalParents();
888
- const inter = parents1?.intersection(parentsN);
889
- let prefix = "";
890
- if (!inter || inter.length < 2) {
891
- prefix = "demi-";
892
- }
893
950
  if (this.personN?.isMale()) {
894
- return `${prefix}fr\xE8re`;
951
+ return "fr\xE8re";
895
952
  }
896
953
  if (this.personN?.isFemale()) {
897
- return `${prefix}s\u0153ur`;
954
+ return "s\u0153ur";
955
+ }
956
+ return "fr\xE8re/s\u0153ur";
957
+ }
958
+ halfBlood(relation) {
959
+ if (!relation || !this.isHalfBlood) {
960
+ return relation ?? "";
898
961
  }
899
- return `${prefix}fr\xE8re/s\u0153ur`;
962
+ return `demi-${relation}`;
900
963
  }
901
964
  spouse() {
902
965
  if (this.personN?.isMale()) {
@@ -993,12 +1056,12 @@ var InLawsEs = {
993
1056
  "madre del (c\xF3nyuge|esposa|esposo)": "suegra",
994
1057
  "padre del (c\xF3nyuge|esposa|esposo)": "suegro",
995
1058
  "padre/madre del (c\xF3nyuge|esposa|esposo)": "suegro/suegra",
996
- "esposa de (medio )?(hermano/hermana|hermana|hermano)": "cu\xF1ada",
997
- "esposo de (medio )?(hermano/hermana|hermana|hermano)": "cu\xF1ado",
998
- "c\xF3nyuge de (medio )?(hermano/hermana|hermana|hermano)": "cu\xF1ado/cu\xF1ada",
999
- "(medio )?hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ada",
1000
- "(medio )?hermano del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado",
1001
- "(medio )?hermano/hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado/cu\xF1ada"
1059
+ "esposa de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ada",
1060
+ "esposo de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ado",
1061
+ "c\xF3nyuge de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ado/cu\xF1ada",
1062
+ "(medio |media |medio/a )?hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ada",
1063
+ "(medio |media |medio/a )?hermano del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado",
1064
+ "(medio |media |medio/a )?hermano/hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado/cu\xF1ada"
1002
1065
  };
1003
1066
 
1004
1067
  // src/kinship-translator/kinship-translator.es.ts
@@ -1078,20 +1141,25 @@ var KinshipTranslatorEs = class extends KinshipTranslatorBasic {
1078
1141
  return `${prefix}hijo/hija`;
1079
1142
  }
1080
1143
  sibling() {
1081
- const parents1 = this.person1?.getBiologicalParents();
1082
- const parentsN = this.personN?.getBiologicalParents();
1083
- const inter = parents1?.intersection(parentsN);
1084
- let prefix = "";
1085
- if (!inter || inter.length < 2) {
1086
- prefix = "medio ";
1087
- }
1088
1144
  if (this.personN?.isMale()) {
1089
- return `${prefix}hermano`;
1145
+ return "hermano";
1090
1146
  }
1091
1147
  if (this.personN?.isFemale()) {
1092
- return `${prefix}hermana`;
1148
+ return "hermana";
1093
1149
  }
1094
- return `${prefix}hermano/hermana`;
1150
+ return "hermano/hermana";
1151
+ }
1152
+ halfBlood(relation) {
1153
+ if (!relation || !this.isHalfBlood) {
1154
+ return relation ?? "";
1155
+ }
1156
+ if (this.personN?.isFemale()) {
1157
+ return `media ${relation}`;
1158
+ }
1159
+ if (this.personN?.isMale()) {
1160
+ return `medio ${relation}`;
1161
+ }
1162
+ return `medio/a ${relation}`;
1095
1163
  }
1096
1164
  spouse() {
1097
1165
  if (this.personN?.isMale()) {
@@ -1180,6 +1248,249 @@ var KinshipTranslatorEs = class extends KinshipTranslatorBasic {
1180
1248
  }
1181
1249
  };
1182
1250
 
1251
+ // src/kinship-translator/patterns.ru.ts
1252
+ var InLawsRu = {
1253
+ "\u0441\u0443\u043F\u0440\u0443\u0433(?:\u0430)? (\u0440\u0435\u0431\u0451\u043D\u043A\u0430|\u0434\u043E\u0447\u0435\u0440\u0438|\u0441\u044B\u043D\u0430)": "\u0437\u044F\u0442\u044C/\u043D\u0435\u0432\u0435\u0441\u0442\u043A\u0430",
1254
+ "\u0436\u0435\u043D\u0430 (\u0440\u0435\u0431\u0451\u043D\u043A\u0430|\u0434\u043E\u0447\u0435\u0440\u0438|\u0441\u044B\u043D\u0430)": "\u043D\u0435\u0432\u0435\u0441\u0442\u043A\u0430",
1255
+ "\u043C\u0443\u0436 (\u0440\u0435\u0431\u0451\u043D\u043A\u0430|\u0434\u043E\u0447\u0435\u0440\u0438|\u0441\u044B\u043D\u0430)": "\u0437\u044F\u0442\u044C",
1256
+ "\u043C\u0430\u0442\u044C (\u0441\u0443\u043F\u0440\u0443\u0433\u0430|\u0436\u0435\u043D\u044B|\u043C\u0443\u0436\u0430)": "\u0442\u0451\u0449\u0430",
1257
+ "\u043E\u0442\u0435\u0446 (\u0441\u0443\u043F\u0440\u0443\u0433\u0430|\u0436\u0435\u043D\u044B|\u043C\u0443\u0436\u0430)": "\u0442\u0435\u0441\u0442\u044C",
1258
+ "\u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C (\u0441\u0443\u043F\u0440\u0443\u0433\u0430|\u0436\u0435\u043D\u044B|\u043C\u0443\u0436\u0430)": "\u0442\u0435\u0441\u0442\u044C/\u0442\u0451\u0449\u0430",
1259
+ "\u0436\u0435\u043D\u0430 (\u0441\u0432\u043E\u0434\u043D(?:\u044B\u0439|\u0430\u044F) )?(\u0431\u0440\u0430\u0442\u0430|\u0441\u0435\u0441\u0442\u0440\u044B|\u0441\u0438\u0431\u043B\u0438\u043D\u0433\u0430)": "\u043D\u0435\u0432\u0435\u0441\u0442\u043A\u0430",
1260
+ "\u043C\u0443\u0436 (\u0441\u0432\u043E\u0434\u043D(?:\u044B\u0439|\u0430\u044F) )?(\u0431\u0440\u0430\u0442\u0430|\u0441\u0435\u0441\u0442\u0440\u044B|\u0441\u0438\u0431\u043B\u0438\u043D\u0433\u0430)": "\u0437\u044F\u0442\u044C",
1261
+ "\u0441\u0443\u043F\u0440\u0443\u0433(?:\u0430)? (\u0441\u0432\u043E\u0434\u043D(?:\u044B\u0439|\u0430\u044F) )?(\u0431\u0440\u0430\u0442\u0430|\u0441\u0435\u0441\u0442\u0440\u044B|\u0441\u0438\u0431\u043B\u0438\u043D\u0433\u0430)": "\u0437\u044F\u0442\u044C/\u043D\u0435\u0432\u0435\u0441\u0442\u043A\u0430",
1262
+ "(\u0441\u0432\u043E\u0434\u043D(?:\u044B\u0439|\u0430\u044F) )?\u0441\u0435\u0441\u0442\u0440\u0430 (\u0441\u0443\u043F\u0440\u0443\u0433\u0430|\u0436\u0435\u043D\u044B|\u043C\u0443\u0436\u0430)": "\u0437\u043E\u043B\u043E\u0432\u043A\u0430",
1263
+ "(\u0441\u0432\u043E\u0434\u043D(?:\u044B\u0439|\u0430\u044F) )?\u0431\u0440\u0430\u0442 (\u0441\u0443\u043F\u0440\u0443\u0433\u0430|\u0436\u0435\u043D\u044B|\u043C\u0443\u0436\u0430)": "\u0448\u0443\u0440\u0438\u043D",
1264
+ "(\u0441\u0432\u043E\u0434\u043D(?:\u044B\u0439|\u0430\u044F) )?\u0441\u0438\u0431\u043B\u0438\u043D\u0433 (\u0441\u0443\u043F\u0440\u0443\u0433\u0430|\u0436\u0435\u043D\u044B|\u043C\u0443\u0436\u0430)": "\u0448\u0443\u0440\u0438\u043D/\u0437\u043E\u043B\u043E\u0432\u043A\u0430"
1265
+ };
1266
+
1267
+ // src/kinship-translator/kinship-translator.ru.ts
1268
+ var GENITIVE = {
1269
+ \u0441\u044B\u043D: "\u0441\u044B\u043D\u0430",
1270
+ \u0434\u043E\u0447\u044C: "\u0434\u043E\u0447\u0435\u0440\u0438",
1271
+ \u0440\u0435\u0431\u0451\u043D\u043E\u043A: "\u0440\u0435\u0431\u0451\u043D\u043A\u0430",
1272
+ \u0431\u0440\u0430\u0442: "\u0431\u0440\u0430\u0442\u0430",
1273
+ \u0441\u0435\u0441\u0442\u0440\u0430: "\u0441\u0435\u0441\u0442\u0440\u044B",
1274
+ \u0441\u0438\u0431\u043B\u0438\u043D\u0433: "\u0441\u0438\u0431\u043B\u0438\u043D\u0433\u0430",
1275
+ \u043E\u0442\u0435\u0446: "\u043E\u0442\u0446\u0430",
1276
+ \u043C\u0430\u0442\u044C: "\u043C\u0430\u0442\u0435\u0440\u0438",
1277
+ \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C: "\u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044F",
1278
+ \u043C\u0443\u0436: "\u043C\u0443\u0436\u0430",
1279
+ \u0436\u0435\u043D\u0430: "\u0436\u0435\u043D\u044B",
1280
+ \u0441\u0443\u043F\u0440\u0443\u0433: "\u0441\u0443\u043F\u0440\u0443\u0433\u0430",
1281
+ \u0441\u0443\u043F\u0440\u0443\u0433\u0430: "\u0441\u0443\u043F\u0440\u0443\u0433\u0438"
1282
+ };
1283
+ var toGenitive = (word) => GENITIVE[word] ?? word;
1284
+ var cousinWord = (degree, sex) => {
1285
+ const stem = degree <= 1 ? "\u0434\u0432\u043E\u044E\u0440\u043E\u0434\u043D" : degree === 2 ? "\u0442\u0440\u043E\u044E\u0440\u043E\u0434\u043D" : degree === 3 ? "\u0447\u0435\u0442\u0432\u0435\u0440\u043E\u044E\u0440\u043E\u0434\u043D" : `${degree + 1}-\u044E\u0440\u043E\u0434\u043D`;
1286
+ if (sex === "m") {
1287
+ return `${stem}\u044B\u0439 \u0431\u0440\u0430\u0442`;
1288
+ }
1289
+ if (sex === "f") {
1290
+ return `${stem}\u0430\u044F \u0441\u0435\u0441\u0442\u0440\u0430`;
1291
+ }
1292
+ return `${stem}\u044B\u0439 \u0431\u0440\u0430\u0442/\u0441\u0435\u0441\u0442\u0440\u0430`;
1293
+ };
1294
+ var praRepeat = (count) => count > 0 ? "\u043F\u0440\u0430".repeat(count) : "";
1295
+ var sexOf = (person) => {
1296
+ if (person?.isMale?.()) {
1297
+ return "m";
1298
+ }
1299
+ if (person?.isFemale?.()) {
1300
+ return "f";
1301
+ }
1302
+ return "n";
1303
+ };
1304
+ var KinshipTranslatorRu = class extends KinshipTranslatorBasic {
1305
+ indirect() {
1306
+ let degree = Math.abs(this.pathN?.degree ?? 0);
1307
+ if (degree > 0) {
1308
+ degree = degree - 1;
1309
+ }
1310
+ return cousinWord(degree, sexOf(this.personN));
1311
+ }
1312
+ removal() {
1313
+ const level = this.pathN?.level ?? 0;
1314
+ let degree = Math.abs(this.pathN?.degree ?? 0);
1315
+ if (degree > 0) {
1316
+ degree = degree - 1;
1317
+ }
1318
+ if (!degree) {
1319
+ return level < 0 ? this.nibling() : this.auncle();
1320
+ }
1321
+ const removed = Math.abs(level);
1322
+ return `${cousinWord(degree, sexOf(this.personN))} (${removed}\xD7 \u0447\u0435\u0440\u0435\u0437 \u043F\u043E\u043A\u043E\u043B\u0435\u043D\u0438\u0435)`;
1323
+ }
1324
+ auncle() {
1325
+ const level = Math.abs(this.pathN?.level ?? 0);
1326
+ const pra = praRepeat(Math.max(0, level - 2));
1327
+ const sex = sexOf(this.personN);
1328
+ if (sex === "m") {
1329
+ return `${pra}\u0434\u044F\u0434\u044F`;
1330
+ }
1331
+ if (sex === "f") {
1332
+ return `${pra}\u0442\u0451\u0442\u044F`;
1333
+ }
1334
+ return `${pra}\u0434\u044F\u0434\u044F/\u0442\u0451\u0442\u044F`;
1335
+ }
1336
+ nibling() {
1337
+ const level = Math.abs(this.pathN?.level ?? 0);
1338
+ const pra = praRepeat(Math.max(0, level - 2));
1339
+ const sex = sexOf(this.personN);
1340
+ if (sex === "m") {
1341
+ return `${pra}\u043F\u043B\u0435\u043C\u044F\u043D\u043D\u0438\u043A`;
1342
+ }
1343
+ if (sex === "f") {
1344
+ return `${pra}\u043F\u043B\u0435\u043C\u044F\u043D\u043D\u0438\u0446\u0430`;
1345
+ }
1346
+ return `${pra}\u043F\u043B\u0435\u043C\u044F\u043D\u043D\u0438\u043A/\u043F\u043B\u0435\u043C\u044F\u043D\u043D\u0438\u0446\u0430`;
1347
+ }
1348
+ parent() {
1349
+ const level = Math.abs(this.pathN?.level ?? 0);
1350
+ const sex = sexOf(this.personN);
1351
+ if (level <= 1) {
1352
+ if (sex === "m") {
1353
+ return "\u043E\u0442\u0435\u0446";
1354
+ }
1355
+ if (sex === "f") {
1356
+ return "\u043C\u0430\u0442\u044C";
1357
+ }
1358
+ return "\u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C";
1359
+ }
1360
+ if (level === 2) {
1361
+ if (sex === "m") {
1362
+ return "\u0434\u0435\u0434";
1363
+ }
1364
+ if (sex === "f") {
1365
+ return "\u0431\u0430\u0431\u0443\u0448\u043A\u0430";
1366
+ }
1367
+ return "\u0434\u0435\u0434/\u0431\u0430\u0431\u0443\u0448\u043A\u0430";
1368
+ }
1369
+ const pra = praRepeat(level - 2);
1370
+ if (sex === "m") {
1371
+ return `${pra}\u0434\u0435\u0434`;
1372
+ }
1373
+ if (sex === "f") {
1374
+ return `${pra}\u0431\u0430\u0431\u0443\u0448\u043A\u0430`;
1375
+ }
1376
+ return `${pra}\u0434\u0435\u0434/\u0431\u0430\u0431\u0443\u0448\u043A\u0430`;
1377
+ }
1378
+ child() {
1379
+ const level = Math.abs(this.pathN?.level ?? 0);
1380
+ const sex = sexOf(this.personN);
1381
+ if (level <= 1) {
1382
+ if (sex === "m") {
1383
+ return "\u0441\u044B\u043D";
1384
+ }
1385
+ if (sex === "f") {
1386
+ return "\u0434\u043E\u0447\u044C";
1387
+ }
1388
+ return "\u0440\u0435\u0431\u0451\u043D\u043E\u043A";
1389
+ }
1390
+ if (level === 2) {
1391
+ if (sex === "m") {
1392
+ return "\u0432\u043D\u0443\u043A";
1393
+ }
1394
+ if (sex === "f") {
1395
+ return "\u0432\u043D\u0443\u0447\u043A\u0430";
1396
+ }
1397
+ return "\u0432\u043D\u0443\u043A/\u0432\u043D\u0443\u0447\u043A\u0430";
1398
+ }
1399
+ const pra = praRepeat(level - 2);
1400
+ if (sex === "m") {
1401
+ return `${pra}\u0432\u043D\u0443\u043A`;
1402
+ }
1403
+ if (sex === "f") {
1404
+ return `${pra}\u0432\u043D\u0443\u0447\u043A\u0430`;
1405
+ }
1406
+ return `${pra}\u0432\u043D\u0443\u043A/\u0432\u043D\u0443\u0447\u043A\u0430`;
1407
+ }
1408
+ sibling() {
1409
+ const sex = sexOf(this.personN);
1410
+ if (sex === "m") {
1411
+ return "\u0431\u0440\u0430\u0442";
1412
+ }
1413
+ if (sex === "f") {
1414
+ return "\u0441\u0435\u0441\u0442\u0440\u0430";
1415
+ }
1416
+ return "\u0441\u0438\u0431\u043B\u0438\u043D\u0433";
1417
+ }
1418
+ halfBlood(relation) {
1419
+ if (!relation || !this.isHalfBlood) {
1420
+ return relation ?? "";
1421
+ }
1422
+ if (/сестра|дочь|мать|тётя|бабушка|жена|племянница|внучка/.test(
1423
+ relation
1424
+ )) {
1425
+ return `\u0441\u0432\u043E\u0434\u043D\u0430\u044F ${relation}`;
1426
+ }
1427
+ return `\u0441\u0432\u043E\u0434\u043D\u044B\u0439 ${relation}`;
1428
+ }
1429
+ spouse() {
1430
+ const sex = sexOf(this.personN);
1431
+ if (sex === "m") {
1432
+ return "\u043C\u0443\u0436";
1433
+ }
1434
+ if (sex === "f") {
1435
+ return "\u0436\u0435\u043D\u0430";
1436
+ }
1437
+ return "\u0441\u0443\u043F\u0440\u0443\u0433";
1438
+ }
1439
+ ofSpouse(relation) {
1440
+ if (!relation) {
1441
+ return "";
1442
+ }
1443
+ const spouse = this.path?.[1].indi;
1444
+ const sex = sexOf(spouse);
1445
+ const spouseType = sex === "m" ? "\u043C\u0443\u0436" : sex === "f" ? "\u0436\u0435\u043D\u0430" : "\u0441\u0443\u043F\u0440\u0443\u0433";
1446
+ return `${relation} ${toGenitive(spouseType)}`;
1447
+ }
1448
+ spouseOf(relation) {
1449
+ if (!relation) {
1450
+ return "";
1451
+ }
1452
+ const spouse = this.path?.[this.path.length - 1].indi;
1453
+ const sex = sexOf(spouse);
1454
+ const spouseType = sex === "m" ? "\u043C\u0443\u0436" : sex === "f" ? "\u0436\u0435\u043D\u0430" : "\u0441\u0443\u043F\u0440\u0443\u0433";
1455
+ return `${spouseType} ${toGenitive(relation)}`;
1456
+ }
1457
+ of(relation) {
1458
+ const formattedName = nameFormatter(this.path?.[0]?.indi, {
1459
+ nameOrder: "first-last"
1460
+ });
1461
+ let name = formattedName.inOrder.filter(Boolean).join(" ");
1462
+ if (this.displayName === "none") {
1463
+ name = "";
1464
+ } else if (this.displayName === "givenname") {
1465
+ name = formattedName.givenname;
1466
+ } else if (this.displayName === "surname") {
1467
+ name = `${formattedName.surname}`;
1468
+ }
1469
+ if (!name || !relation) {
1470
+ return relation ?? "";
1471
+ }
1472
+ return `${name}: ${relation}`;
1473
+ }
1474
+ inLaw(relation) {
1475
+ let inLawRelation = relation;
1476
+ Object.keys(InLawsRu).find((pattern) => {
1477
+ const regex = new RegExp(`^${pattern}$`);
1478
+ if (relation?.match(regex)) {
1479
+ inLawRelation = InLawsRu[pattern];
1480
+ return true;
1481
+ }
1482
+ return false;
1483
+ });
1484
+ return inLawRelation ?? "";
1485
+ }
1486
+ relationType(relation) {
1487
+ if (!relation || !this.pathN?.relation) {
1488
+ return relation ?? "";
1489
+ }
1490
+ return `${this.pathN.relation} ${relation}`;
1491
+ }
1492
+ };
1493
+
1183
1494
  // src/kinship-translator/kinship-translator.ts
1184
1495
  var KinshipTranslator = class {
1185
1496
  constructor(person1, person2, lang = "en", entirePath, displayName = "givenname") {
@@ -1273,6 +1584,7 @@ var KinshipTranslator = class {
1273
1584
  } else if (personN.level !== 0) {
1274
1585
  relation = this.removal();
1275
1586
  }
1587
+ relation = this.translator?.halfBlood(relation);
1276
1588
  relation = this.translator?.relationType(relation);
1277
1589
  if (this.translator?.isOfSpouse) {
1278
1590
  relation = this.translator?.ofSpouse(relation);
@@ -3090,6 +3402,135 @@ var profilePictureCache = (gedcom, key, value) => {
3090
3402
  const cached = caches.profilePictureCache?.[fullKey];
3091
3403
  return cached;
3092
3404
  };
3405
+ var isNonBiologicalPath = (path) => path.some(
3406
+ (item) => item.relation && item.relation !== "biological" /* BIOLOGICAL */
3407
+ );
3408
+ var invertHop = (kinship) => {
3409
+ if (kinship === "parent") {
3410
+ return "child";
3411
+ }
3412
+ if (kinship === "child") {
3413
+ return "parent";
3414
+ }
3415
+ return kinship;
3416
+ };
3417
+ var hopRelation = (from, toIndi, kinship, inherited) => {
3418
+ if (kinship === "parent" || kinship === "child") {
3419
+ const parent = kinship === "parent" ? toIndi : from.indi;
3420
+ const child = kinship === "parent" ? from.indi : toIndi;
3421
+ const currentRelation = child.getParentType(parent);
3422
+ if (currentRelation && currentRelation !== "biological" /* BIOLOGICAL */) {
3423
+ return currentRelation;
3424
+ }
3425
+ }
3426
+ if (inherited && inherited !== "biological" /* BIOLOGICAL */) {
3427
+ return inherited;
3428
+ }
3429
+ return void 0;
3430
+ };
3431
+ var rebuildPathFromHops = (hops, skipRelation = false) => {
3432
+ if (hops.length === 0) {
3433
+ return [];
3434
+ }
3435
+ const path = [
3436
+ {
3437
+ indi: hops[0].indi,
3438
+ kinship: "self",
3439
+ level: 0,
3440
+ levelUp: 0,
3441
+ levelDown: 0,
3442
+ degree: 0
3443
+ }
3444
+ ];
3445
+ for (let i = 1; i < hops.length; i++) {
3446
+ const prev = path[i - 1];
3447
+ const { indi, kinship } = hops[i];
3448
+ const relation = skipRelation ? void 0 : hopRelation(prev, indi, kinship, prev.relation);
3449
+ if (kinship === "parent") {
3450
+ path.push({
3451
+ indi,
3452
+ kinship,
3453
+ relation,
3454
+ level: prev.level + 1,
3455
+ levelUp: prev.levelUp + 1,
3456
+ levelDown: prev.levelDown,
3457
+ degree: prev.degree
3458
+ });
3459
+ continue;
3460
+ }
3461
+ if (kinship === "child") {
3462
+ path.push({
3463
+ indi,
3464
+ kinship,
3465
+ relation,
3466
+ level: prev.level - 1,
3467
+ levelUp: prev.levelUp,
3468
+ levelDown: prev.levelDown + 1,
3469
+ degree: prev.levelUp ? prev.level > 0 ? prev.levelUp - prev.level + 1 : prev.levelDown - Math.abs(prev.level) : 0
3470
+ });
3471
+ continue;
3472
+ }
3473
+ path.push({
3474
+ indi,
3475
+ kinship,
3476
+ relation,
3477
+ level: prev.level,
3478
+ levelUp: prev.levelUp,
3479
+ levelDown: prev.levelDown,
3480
+ degree: prev.degree
3481
+ });
3482
+ }
3483
+ return path;
3484
+ };
3485
+ var storePathIfBetter = (gedcom, fromId, toId, path) => {
3486
+ const key = `${fromId}|${toId}`;
3487
+ const existing = pathCache(gedcom, key);
3488
+ if (existing && (!isNonBiologicalPath(existing) || isNonBiologicalPath(path))) {
3489
+ return;
3490
+ }
3491
+ pathCache(gedcom, key, path);
3492
+ };
3493
+ var cacheDiscoveredPath = (gedcom, path) => {
3494
+ const n = path.length;
3495
+ if (n < 2) {
3496
+ return;
3497
+ }
3498
+ for (let i = 0; i < n; i++) {
3499
+ const fromId = path[i].indi.id;
3500
+ if (!fromId) {
3501
+ continue;
3502
+ }
3503
+ for (let j = i + 1; j < n; j++) {
3504
+ const toId = path[j].indi.id;
3505
+ if (!toId) {
3506
+ continue;
3507
+ }
3508
+ const isOriginalPair = i === 0 && j === n - 1;
3509
+ const isDirectHop = j === i + 1;
3510
+ const slice = path.slice(i, j + 1);
3511
+ const sliceMixed = isNonBiologicalPath(slice);
3512
+ if (!isOriginalPair && !isDirectHop && sliceMixed) {
3513
+ continue;
3514
+ }
3515
+ const forward = i === 0 ? slice : rebuildPathFromHops(slice, !sliceMixed);
3516
+ const reverseHops = [
3517
+ {
3518
+ indi: slice[slice.length - 1].indi,
3519
+ kinship: "self"
3520
+ }
3521
+ ];
3522
+ for (let k = slice.length - 2; k >= 0; k--) {
3523
+ reverseHops.push({
3524
+ indi: slice[k].indi,
3525
+ kinship: invertHop(slice[k + 1].kinship)
3526
+ });
3527
+ }
3528
+ const reverse = rebuildPathFromHops(reverseHops, !sliceMixed);
3529
+ storePathIfBetter(gedcom, fromId, toId, forward);
3530
+ storePathIfBetter(gedcom, toId, fromId, reverse);
3531
+ }
3532
+ }
3533
+ };
3093
3534
 
3094
3535
  // src/utils/get-places.ts
3095
3536
  var getPlaces = (common, type = ["ALL" /* All */], maxLevel = 1, level = 0, mainKey) => {
@@ -5110,7 +5551,6 @@ var Indi = class extends Common {
5110
5551
  if (cache) {
5111
5552
  return cache;
5112
5553
  }
5113
- const visited = new Individuals().append(this);
5114
5554
  const mainItem = {
5115
5555
  indi: this,
5116
5556
  level: 0,
@@ -5119,129 +5559,155 @@ var Indi = class extends Common {
5119
5559
  degree: 0,
5120
5560
  kinship: "self"
5121
5561
  };
5122
- const path = [mainItem];
5562
+ const mainPath = [mainItem];
5123
5563
  if (this.id === usedIndi.id) {
5124
- return path;
5564
+ return mainPath;
5125
5565
  }
5126
- const queue = [
5127
- {
5128
- ...mainItem,
5129
- path
5130
- }
5131
- ];
5132
- let helper = 0;
5133
- while (queue.length > 0) {
5134
- if (helper++ > 1e6) {
5135
- break;
5136
- }
5137
- const {
5138
- indi,
5139
- path: path2,
5140
- kinship,
5141
- relation,
5142
- level,
5143
- levelUp,
5144
- levelDown,
5145
- degree,
5146
- breakOnNext,
5147
- breakAfterNext,
5148
- inLaw
5149
- } = queue.shift();
5150
- if (usedIndi.id === indi.id) {
5151
- if (breakOnNext) {
5152
- return void 0;
5566
+ const bfs = (biologicalOnly) => {
5567
+ const visited = new Individuals().append(this);
5568
+ const queue = [
5569
+ {
5570
+ ...mainItem,
5571
+ path: mainPath
5153
5572
  }
5154
- pathCache(this._gedcom, cacheKey, path2);
5155
- return path2;
5156
- }
5157
- visited.append(indi);
5158
- const additional = {};
5159
- if (breakOnNext || breakAfterNext) {
5160
- additional.breakOnNext = breakOnNext || breakAfterNext;
5161
- }
5162
- if (inLaw) {
5163
- additional.inLaw = inLaw;
5164
- }
5165
- if (kinship === "spouse" && breakAfterSpouse) {
5166
- if (path2.length <= 2) {
5167
- additional.inLaw = true;
5168
- } else {
5169
- additional.breakOnNext = true;
5573
+ ];
5574
+ let helper = 0;
5575
+ while (queue.length > 0) {
5576
+ if (helper++ > 1e6) {
5577
+ break;
5170
5578
  }
5171
- }
5172
- if (kinship !== "child" || !breakAfterSpouse) {
5173
- indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(indi.getFathers().copy().merge(indi.getMothers())).forEach((relative) => {
5579
+ const {
5580
+ indi,
5581
+ path,
5582
+ kinship,
5583
+ relation,
5584
+ level,
5585
+ levelUp,
5586
+ levelDown,
5587
+ degree,
5588
+ breakOnNext,
5589
+ breakAfterNext,
5590
+ inLaw
5591
+ } = queue.shift();
5592
+ if (usedIndi.id === indi.id) {
5593
+ if (breakOnNext) {
5594
+ return void 0;
5595
+ }
5596
+ return path;
5597
+ }
5598
+ visited.append(indi);
5599
+ const additional = {};
5600
+ if (breakOnNext || breakAfterNext) {
5601
+ additional.breakOnNext = breakOnNext || breakAfterNext;
5602
+ }
5603
+ if (inLaw) {
5604
+ additional.inLaw = inLaw;
5605
+ }
5606
+ if (!biologicalOnly && kinship === "spouse" && breakAfterSpouse) {
5607
+ if (path.length <= 2) {
5608
+ additional.inLaw = true;
5609
+ } else {
5610
+ additional.breakOnNext = true;
5611
+ }
5612
+ }
5613
+ if (kinship !== "child" || !breakAfterSpouse) {
5614
+ indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(indi.getFathers().copy().merge(indi.getMothers())).forEach((relative) => {
5615
+ if (!visited.has(relative)) {
5616
+ const currentRelation = indi.getParentType(relative);
5617
+ const isNonBiological = !!currentRelation && currentRelation !== "biological" /* BIOLOGICAL */;
5618
+ if (biologicalOnly && isNonBiological) {
5619
+ return;
5620
+ }
5621
+ if (!biologicalOnly && breakAfterNonBiological && isNonBiological) {
5622
+ additional.breakAfterNext = true;
5623
+ }
5624
+ const newItem = {
5625
+ indi: relative,
5626
+ kinship: "parent",
5627
+ relation: isNonBiological ? currentRelation : relation,
5628
+ level: level + 1,
5629
+ levelUp: levelUp + 1,
5630
+ levelDown,
5631
+ degree,
5632
+ ...additional
5633
+ };
5634
+ queue.push({
5635
+ ...newItem,
5636
+ path: [...path, newItem]
5637
+ });
5638
+ }
5639
+ });
5640
+ }
5641
+ indi.getChildren().forEach((relative) => {
5174
5642
  if (!visited.has(relative)) {
5175
- const currentRelation = indi.getParentType(relative);
5176
- if (breakAfterNonBiological && currentRelation !== "biological" /* BIOLOGICAL */) {
5643
+ const currentRelation = relative.getParentType(indi);
5644
+ const isNonBiological = !!currentRelation && currentRelation !== "biological" /* BIOLOGICAL */;
5645
+ if (biologicalOnly && isNonBiological) {
5646
+ return;
5647
+ }
5648
+ if (!biologicalOnly && breakAfterNonBiological && isNonBiological) {
5177
5649
  additional.breakAfterNext = true;
5178
5650
  }
5179
5651
  const newItem = {
5180
5652
  indi: relative,
5181
- kinship: "parent",
5182
- relation: currentRelation && currentRelation !== "biological" /* BIOLOGICAL */ ? currentRelation : relation,
5183
- level: level + 1,
5184
- levelUp: levelUp + 1,
5185
- levelDown,
5186
- degree,
5653
+ kinship: "child",
5654
+ relation: isNonBiological ? currentRelation : relation,
5655
+ level: level - 1,
5656
+ levelUp,
5657
+ levelDown: levelDown + 1,
5658
+ degree: levelUp ? level > 0 ? levelUp - level + 1 : levelDown - Math.abs(level) : 0,
5187
5659
  ...additional
5188
5660
  };
5189
5661
  queue.push({
5190
5662
  ...newItem,
5191
- path: [...path2, newItem]
5663
+ path: [...path, newItem]
5192
5664
  });
5193
5665
  }
5194
5666
  });
5195
- }
5196
- indi.getChildren().forEach((relative) => {
5197
- if (!visited.has(relative)) {
5198
- const currentRelation = relative.getParentType(indi);
5199
- if (breakAfterNonBiological && currentRelation !== "biological" /* BIOLOGICAL */) {
5200
- additional.breakAfterNext = true;
5201
- }
5202
- const newItem = {
5203
- indi: relative,
5204
- kinship: "child",
5205
- relation: currentRelation && currentRelation !== "biological" /* BIOLOGICAL */ ? currentRelation : relation,
5206
- level: level - 1,
5207
- levelUp,
5208
- levelDown: levelDown + 1,
5209
- degree: levelUp ? level > 0 ? levelUp - level + 1 : levelDown - Math.abs(level) : 0,
5210
- ...additional
5211
- };
5212
- queue.push({
5213
- ...newItem,
5214
- path: [...path2, newItem]
5215
- });
5667
+ if (biologicalOnly) {
5668
+ continue;
5216
5669
  }
5217
- });
5218
- indi.getCoParents().forEach((relative) => {
5219
- if (!visited.has(relative)) {
5220
- const currentAddition = {};
5221
- if (relation && relation !== "biological" /* BIOLOGICAL */) {
5222
- currentAddition.relation = relation;
5223
- }
5224
- if (inLaw) {
5225
- currentAddition.breakOnNext = true;
5670
+ indi.getCoParents().forEach((relative) => {
5671
+ if (!visited.has(relative)) {
5672
+ const currentAddition = {};
5673
+ if (relation && relation !== "biological" /* BIOLOGICAL */) {
5674
+ currentAddition.relation = relation;
5675
+ }
5676
+ if (inLaw) {
5677
+ currentAddition.breakOnNext = true;
5678
+ }
5679
+ const newItem = {
5680
+ indi: relative,
5681
+ kinship: "spouse",
5682
+ level,
5683
+ levelUp,
5684
+ levelDown,
5685
+ degree,
5686
+ ...additional,
5687
+ ...currentAddition
5688
+ };
5689
+ queue.push({
5690
+ ...newItem,
5691
+ path: [...path, newItem]
5692
+ });
5226
5693
  }
5227
- const newItem = {
5228
- indi: relative,
5229
- kinship: "spouse",
5230
- level,
5231
- levelUp,
5232
- levelDown,
5233
- degree,
5234
- ...additional,
5235
- ...currentAddition
5236
- };
5237
- queue.push({
5238
- ...newItem,
5239
- path: [...path2, newItem]
5240
- });
5241
- }
5242
- });
5694
+ });
5695
+ }
5696
+ return void 0;
5697
+ };
5698
+ const foundPath = bfs(false);
5699
+ const lastItem = foundPath?.[foundPath.length - 1];
5700
+ if (lastItem?.relation && lastItem.relation !== "biological" /* BIOLOGICAL */) {
5701
+ const biologicalPath = bfs(true);
5702
+ if (biologicalPath) {
5703
+ cacheDiscoveredPath(this._gedcom, biologicalPath);
5704
+ return biologicalPath;
5705
+ }
5243
5706
  }
5244
- return void 0;
5707
+ if (foundPath) {
5708
+ cacheDiscoveredPath(this._gedcom, foundPath);
5709
+ }
5710
+ return foundPath;
5245
5711
  }
5246
5712
  kinship(other, showMainPerson, lang = "en", entirePath, displayName = "givenname") {
5247
5713
  const KinshipTranslatorClass2 = getKinshipTranslatorClass();
@@ -6169,20 +6635,22 @@ var KinshipTranslatorDe = class extends KinshipTranslatorBasic {
6169
6635
  return `${prefix}kind`;
6170
6636
  }
6171
6637
  sibling() {
6172
- const parents1 = this.person1?.getBiologicalParents();
6173
- const parentsN = this.personN?.getBiologicalParents();
6174
- const inter = parents1?.intersection(parentsN);
6175
- let prefix = "";
6176
- if (!inter || inter.length < 2) {
6177
- prefix = "Halb";
6178
- }
6179
6638
  if (this.personN?.isMale()) {
6180
- return `${prefix}bruder`;
6639
+ return "bruder";
6181
6640
  }
6182
6641
  if (this.personN?.isFemale()) {
6183
- return `${prefix}schwester`;
6642
+ return "schwester";
6643
+ }
6644
+ return "geschwister";
6645
+ }
6646
+ halfBlood(relation) {
6647
+ if (!relation || !this.isHalfBlood) {
6648
+ return relation ?? "";
6649
+ }
6650
+ if (/^[A-ZÄÖÜ]/.test(relation) || /[-\s]/.test(relation)) {
6651
+ return `Halb-${relation}`;
6184
6652
  }
6185
- return `${prefix}geschwister`;
6653
+ return `Halb${relation}`;
6186
6654
  }
6187
6655
  spouse() {
6188
6656
  if (this.personN?.isMale()) {
@@ -6271,4 +6739,4 @@ var KinshipTranslatorDe = class extends KinshipTranslatorBasic {
6271
6739
  }
6272
6740
  };
6273
6741
 
6274
- export { KinshipTranslator, KinshipTranslatorBasic, KinshipTranslatorDe as KinshipTranslatorDE, KinshipTranslatorEn as KinshipTranslatorEN, KinshipTranslatorEs as KinshipTranslatorES, KinshipTranslatorFr as KinshipTranslatorFR, KinshipTranslatorHU, translators_exports as translators };
6742
+ export { KinshipTranslator, KinshipTranslatorBasic, KinshipTranslatorDe as KinshipTranslatorDE, KinshipTranslatorEn as KinshipTranslatorEN, KinshipTranslatorEs as KinshipTranslatorES, KinshipTranslatorFr as KinshipTranslatorFR, KinshipTranslatorHU, KinshipTranslatorRu as KinshipTranslatorRU, translators_exports as translators };