@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
@@ -77,7 +77,8 @@ __export(translators_exports, {
77
77
  en: () => KinshipTranslatorEn,
78
78
  es: () => KinshipTranslatorEs,
79
79
  fr: () => KinshipTranslatorFr,
80
- hu: () => KinshipTranslatorHU
80
+ hu: () => KinshipTranslatorHU,
81
+ ru: () => KinshipTranslatorRu
81
82
  });
82
83
 
83
84
  // src/constants/constants.ts
@@ -1347,6 +1348,44 @@ var KinshipTranslatorBasic = class {
1347
1348
  }
1348
1349
  return this.pathN?.indi;
1349
1350
  }
1351
+ /**
1352
+ * True when the path goes through a common ancestor whose two children
1353
+ * (the person we came from and the person we go to) share fewer than two
1354
+ * biological parents — i.e. they are half-siblings, so every collateral
1355
+ * relative on this path is a half-aunt/half-cousin/... too.
1356
+ *
1357
+ * Direct ancestors/descendants and paths that already use a
1358
+ * step/adopted/foster edge are never half-blood.
1359
+ */
1360
+ get isHalfBlood() {
1361
+ const path = this.path;
1362
+ if (!path || path.length < 3) {
1363
+ return false;
1364
+ }
1365
+ if (path.some(
1366
+ (item) => item.relation && item.relation !== "biological" /* BIOLOGICAL */
1367
+ )) {
1368
+ return false;
1369
+ }
1370
+ let peakIndex = -1;
1371
+ for (let i = 1; i < path.length; i++) {
1372
+ if (path[i].kinship === "parent") {
1373
+ peakIndex = i;
1374
+ }
1375
+ }
1376
+ if (peakIndex <= 0 || peakIndex >= path.length - 1) {
1377
+ return false;
1378
+ }
1379
+ if (path[peakIndex + 1].kinship !== "child") {
1380
+ return false;
1381
+ }
1382
+ const siblingA = path[peakIndex - 1].indi;
1383
+ const siblingB = path[peakIndex + 1].indi;
1384
+ const parentsA = siblingA.getBiologicalParents();
1385
+ const parentsB = siblingB.getBiologicalParents();
1386
+ const inter = parentsA.intersection(parentsB);
1387
+ return inter.length === 1 && (parentsA.length > 1 || parentsB.length > 1);
1388
+ }
1350
1389
  indirect() {
1351
1390
  return "";
1352
1391
  }
@@ -1374,6 +1413,9 @@ var KinshipTranslatorBasic = class {
1374
1413
  relationType(relation) {
1375
1414
  return relation ?? "";
1376
1415
  }
1416
+ halfBlood(relation) {
1417
+ return relation ?? "";
1418
+ }
1377
1419
  of(relation) {
1378
1420
  return relation ?? "";
1379
1421
  }
@@ -1612,14 +1654,34 @@ var KinshipTranslatorHU = class extends KinshipTranslatorBasic {
1612
1654
  return `${prefix.replace(/nagy$/, "")}unoka`;
1613
1655
  }
1614
1656
  sibling() {
1615
- const parents1 = this.person1?.getBiologicalParents();
1616
- const parentsN = this.personN?.getBiologicalParents();
1617
- const inter = parents1?.intersection(parentsN);
1618
- if (!inter || inter.length < 2) {
1619
- return "f\xE9ltestv\xE9r";
1620
- }
1621
1657
  return "testv\xE9r";
1622
1658
  }
1659
+ halfBlood(relation) {
1660
+ if (!relation || !this.isHalfBlood) {
1661
+ return relation ?? "";
1662
+ }
1663
+ const [head, ...rest] = relation.split(" ");
1664
+ if (!head) {
1665
+ return relation;
1666
+ }
1667
+ const prefixed = this.prefixHalf(head);
1668
+ return [prefixed, ...rest].join(" ");
1669
+ }
1670
+ /**
1671
+ * AkH. 139: compounds of more than two members stay closed up to 6
1672
+ * syllables; longer ones are hyphenated at the main boundary. A head
1673
+ * that is already hyphenated also takes a hyphenated half- prefix.
1674
+ */
1675
+ prefixHalf(head) {
1676
+ if (head.includes("-") || !/[aáeéiíoóöőuúüű]/i.test(head)) {
1677
+ return `f\xE9l-${head}`;
1678
+ }
1679
+ const syllables = (head.match(/[aáeéiíoóöőuúüű]/gi) ?? []).length + 1;
1680
+ if (syllables > 6) {
1681
+ return `f\xE9l-${head}`;
1682
+ }
1683
+ return `f\xE9l${head}`;
1684
+ }
1623
1685
  spouse() {
1624
1686
  if (this.personN?.isMale()) {
1625
1687
  return "f\xE9rj";
@@ -1818,20 +1880,22 @@ var KinshipTranslatorEn = class extends KinshipTranslatorBasic {
1818
1880
  return `${prefix}child`;
1819
1881
  }
1820
1882
  sibling() {
1821
- const parents1 = this.person1?.getBiologicalParents();
1822
- const parentsN = this.personN?.getBiologicalParents();
1823
- const inter = parents1?.intersection(parentsN);
1824
- let prefix = "";
1825
- if (!inter || inter.length < 2) {
1826
- prefix = "half-";
1827
- }
1828
1883
  if (this.personN?.isMale()) {
1829
- return `${prefix}brother`;
1884
+ return "brother";
1830
1885
  }
1831
1886
  if (this.personN?.isFemale()) {
1832
- return `${prefix}sister`;
1887
+ return "sister";
1833
1888
  }
1834
- return `${prefix}sibling`;
1889
+ return "sibling";
1890
+ }
1891
+ halfBlood(relation) {
1892
+ if (!relation || !this.isHalfBlood) {
1893
+ return relation ?? "";
1894
+ }
1895
+ if (relation.includes(" ")) {
1896
+ return `half ${relation}`;
1897
+ }
1898
+ return `half-${relation}`;
1835
1899
  }
1836
1900
  spouse() {
1837
1901
  if (this.personN?.isMale()) {
@@ -2013,20 +2077,22 @@ var KinshipTranslatorDe = class extends KinshipTranslatorBasic {
2013
2077
  return `${prefix}kind`;
2014
2078
  }
2015
2079
  sibling() {
2016
- const parents1 = this.person1?.getBiologicalParents();
2017
- const parentsN = this.personN?.getBiologicalParents();
2018
- const inter = parents1?.intersection(parentsN);
2019
- let prefix = "";
2020
- if (!inter || inter.length < 2) {
2021
- prefix = "Halb";
2022
- }
2023
2080
  if (this.personN?.isMale()) {
2024
- return `${prefix}bruder`;
2081
+ return "bruder";
2025
2082
  }
2026
2083
  if (this.personN?.isFemale()) {
2027
- return `${prefix}schwester`;
2084
+ return "schwester";
2028
2085
  }
2029
- return `${prefix}geschwister`;
2086
+ return "geschwister";
2087
+ }
2088
+ halfBlood(relation) {
2089
+ if (!relation || !this.isHalfBlood) {
2090
+ return relation ?? "";
2091
+ }
2092
+ if (/^[A-ZÄÖÜ]/.test(relation) || /[-\s]/.test(relation)) {
2093
+ return `Halb-${relation}`;
2094
+ }
2095
+ return `Halb${relation}`;
2030
2096
  }
2031
2097
  spouse() {
2032
2098
  if (this.personN?.isMale()) {
@@ -2208,20 +2274,19 @@ var KinshipTranslatorFr = class extends KinshipTranslatorBasic {
2208
2274
  return `${prefix}enfant`;
2209
2275
  }
2210
2276
  sibling() {
2211
- const parents1 = this.person1?.getBiologicalParents();
2212
- const parentsN = this.personN?.getBiologicalParents();
2213
- const inter = parents1?.intersection(parentsN);
2214
- let prefix = "";
2215
- if (!inter || inter.length < 2) {
2216
- prefix = "demi-";
2217
- }
2218
2277
  if (this.personN?.isMale()) {
2219
- return `${prefix}fr\xE8re`;
2278
+ return "fr\xE8re";
2220
2279
  }
2221
2280
  if (this.personN?.isFemale()) {
2222
- return `${prefix}s\u0153ur`;
2281
+ return "s\u0153ur";
2282
+ }
2283
+ return "fr\xE8re/s\u0153ur";
2284
+ }
2285
+ halfBlood(relation) {
2286
+ if (!relation || !this.isHalfBlood) {
2287
+ return relation ?? "";
2223
2288
  }
2224
- return `${prefix}fr\xE8re/s\u0153ur`;
2289
+ return `demi-${relation}`;
2225
2290
  }
2226
2291
  spouse() {
2227
2292
  if (this.personN?.isMale()) {
@@ -2318,12 +2383,12 @@ var InLawsEs = {
2318
2383
  "madre del (c\xF3nyuge|esposa|esposo)": "suegra",
2319
2384
  "padre del (c\xF3nyuge|esposa|esposo)": "suegro",
2320
2385
  "padre/madre del (c\xF3nyuge|esposa|esposo)": "suegro/suegra",
2321
- "esposa de (medio )?(hermano/hermana|hermana|hermano)": "cu\xF1ada",
2322
- "esposo de (medio )?(hermano/hermana|hermana|hermano)": "cu\xF1ado",
2323
- "c\xF3nyuge de (medio )?(hermano/hermana|hermana|hermano)": "cu\xF1ado/cu\xF1ada",
2324
- "(medio )?hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ada",
2325
- "(medio )?hermano del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado",
2326
- "(medio )?hermano/hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado/cu\xF1ada"
2386
+ "esposa de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ada",
2387
+ "esposo de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ado",
2388
+ "c\xF3nyuge de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ado/cu\xF1ada",
2389
+ "(medio |media |medio/a )?hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ada",
2390
+ "(medio |media |medio/a )?hermano del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado",
2391
+ "(medio |media |medio/a )?hermano/hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado/cu\xF1ada"
2327
2392
  };
2328
2393
 
2329
2394
  // src/kinship-translator/kinship-translator.es.ts
@@ -2403,20 +2468,25 @@ var KinshipTranslatorEs = class extends KinshipTranslatorBasic {
2403
2468
  return `${prefix}hijo/hija`;
2404
2469
  }
2405
2470
  sibling() {
2406
- const parents1 = this.person1?.getBiologicalParents();
2407
- const parentsN = this.personN?.getBiologicalParents();
2408
- const inter = parents1?.intersection(parentsN);
2409
- let prefix = "";
2410
- if (!inter || inter.length < 2) {
2411
- prefix = "medio ";
2412
- }
2413
2471
  if (this.personN?.isMale()) {
2414
- return `${prefix}hermano`;
2472
+ return "hermano";
2415
2473
  }
2416
2474
  if (this.personN?.isFemale()) {
2417
- return `${prefix}hermana`;
2475
+ return "hermana";
2418
2476
  }
2419
- return `${prefix}hermano/hermana`;
2477
+ return "hermano/hermana";
2478
+ }
2479
+ halfBlood(relation) {
2480
+ if (!relation || !this.isHalfBlood) {
2481
+ return relation ?? "";
2482
+ }
2483
+ if (this.personN?.isFemale()) {
2484
+ return `media ${relation}`;
2485
+ }
2486
+ if (this.personN?.isMale()) {
2487
+ return `medio ${relation}`;
2488
+ }
2489
+ return `medio/a ${relation}`;
2420
2490
  }
2421
2491
  spouse() {
2422
2492
  if (this.personN?.isMale()) {
@@ -2505,6 +2575,249 @@ var KinshipTranslatorEs = class extends KinshipTranslatorBasic {
2505
2575
  }
2506
2576
  };
2507
2577
 
2578
+ // src/kinship-translator/patterns.ru.ts
2579
+ var InLawsRu = {
2580
+ "\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",
2581
+ "\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",
2582
+ "\u043C\u0443\u0436 (\u0440\u0435\u0431\u0451\u043D\u043A\u0430|\u0434\u043E\u0447\u0435\u0440\u0438|\u0441\u044B\u043D\u0430)": "\u0437\u044F\u0442\u044C",
2583
+ "\u043C\u0430\u0442\u044C (\u0441\u0443\u043F\u0440\u0443\u0433\u0430|\u0436\u0435\u043D\u044B|\u043C\u0443\u0436\u0430)": "\u0442\u0451\u0449\u0430",
2584
+ "\u043E\u0442\u0435\u0446 (\u0441\u0443\u043F\u0440\u0443\u0433\u0430|\u0436\u0435\u043D\u044B|\u043C\u0443\u0436\u0430)": "\u0442\u0435\u0441\u0442\u044C",
2585
+ "\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",
2586
+ "\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",
2587
+ "\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",
2588
+ "\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",
2589
+ "(\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",
2590
+ "(\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",
2591
+ "(\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"
2592
+ };
2593
+
2594
+ // src/kinship-translator/kinship-translator.ru.ts
2595
+ var GENITIVE = {
2596
+ \u0441\u044B\u043D: "\u0441\u044B\u043D\u0430",
2597
+ \u0434\u043E\u0447\u044C: "\u0434\u043E\u0447\u0435\u0440\u0438",
2598
+ \u0440\u0435\u0431\u0451\u043D\u043E\u043A: "\u0440\u0435\u0431\u0451\u043D\u043A\u0430",
2599
+ \u0431\u0440\u0430\u0442: "\u0431\u0440\u0430\u0442\u0430",
2600
+ \u0441\u0435\u0441\u0442\u0440\u0430: "\u0441\u0435\u0441\u0442\u0440\u044B",
2601
+ \u0441\u0438\u0431\u043B\u0438\u043D\u0433: "\u0441\u0438\u0431\u043B\u0438\u043D\u0433\u0430",
2602
+ \u043E\u0442\u0435\u0446: "\u043E\u0442\u0446\u0430",
2603
+ \u043C\u0430\u0442\u044C: "\u043C\u0430\u0442\u0435\u0440\u0438",
2604
+ \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C: "\u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044F",
2605
+ \u043C\u0443\u0436: "\u043C\u0443\u0436\u0430",
2606
+ \u0436\u0435\u043D\u0430: "\u0436\u0435\u043D\u044B",
2607
+ \u0441\u0443\u043F\u0440\u0443\u0433: "\u0441\u0443\u043F\u0440\u0443\u0433\u0430",
2608
+ \u0441\u0443\u043F\u0440\u0443\u0433\u0430: "\u0441\u0443\u043F\u0440\u0443\u0433\u0438"
2609
+ };
2610
+ var toGenitive = (word) => GENITIVE[word] ?? word;
2611
+ var cousinWord = (degree, sex) => {
2612
+ 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`;
2613
+ if (sex === "m") {
2614
+ return `${stem}\u044B\u0439 \u0431\u0440\u0430\u0442`;
2615
+ }
2616
+ if (sex === "f") {
2617
+ return `${stem}\u0430\u044F \u0441\u0435\u0441\u0442\u0440\u0430`;
2618
+ }
2619
+ return `${stem}\u044B\u0439 \u0431\u0440\u0430\u0442/\u0441\u0435\u0441\u0442\u0440\u0430`;
2620
+ };
2621
+ var praRepeat = (count) => count > 0 ? "\u043F\u0440\u0430".repeat(count) : "";
2622
+ var sexOf = (person) => {
2623
+ if (person?.isMale?.()) {
2624
+ return "m";
2625
+ }
2626
+ if (person?.isFemale?.()) {
2627
+ return "f";
2628
+ }
2629
+ return "n";
2630
+ };
2631
+ var KinshipTranslatorRu = class extends KinshipTranslatorBasic {
2632
+ indirect() {
2633
+ let degree = Math.abs(this.pathN?.degree ?? 0);
2634
+ if (degree > 0) {
2635
+ degree = degree - 1;
2636
+ }
2637
+ return cousinWord(degree, sexOf(this.personN));
2638
+ }
2639
+ removal() {
2640
+ const level = this.pathN?.level ?? 0;
2641
+ let degree = Math.abs(this.pathN?.degree ?? 0);
2642
+ if (degree > 0) {
2643
+ degree = degree - 1;
2644
+ }
2645
+ if (!degree) {
2646
+ return level < 0 ? this.nibling() : this.auncle();
2647
+ }
2648
+ const removed = Math.abs(level);
2649
+ return `${cousinWord(degree, sexOf(this.personN))} (${removed}\xD7 \u0447\u0435\u0440\u0435\u0437 \u043F\u043E\u043A\u043E\u043B\u0435\u043D\u0438\u0435)`;
2650
+ }
2651
+ auncle() {
2652
+ const level = Math.abs(this.pathN?.level ?? 0);
2653
+ const pra = praRepeat(Math.max(0, level - 2));
2654
+ const sex = sexOf(this.personN);
2655
+ if (sex === "m") {
2656
+ return `${pra}\u0434\u044F\u0434\u044F`;
2657
+ }
2658
+ if (sex === "f") {
2659
+ return `${pra}\u0442\u0451\u0442\u044F`;
2660
+ }
2661
+ return `${pra}\u0434\u044F\u0434\u044F/\u0442\u0451\u0442\u044F`;
2662
+ }
2663
+ nibling() {
2664
+ const level = Math.abs(this.pathN?.level ?? 0);
2665
+ const pra = praRepeat(Math.max(0, level - 2));
2666
+ const sex = sexOf(this.personN);
2667
+ if (sex === "m") {
2668
+ return `${pra}\u043F\u043B\u0435\u043C\u044F\u043D\u043D\u0438\u043A`;
2669
+ }
2670
+ if (sex === "f") {
2671
+ return `${pra}\u043F\u043B\u0435\u043C\u044F\u043D\u043D\u0438\u0446\u0430`;
2672
+ }
2673
+ return `${pra}\u043F\u043B\u0435\u043C\u044F\u043D\u043D\u0438\u043A/\u043F\u043B\u0435\u043C\u044F\u043D\u043D\u0438\u0446\u0430`;
2674
+ }
2675
+ parent() {
2676
+ const level = Math.abs(this.pathN?.level ?? 0);
2677
+ const sex = sexOf(this.personN);
2678
+ if (level <= 1) {
2679
+ if (sex === "m") {
2680
+ return "\u043E\u0442\u0435\u0446";
2681
+ }
2682
+ if (sex === "f") {
2683
+ return "\u043C\u0430\u0442\u044C";
2684
+ }
2685
+ return "\u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C";
2686
+ }
2687
+ if (level === 2) {
2688
+ if (sex === "m") {
2689
+ return "\u0434\u0435\u0434";
2690
+ }
2691
+ if (sex === "f") {
2692
+ return "\u0431\u0430\u0431\u0443\u0448\u043A\u0430";
2693
+ }
2694
+ return "\u0434\u0435\u0434/\u0431\u0430\u0431\u0443\u0448\u043A\u0430";
2695
+ }
2696
+ const pra = praRepeat(level - 2);
2697
+ if (sex === "m") {
2698
+ return `${pra}\u0434\u0435\u0434`;
2699
+ }
2700
+ if (sex === "f") {
2701
+ return `${pra}\u0431\u0430\u0431\u0443\u0448\u043A\u0430`;
2702
+ }
2703
+ return `${pra}\u0434\u0435\u0434/\u0431\u0430\u0431\u0443\u0448\u043A\u0430`;
2704
+ }
2705
+ child() {
2706
+ const level = Math.abs(this.pathN?.level ?? 0);
2707
+ const sex = sexOf(this.personN);
2708
+ if (level <= 1) {
2709
+ if (sex === "m") {
2710
+ return "\u0441\u044B\u043D";
2711
+ }
2712
+ if (sex === "f") {
2713
+ return "\u0434\u043E\u0447\u044C";
2714
+ }
2715
+ return "\u0440\u0435\u0431\u0451\u043D\u043E\u043A";
2716
+ }
2717
+ if (level === 2) {
2718
+ if (sex === "m") {
2719
+ return "\u0432\u043D\u0443\u043A";
2720
+ }
2721
+ if (sex === "f") {
2722
+ return "\u0432\u043D\u0443\u0447\u043A\u0430";
2723
+ }
2724
+ return "\u0432\u043D\u0443\u043A/\u0432\u043D\u0443\u0447\u043A\u0430";
2725
+ }
2726
+ const pra = praRepeat(level - 2);
2727
+ if (sex === "m") {
2728
+ return `${pra}\u0432\u043D\u0443\u043A`;
2729
+ }
2730
+ if (sex === "f") {
2731
+ return `${pra}\u0432\u043D\u0443\u0447\u043A\u0430`;
2732
+ }
2733
+ return `${pra}\u0432\u043D\u0443\u043A/\u0432\u043D\u0443\u0447\u043A\u0430`;
2734
+ }
2735
+ sibling() {
2736
+ const sex = sexOf(this.personN);
2737
+ if (sex === "m") {
2738
+ return "\u0431\u0440\u0430\u0442";
2739
+ }
2740
+ if (sex === "f") {
2741
+ return "\u0441\u0435\u0441\u0442\u0440\u0430";
2742
+ }
2743
+ return "\u0441\u0438\u0431\u043B\u0438\u043D\u0433";
2744
+ }
2745
+ halfBlood(relation) {
2746
+ if (!relation || !this.isHalfBlood) {
2747
+ return relation ?? "";
2748
+ }
2749
+ if (/сестра|дочь|мать|тётя|бабушка|жена|племянница|внучка/.test(
2750
+ relation
2751
+ )) {
2752
+ return `\u0441\u0432\u043E\u0434\u043D\u0430\u044F ${relation}`;
2753
+ }
2754
+ return `\u0441\u0432\u043E\u0434\u043D\u044B\u0439 ${relation}`;
2755
+ }
2756
+ spouse() {
2757
+ const sex = sexOf(this.personN);
2758
+ if (sex === "m") {
2759
+ return "\u043C\u0443\u0436";
2760
+ }
2761
+ if (sex === "f") {
2762
+ return "\u0436\u0435\u043D\u0430";
2763
+ }
2764
+ return "\u0441\u0443\u043F\u0440\u0443\u0433";
2765
+ }
2766
+ ofSpouse(relation) {
2767
+ if (!relation) {
2768
+ return "";
2769
+ }
2770
+ const spouse = this.path?.[1].indi;
2771
+ const sex = sexOf(spouse);
2772
+ const spouseType = sex === "m" ? "\u043C\u0443\u0436" : sex === "f" ? "\u0436\u0435\u043D\u0430" : "\u0441\u0443\u043F\u0440\u0443\u0433";
2773
+ return `${relation} ${toGenitive(spouseType)}`;
2774
+ }
2775
+ spouseOf(relation) {
2776
+ if (!relation) {
2777
+ return "";
2778
+ }
2779
+ const spouse = this.path?.[this.path.length - 1].indi;
2780
+ const sex = sexOf(spouse);
2781
+ const spouseType = sex === "m" ? "\u043C\u0443\u0436" : sex === "f" ? "\u0436\u0435\u043D\u0430" : "\u0441\u0443\u043F\u0440\u0443\u0433";
2782
+ return `${spouseType} ${toGenitive(relation)}`;
2783
+ }
2784
+ of(relation) {
2785
+ const formattedName = nameFormatter(this.path?.[0]?.indi, {
2786
+ nameOrder: "first-last"
2787
+ });
2788
+ let name = formattedName.inOrder.filter(Boolean).join(" ");
2789
+ if (this.displayName === "none") {
2790
+ name = "";
2791
+ } else if (this.displayName === "givenname") {
2792
+ name = formattedName.givenname;
2793
+ } else if (this.displayName === "surname") {
2794
+ name = `${formattedName.surname}`;
2795
+ }
2796
+ if (!name || !relation) {
2797
+ return relation ?? "";
2798
+ }
2799
+ return `${name}: ${relation}`;
2800
+ }
2801
+ inLaw(relation) {
2802
+ let inLawRelation = relation;
2803
+ Object.keys(InLawsRu).find((pattern) => {
2804
+ const regex = new RegExp(`^${pattern}$`);
2805
+ if (relation?.match(regex)) {
2806
+ inLawRelation = InLawsRu[pattern];
2807
+ return true;
2808
+ }
2809
+ return false;
2810
+ });
2811
+ return inLawRelation ?? "";
2812
+ }
2813
+ relationType(relation) {
2814
+ if (!relation || !this.pathN?.relation) {
2815
+ return relation ?? "";
2816
+ }
2817
+ return `${this.pathN.relation} ${relation}`;
2818
+ }
2819
+ };
2820
+
2508
2821
  // src/kinship-translator/kinship-translator.ts
2509
2822
  var KinshipTranslator = class {
2510
2823
  constructor(person1, person2, lang = "en", entirePath, displayName = "givenname") {
@@ -2598,6 +2911,7 @@ var KinshipTranslator = class {
2598
2911
  } else if (personN.level !== 0) {
2599
2912
  relation = this.removal();
2600
2913
  }
2914
+ relation = this.translator?.halfBlood(relation);
2601
2915
  relation = this.translator?.relationType(relation);
2602
2916
  if (this.translator?.isOfSpouse) {
2603
2917
  relation = this.translator?.ofSpouse(relation);
@@ -3366,6 +3680,135 @@ var profilePictureCache = (gedcom, key, value) => {
3366
3680
  const cached = caches.profilePictureCache?.[fullKey];
3367
3681
  return cached;
3368
3682
  };
3683
+ var isNonBiologicalPath = (path) => path.some(
3684
+ (item) => item.relation && item.relation !== "biological" /* BIOLOGICAL */
3685
+ );
3686
+ var invertHop = (kinship) => {
3687
+ if (kinship === "parent") {
3688
+ return "child";
3689
+ }
3690
+ if (kinship === "child") {
3691
+ return "parent";
3692
+ }
3693
+ return kinship;
3694
+ };
3695
+ var hopRelation = (from, toIndi, kinship, inherited) => {
3696
+ if (kinship === "parent" || kinship === "child") {
3697
+ const parent = kinship === "parent" ? toIndi : from.indi;
3698
+ const child = kinship === "parent" ? from.indi : toIndi;
3699
+ const currentRelation = child.getParentType(parent);
3700
+ if (currentRelation && currentRelation !== "biological" /* BIOLOGICAL */) {
3701
+ return currentRelation;
3702
+ }
3703
+ }
3704
+ if (inherited && inherited !== "biological" /* BIOLOGICAL */) {
3705
+ return inherited;
3706
+ }
3707
+ return void 0;
3708
+ };
3709
+ var rebuildPathFromHops = (hops, skipRelation = false) => {
3710
+ if (hops.length === 0) {
3711
+ return [];
3712
+ }
3713
+ const path = [
3714
+ {
3715
+ indi: hops[0].indi,
3716
+ kinship: "self",
3717
+ level: 0,
3718
+ levelUp: 0,
3719
+ levelDown: 0,
3720
+ degree: 0
3721
+ }
3722
+ ];
3723
+ for (let i = 1; i < hops.length; i++) {
3724
+ const prev = path[i - 1];
3725
+ const { indi, kinship } = hops[i];
3726
+ const relation = skipRelation ? void 0 : hopRelation(prev, indi, kinship, prev.relation);
3727
+ if (kinship === "parent") {
3728
+ path.push({
3729
+ indi,
3730
+ kinship,
3731
+ relation,
3732
+ level: prev.level + 1,
3733
+ levelUp: prev.levelUp + 1,
3734
+ levelDown: prev.levelDown,
3735
+ degree: prev.degree
3736
+ });
3737
+ continue;
3738
+ }
3739
+ if (kinship === "child") {
3740
+ path.push({
3741
+ indi,
3742
+ kinship,
3743
+ relation,
3744
+ level: prev.level - 1,
3745
+ levelUp: prev.levelUp,
3746
+ levelDown: prev.levelDown + 1,
3747
+ degree: prev.levelUp ? prev.level > 0 ? prev.levelUp - prev.level + 1 : prev.levelDown - Math.abs(prev.level) : 0
3748
+ });
3749
+ continue;
3750
+ }
3751
+ path.push({
3752
+ indi,
3753
+ kinship,
3754
+ relation,
3755
+ level: prev.level,
3756
+ levelUp: prev.levelUp,
3757
+ levelDown: prev.levelDown,
3758
+ degree: prev.degree
3759
+ });
3760
+ }
3761
+ return path;
3762
+ };
3763
+ var storePathIfBetter = (gedcom, fromId, toId, path) => {
3764
+ const key = `${fromId}|${toId}`;
3765
+ const existing = pathCache(gedcom, key);
3766
+ if (existing && (!isNonBiologicalPath(existing) || isNonBiologicalPath(path))) {
3767
+ return;
3768
+ }
3769
+ pathCache(gedcom, key, path);
3770
+ };
3771
+ var cacheDiscoveredPath = (gedcom, path) => {
3772
+ const n = path.length;
3773
+ if (n < 2) {
3774
+ return;
3775
+ }
3776
+ for (let i = 0; i < n; i++) {
3777
+ const fromId = path[i].indi.id;
3778
+ if (!fromId) {
3779
+ continue;
3780
+ }
3781
+ for (let j = i + 1; j < n; j++) {
3782
+ const toId = path[j].indi.id;
3783
+ if (!toId) {
3784
+ continue;
3785
+ }
3786
+ const isOriginalPair = i === 0 && j === n - 1;
3787
+ const isDirectHop = j === i + 1;
3788
+ const slice = path.slice(i, j + 1);
3789
+ const sliceMixed = isNonBiologicalPath(slice);
3790
+ if (!isOriginalPair && !isDirectHop && sliceMixed) {
3791
+ continue;
3792
+ }
3793
+ const forward = i === 0 ? slice : rebuildPathFromHops(slice, !sliceMixed);
3794
+ const reverseHops = [
3795
+ {
3796
+ indi: slice[slice.length - 1].indi,
3797
+ kinship: "self"
3798
+ }
3799
+ ];
3800
+ for (let k = slice.length - 2; k >= 0; k--) {
3801
+ reverseHops.push({
3802
+ indi: slice[k].indi,
3803
+ kinship: invertHop(slice[k + 1].kinship)
3804
+ });
3805
+ }
3806
+ const reverse = rebuildPathFromHops(reverseHops, !sliceMixed);
3807
+ storePathIfBetter(gedcom, fromId, toId, forward);
3808
+ storePathIfBetter(gedcom, toId, fromId, reverse);
3809
+ }
3810
+ }
3811
+ };
3369
3812
 
3370
3813
  // src/utils/get-places.ts
3371
3814
  var getPlaces = (common, type = ["ALL" /* All */], maxLevel = 1, level = 0, mainKey) => {
@@ -5358,7 +5801,6 @@ var Indi = class extends Common {
5358
5801
  if (cache) {
5359
5802
  return cache;
5360
5803
  }
5361
- const visited = new Individuals().append(this);
5362
5804
  const mainItem = {
5363
5805
  indi: this,
5364
5806
  level: 0,
@@ -5367,129 +5809,155 @@ var Indi = class extends Common {
5367
5809
  degree: 0,
5368
5810
  kinship: "self"
5369
5811
  };
5370
- const path = [mainItem];
5812
+ const mainPath = [mainItem];
5371
5813
  if (this.id === usedIndi.id) {
5372
- return path;
5814
+ return mainPath;
5373
5815
  }
5374
- const queue = [
5375
- {
5376
- ...mainItem,
5377
- path
5378
- }
5379
- ];
5380
- let helper = 0;
5381
- while (queue.length > 0) {
5382
- if (helper++ > 1e6) {
5383
- break;
5384
- }
5385
- const {
5386
- indi,
5387
- path: path2,
5388
- kinship,
5389
- relation,
5390
- level,
5391
- levelUp,
5392
- levelDown,
5393
- degree,
5394
- breakOnNext,
5395
- breakAfterNext,
5396
- inLaw
5397
- } = queue.shift();
5398
- if (usedIndi.id === indi.id) {
5399
- if (breakOnNext) {
5400
- return void 0;
5816
+ const bfs = (biologicalOnly) => {
5817
+ const visited = new Individuals().append(this);
5818
+ const queue = [
5819
+ {
5820
+ ...mainItem,
5821
+ path: mainPath
5401
5822
  }
5402
- pathCache(this._gedcom, cacheKey, path2);
5403
- return path2;
5404
- }
5405
- visited.append(indi);
5406
- const additional = {};
5407
- if (breakOnNext || breakAfterNext) {
5408
- additional.breakOnNext = breakOnNext || breakAfterNext;
5409
- }
5410
- if (inLaw) {
5411
- additional.inLaw = inLaw;
5412
- }
5413
- if (kinship === "spouse" && breakAfterSpouse) {
5414
- if (path2.length <= 2) {
5415
- additional.inLaw = true;
5416
- } else {
5417
- additional.breakOnNext = true;
5823
+ ];
5824
+ let helper = 0;
5825
+ while (queue.length > 0) {
5826
+ if (helper++ > 1e6) {
5827
+ break;
5418
5828
  }
5419
- }
5420
- if (kinship !== "child" || !breakAfterSpouse) {
5421
- indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(indi.getFathers().copy().merge(indi.getMothers())).forEach((relative) => {
5829
+ const {
5830
+ indi,
5831
+ path,
5832
+ kinship,
5833
+ relation,
5834
+ level,
5835
+ levelUp,
5836
+ levelDown,
5837
+ degree,
5838
+ breakOnNext,
5839
+ breakAfterNext,
5840
+ inLaw
5841
+ } = queue.shift();
5842
+ if (usedIndi.id === indi.id) {
5843
+ if (breakOnNext) {
5844
+ return void 0;
5845
+ }
5846
+ return path;
5847
+ }
5848
+ visited.append(indi);
5849
+ const additional = {};
5850
+ if (breakOnNext || breakAfterNext) {
5851
+ additional.breakOnNext = breakOnNext || breakAfterNext;
5852
+ }
5853
+ if (inLaw) {
5854
+ additional.inLaw = inLaw;
5855
+ }
5856
+ if (!biologicalOnly && kinship === "spouse" && breakAfterSpouse) {
5857
+ if (path.length <= 2) {
5858
+ additional.inLaw = true;
5859
+ } else {
5860
+ additional.breakOnNext = true;
5861
+ }
5862
+ }
5863
+ if (kinship !== "child" || !breakAfterSpouse) {
5864
+ indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(indi.getFathers().copy().merge(indi.getMothers())).forEach((relative) => {
5865
+ if (!visited.has(relative)) {
5866
+ const currentRelation = indi.getParentType(relative);
5867
+ const isNonBiological = !!currentRelation && currentRelation !== "biological" /* BIOLOGICAL */;
5868
+ if (biologicalOnly && isNonBiological) {
5869
+ return;
5870
+ }
5871
+ if (!biologicalOnly && breakAfterNonBiological && isNonBiological) {
5872
+ additional.breakAfterNext = true;
5873
+ }
5874
+ const newItem = {
5875
+ indi: relative,
5876
+ kinship: "parent",
5877
+ relation: isNonBiological ? currentRelation : relation,
5878
+ level: level + 1,
5879
+ levelUp: levelUp + 1,
5880
+ levelDown,
5881
+ degree,
5882
+ ...additional
5883
+ };
5884
+ queue.push({
5885
+ ...newItem,
5886
+ path: [...path, newItem]
5887
+ });
5888
+ }
5889
+ });
5890
+ }
5891
+ indi.getChildren().forEach((relative) => {
5422
5892
  if (!visited.has(relative)) {
5423
- const currentRelation = indi.getParentType(relative);
5424
- if (breakAfterNonBiological && currentRelation !== "biological" /* BIOLOGICAL */) {
5893
+ const currentRelation = relative.getParentType(indi);
5894
+ const isNonBiological = !!currentRelation && currentRelation !== "biological" /* BIOLOGICAL */;
5895
+ if (biologicalOnly && isNonBiological) {
5896
+ return;
5897
+ }
5898
+ if (!biologicalOnly && breakAfterNonBiological && isNonBiological) {
5425
5899
  additional.breakAfterNext = true;
5426
5900
  }
5427
5901
  const newItem = {
5428
5902
  indi: relative,
5429
- kinship: "parent",
5430
- relation: currentRelation && currentRelation !== "biological" /* BIOLOGICAL */ ? currentRelation : relation,
5431
- level: level + 1,
5432
- levelUp: levelUp + 1,
5433
- levelDown,
5434
- degree,
5903
+ kinship: "child",
5904
+ relation: isNonBiological ? currentRelation : relation,
5905
+ level: level - 1,
5906
+ levelUp,
5907
+ levelDown: levelDown + 1,
5908
+ degree: levelUp ? level > 0 ? levelUp - level + 1 : levelDown - Math.abs(level) : 0,
5435
5909
  ...additional
5436
5910
  };
5437
5911
  queue.push({
5438
5912
  ...newItem,
5439
- path: [...path2, newItem]
5913
+ path: [...path, newItem]
5440
5914
  });
5441
5915
  }
5442
5916
  });
5443
- }
5444
- indi.getChildren().forEach((relative) => {
5445
- if (!visited.has(relative)) {
5446
- const currentRelation = relative.getParentType(indi);
5447
- if (breakAfterNonBiological && currentRelation !== "biological" /* BIOLOGICAL */) {
5448
- additional.breakAfterNext = true;
5449
- }
5450
- const newItem = {
5451
- indi: relative,
5452
- kinship: "child",
5453
- relation: currentRelation && currentRelation !== "biological" /* BIOLOGICAL */ ? currentRelation : relation,
5454
- level: level - 1,
5455
- levelUp,
5456
- levelDown: levelDown + 1,
5457
- degree: levelUp ? level > 0 ? levelUp - level + 1 : levelDown - Math.abs(level) : 0,
5458
- ...additional
5459
- };
5460
- queue.push({
5461
- ...newItem,
5462
- path: [...path2, newItem]
5463
- });
5917
+ if (biologicalOnly) {
5918
+ continue;
5464
5919
  }
5465
- });
5466
- indi.getCoParents().forEach((relative) => {
5467
- if (!visited.has(relative)) {
5468
- const currentAddition = {};
5469
- if (relation && relation !== "biological" /* BIOLOGICAL */) {
5470
- currentAddition.relation = relation;
5471
- }
5472
- if (inLaw) {
5473
- currentAddition.breakOnNext = true;
5920
+ indi.getCoParents().forEach((relative) => {
5921
+ if (!visited.has(relative)) {
5922
+ const currentAddition = {};
5923
+ if (relation && relation !== "biological" /* BIOLOGICAL */) {
5924
+ currentAddition.relation = relation;
5925
+ }
5926
+ if (inLaw) {
5927
+ currentAddition.breakOnNext = true;
5928
+ }
5929
+ const newItem = {
5930
+ indi: relative,
5931
+ kinship: "spouse",
5932
+ level,
5933
+ levelUp,
5934
+ levelDown,
5935
+ degree,
5936
+ ...additional,
5937
+ ...currentAddition
5938
+ };
5939
+ queue.push({
5940
+ ...newItem,
5941
+ path: [...path, newItem]
5942
+ });
5474
5943
  }
5475
- const newItem = {
5476
- indi: relative,
5477
- kinship: "spouse",
5478
- level,
5479
- levelUp,
5480
- levelDown,
5481
- degree,
5482
- ...additional,
5483
- ...currentAddition
5484
- };
5485
- queue.push({
5486
- ...newItem,
5487
- path: [...path2, newItem]
5488
- });
5489
- }
5490
- });
5944
+ });
5945
+ }
5946
+ return void 0;
5947
+ };
5948
+ const foundPath = bfs(false);
5949
+ const lastItem = foundPath?.[foundPath.length - 1];
5950
+ if (lastItem?.relation && lastItem.relation !== "biological" /* BIOLOGICAL */) {
5951
+ const biologicalPath = bfs(true);
5952
+ if (biologicalPath) {
5953
+ cacheDiscoveredPath(this._gedcom, biologicalPath);
5954
+ return biologicalPath;
5955
+ }
5491
5956
  }
5492
- return void 0;
5957
+ if (foundPath) {
5958
+ cacheDiscoveredPath(this._gedcom, foundPath);
5959
+ }
5960
+ return foundPath;
5493
5961
  }
5494
5962
  kinship(other, showMainPerson, lang = "en", entirePath, displayName = "givenname") {
5495
5963
  const KinshipTranslatorClass2 = getKinshipTranslatorClass();
@@ -6294,7 +6762,7 @@ var createIndi = (gedcom, id, main, parent) => {
6294
6762
 
6295
6763
  // package.json
6296
6764
  var package_default = {
6297
- version: "2.0.8"};
6765
+ version: "2.0.10"};
6298
6766
 
6299
6767
  // src/utils/get-product-details.ts
6300
6768
  var getVersion = () => package_default.version;