@treeviz/gedcom-parser 2.0.7 → 2.0.9

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 (29) hide show
  1. package/dist/classes/date.d.ts +2 -0
  2. package/dist/classes/date.d.ts.map +1 -1
  3. package/dist/classes/index.js +424 -159
  4. package/dist/classes/indi.d.ts.map +1 -1
  5. package/dist/cli/index.js +424 -159
  6. package/dist/constants/index.js +423 -158
  7. package/dist/factories/index.js +423 -158
  8. package/dist/index.js +425 -160
  9. package/dist/kinship-translator/index.js +423 -158
  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/patterns.es.d.ts.map +1 -1
  26. package/dist/utils/cache.d.ts +14 -1
  27. package/dist/utils/cache.d.ts.map +1 -1
  28. package/dist/utils/index.js +425 -160
  29. 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
  }
@@ -482,14 +523,34 @@ var KinshipTranslatorHU = class extends KinshipTranslatorBasic {
482
523
  return `${prefix.replace(/nagy$/, "")}unoka`;
483
524
  }
484
525
  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
526
  return "testv\xE9r";
492
527
  }
528
+ halfBlood(relation) {
529
+ if (!relation || !this.isHalfBlood) {
530
+ return relation ?? "";
531
+ }
532
+ const [head, ...rest] = relation.split(" ");
533
+ if (!head) {
534
+ return relation;
535
+ }
536
+ const prefixed = this.prefixHalf(head);
537
+ return [prefixed, ...rest].join(" ");
538
+ }
539
+ /**
540
+ * AkH. 139: compounds of more than two members stay closed up to 6
541
+ * syllables; longer ones are hyphenated at the main boundary. A head
542
+ * that is already hyphenated also takes a hyphenated half- prefix.
543
+ */
544
+ prefixHalf(head) {
545
+ if (head.includes("-") || !/[aáeéiíoóöőuúüű]/i.test(head)) {
546
+ return `f\xE9l-${head}`;
547
+ }
548
+ const syllables = (head.match(/[aáeéiíoóöőuúüű]/gi) ?? []).length + 1;
549
+ if (syllables > 6) {
550
+ return `f\xE9l-${head}`;
551
+ }
552
+ return `f\xE9l${head}`;
553
+ }
493
554
  spouse() {
494
555
  if (this.personN?.isMale()) {
495
556
  return "f\xE9rj";
@@ -688,20 +749,22 @@ var KinshipTranslatorEn = class extends KinshipTranslatorBasic {
688
749
  return `${prefix}child`;
689
750
  }
690
751
  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
752
  if (this.personN?.isMale()) {
699
- return `${prefix}brother`;
753
+ return "brother";
700
754
  }
701
755
  if (this.personN?.isFemale()) {
702
- return `${prefix}sister`;
756
+ return "sister";
703
757
  }
704
- return `${prefix}sibling`;
758
+ return "sibling";
759
+ }
760
+ halfBlood(relation) {
761
+ if (!relation || !this.isHalfBlood) {
762
+ return relation ?? "";
763
+ }
764
+ if (relation.includes(" ")) {
765
+ return `half ${relation}`;
766
+ }
767
+ return `half-${relation}`;
705
768
  }
706
769
  spouse() {
707
770
  if (this.personN?.isMale()) {
@@ -883,20 +946,19 @@ var KinshipTranslatorFr = class extends KinshipTranslatorBasic {
883
946
  return `${prefix}enfant`;
884
947
  }
885
948
  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
949
  if (this.personN?.isMale()) {
894
- return `${prefix}fr\xE8re`;
950
+ return "fr\xE8re";
895
951
  }
896
952
  if (this.personN?.isFemale()) {
897
- return `${prefix}s\u0153ur`;
953
+ return "s\u0153ur";
898
954
  }
899
- return `${prefix}fr\xE8re/s\u0153ur`;
955
+ return "fr\xE8re/s\u0153ur";
956
+ }
957
+ halfBlood(relation) {
958
+ if (!relation || !this.isHalfBlood) {
959
+ return relation ?? "";
960
+ }
961
+ return `demi-${relation}`;
900
962
  }
901
963
  spouse() {
902
964
  if (this.personN?.isMale()) {
@@ -993,12 +1055,12 @@ var InLawsEs = {
993
1055
  "madre del (c\xF3nyuge|esposa|esposo)": "suegra",
994
1056
  "padre del (c\xF3nyuge|esposa|esposo)": "suegro",
995
1057
  "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"
1058
+ "esposa de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ada",
1059
+ "esposo de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ado",
1060
+ "c\xF3nyuge de (medio |media |medio/a )?(hermano/hermana|hermana|hermano)": "cu\xF1ado/cu\xF1ada",
1061
+ "(medio |media |medio/a )?hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ada",
1062
+ "(medio |media |medio/a )?hermano del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado",
1063
+ "(medio |media |medio/a )?hermano/hermana del (c\xF3nyuge|esposa|esposo)": "cu\xF1ado/cu\xF1ada"
1002
1064
  };
1003
1065
 
1004
1066
  // src/kinship-translator/kinship-translator.es.ts
@@ -1078,20 +1140,25 @@ var KinshipTranslatorEs = class extends KinshipTranslatorBasic {
1078
1140
  return `${prefix}hijo/hija`;
1079
1141
  }
1080
1142
  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
1143
  if (this.personN?.isMale()) {
1089
- return `${prefix}hermano`;
1144
+ return "hermano";
1145
+ }
1146
+ if (this.personN?.isFemale()) {
1147
+ return "hermana";
1148
+ }
1149
+ return "hermano/hermana";
1150
+ }
1151
+ halfBlood(relation) {
1152
+ if (!relation || !this.isHalfBlood) {
1153
+ return relation ?? "";
1090
1154
  }
1091
1155
  if (this.personN?.isFemale()) {
1092
- return `${prefix}hermana`;
1156
+ return `media ${relation}`;
1157
+ }
1158
+ if (this.personN?.isMale()) {
1159
+ return `medio ${relation}`;
1093
1160
  }
1094
- return `${prefix}hermano/hermana`;
1161
+ return `medio/a ${relation}`;
1095
1162
  }
1096
1163
  spouse() {
1097
1164
  if (this.personN?.isMale()) {
@@ -1273,6 +1340,7 @@ var KinshipTranslator = class {
1273
1340
  } else if (personN.level !== 0) {
1274
1341
  relation = this.removal();
1275
1342
  }
1343
+ relation = this.translator?.halfBlood(relation);
1276
1344
  relation = this.translator?.relationType(relation);
1277
1345
  if (this.translator?.isOfSpouse) {
1278
1346
  relation = this.translator?.ofSpouse(relation);
@@ -2586,6 +2654,20 @@ var LONG_NOTES = {
2586
2654
  "Bef.": "Before",
2587
2655
  "Aft.": "After"
2588
2656
  };
2657
+ var STANDARD_QUALIFIERS = {
2658
+ ABT: "Abt.",
2659
+ ABOUT: "Abt.",
2660
+ BEF: "Bef.",
2661
+ BEFORE: "Bef.",
2662
+ AFT: "Aft.",
2663
+ AFTER: "Aft."
2664
+ };
2665
+ var EXPORT_QUALIFIERS = {
2666
+ "Abt.": "ABT",
2667
+ "Bef.": "BEF",
2668
+ "Aft.": "AFT"
2669
+ };
2670
+ var GEDCOM_MONTHS = /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/g;
2589
2671
  var NOTE_MARKER = "####";
2590
2672
  var formatDateWithComponents = (date, hasDay, hasMonth, hasYear, noteValue, baseFormat = "dd MMM yyyy", locale) => {
2591
2673
  const hasNote = baseFormat.includes("NOTE");
@@ -2619,6 +2701,17 @@ var CommonDate = class extends Common {
2619
2701
  this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
2620
2702
  this.NOTE.value = noteMatch?.note;
2621
2703
  validValue = value.replace(noteRegExp, "");
2704
+ } else {
2705
+ const qualifierMatch = value.match(
2706
+ /^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER)\b\s*/i
2707
+ );
2708
+ const qualifier = qualifierMatch?.groups?.qualifier?.toUpperCase();
2709
+ const note = qualifier ? STANDARD_QUALIFIERS[qualifier] : void 0;
2710
+ if (note) {
2711
+ this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
2712
+ this.NOTE.value = note;
2713
+ validValue = value.slice(qualifierMatch[0].length);
2714
+ }
2622
2715
  }
2623
2716
  const acceptedDate = this.isValidDateFormat(validValue);
2624
2717
  if (acceptedDate) {
@@ -2724,7 +2817,23 @@ var CommonDate = class extends Common {
2724
2817
  );
2725
2818
  }
2726
2819
  exportValue() {
2727
- return this.toValue("NOTE dd MMM yyyy", null);
2820
+ const formatted = this.toValue("NOTE dd MMM yyyy", null);
2821
+ if (!formatted) {
2822
+ return formatted;
2823
+ }
2824
+ const note = this.NOTE?.value?.trim();
2825
+ const qualifier = note ? EXPORT_QUALIFIERS[note] : void 0;
2826
+ const standardized = qualifier ? formatted.replace(note, qualifier) : formatted;
2827
+ return standardized.replace(
2828
+ GEDCOM_MONTHS,
2829
+ (month) => month.toUpperCase()
2830
+ );
2831
+ }
2832
+ toGedcomLines(tag, level = 0, options) {
2833
+ const internal = new RegExp(
2834
+ `^${level} (DAY|MONTH|YEAR)( |$)|^${level} NOTE (Abt\\.|Bef\\.|Aft\\.)$`
2835
+ );
2836
+ return super.toGedcomLines(tag, level, options).filter((line) => !internal.test(line));
2728
2837
  }
2729
2838
  inRange(range, trueIfNoYear = false) {
2730
2839
  return inRange(this.YEAR?.value, range, trueIfNoYear);
@@ -3049,6 +3158,135 @@ var profilePictureCache = (gedcom, key, value) => {
3049
3158
  const cached = caches.profilePictureCache?.[fullKey];
3050
3159
  return cached;
3051
3160
  };
3161
+ var isNonBiologicalPath = (path) => path.some(
3162
+ (item) => item.relation && item.relation !== "biological" /* BIOLOGICAL */
3163
+ );
3164
+ var invertHop = (kinship) => {
3165
+ if (kinship === "parent") {
3166
+ return "child";
3167
+ }
3168
+ if (kinship === "child") {
3169
+ return "parent";
3170
+ }
3171
+ return kinship;
3172
+ };
3173
+ var hopRelation = (from, toIndi, kinship, inherited) => {
3174
+ if (kinship === "parent" || kinship === "child") {
3175
+ const parent = kinship === "parent" ? toIndi : from.indi;
3176
+ const child = kinship === "parent" ? from.indi : toIndi;
3177
+ const currentRelation = child.getParentType(parent);
3178
+ if (currentRelation && currentRelation !== "biological" /* BIOLOGICAL */) {
3179
+ return currentRelation;
3180
+ }
3181
+ }
3182
+ if (inherited && inherited !== "biological" /* BIOLOGICAL */) {
3183
+ return inherited;
3184
+ }
3185
+ return void 0;
3186
+ };
3187
+ var rebuildPathFromHops = (hops, skipRelation = false) => {
3188
+ if (hops.length === 0) {
3189
+ return [];
3190
+ }
3191
+ const path = [
3192
+ {
3193
+ indi: hops[0].indi,
3194
+ kinship: "self",
3195
+ level: 0,
3196
+ levelUp: 0,
3197
+ levelDown: 0,
3198
+ degree: 0
3199
+ }
3200
+ ];
3201
+ for (let i = 1; i < hops.length; i++) {
3202
+ const prev = path[i - 1];
3203
+ const { indi, kinship } = hops[i];
3204
+ const relation = skipRelation ? void 0 : hopRelation(prev, indi, kinship, prev.relation);
3205
+ if (kinship === "parent") {
3206
+ path.push({
3207
+ indi,
3208
+ kinship,
3209
+ relation,
3210
+ level: prev.level + 1,
3211
+ levelUp: prev.levelUp + 1,
3212
+ levelDown: prev.levelDown,
3213
+ degree: prev.degree
3214
+ });
3215
+ continue;
3216
+ }
3217
+ if (kinship === "child") {
3218
+ path.push({
3219
+ indi,
3220
+ kinship,
3221
+ relation,
3222
+ level: prev.level - 1,
3223
+ levelUp: prev.levelUp,
3224
+ levelDown: prev.levelDown + 1,
3225
+ degree: prev.levelUp ? prev.level > 0 ? prev.levelUp - prev.level + 1 : prev.levelDown - Math.abs(prev.level) : 0
3226
+ });
3227
+ continue;
3228
+ }
3229
+ path.push({
3230
+ indi,
3231
+ kinship,
3232
+ relation,
3233
+ level: prev.level,
3234
+ levelUp: prev.levelUp,
3235
+ levelDown: prev.levelDown,
3236
+ degree: prev.degree
3237
+ });
3238
+ }
3239
+ return path;
3240
+ };
3241
+ var storePathIfBetter = (gedcom, fromId, toId, path) => {
3242
+ const key = `${fromId}|${toId}`;
3243
+ const existing = pathCache(gedcom, key);
3244
+ if (existing && (!isNonBiologicalPath(existing) || isNonBiologicalPath(path))) {
3245
+ return;
3246
+ }
3247
+ pathCache(gedcom, key, path);
3248
+ };
3249
+ var cacheDiscoveredPath = (gedcom, path) => {
3250
+ const n = path.length;
3251
+ if (n < 2) {
3252
+ return;
3253
+ }
3254
+ for (let i = 0; i < n; i++) {
3255
+ const fromId = path[i].indi.id;
3256
+ if (!fromId) {
3257
+ continue;
3258
+ }
3259
+ for (let j = i + 1; j < n; j++) {
3260
+ const toId = path[j].indi.id;
3261
+ if (!toId) {
3262
+ continue;
3263
+ }
3264
+ const isOriginalPair = i === 0 && j === n - 1;
3265
+ const isDirectHop = j === i + 1;
3266
+ const slice = path.slice(i, j + 1);
3267
+ const sliceMixed = isNonBiologicalPath(slice);
3268
+ if (!isOriginalPair && !isDirectHop && sliceMixed) {
3269
+ continue;
3270
+ }
3271
+ const forward = i === 0 ? slice : rebuildPathFromHops(slice, !sliceMixed);
3272
+ const reverseHops = [
3273
+ {
3274
+ indi: slice[slice.length - 1].indi,
3275
+ kinship: "self"
3276
+ }
3277
+ ];
3278
+ for (let k = slice.length - 2; k >= 0; k--) {
3279
+ reverseHops.push({
3280
+ indi: slice[k].indi,
3281
+ kinship: invertHop(slice[k + 1].kinship)
3282
+ });
3283
+ }
3284
+ const reverse = rebuildPathFromHops(reverseHops, !sliceMixed);
3285
+ storePathIfBetter(gedcom, fromId, toId, forward);
3286
+ storePathIfBetter(gedcom, toId, fromId, reverse);
3287
+ }
3288
+ }
3289
+ };
3052
3290
 
3053
3291
  // src/utils/get-places.ts
3054
3292
  var getPlaces = (common, type = ["ALL" /* All */], maxLevel = 1, level = 0, mainKey) => {
@@ -5069,7 +5307,6 @@ var Indi = class extends Common {
5069
5307
  if (cache) {
5070
5308
  return cache;
5071
5309
  }
5072
- const visited = new Individuals().append(this);
5073
5310
  const mainItem = {
5074
5311
  indi: this,
5075
5312
  level: 0,
@@ -5078,129 +5315,155 @@ var Indi = class extends Common {
5078
5315
  degree: 0,
5079
5316
  kinship: "self"
5080
5317
  };
5081
- const path = [mainItem];
5318
+ const mainPath = [mainItem];
5082
5319
  if (this.id === usedIndi.id) {
5083
- return path;
5320
+ return mainPath;
5084
5321
  }
5085
- const queue = [
5086
- {
5087
- ...mainItem,
5088
- path
5089
- }
5090
- ];
5091
- let helper = 0;
5092
- while (queue.length > 0) {
5093
- if (helper++ > 1e6) {
5094
- break;
5095
- }
5096
- const {
5097
- indi,
5098
- path: path2,
5099
- kinship,
5100
- relation,
5101
- level,
5102
- levelUp,
5103
- levelDown,
5104
- degree,
5105
- breakOnNext,
5106
- breakAfterNext,
5107
- inLaw
5108
- } = queue.shift();
5109
- if (usedIndi.id === indi.id) {
5110
- if (breakOnNext) {
5111
- return void 0;
5322
+ const bfs = (biologicalOnly) => {
5323
+ const visited = new Individuals().append(this);
5324
+ const queue = [
5325
+ {
5326
+ ...mainItem,
5327
+ path: mainPath
5112
5328
  }
5113
- pathCache(this._gedcom, cacheKey, path2);
5114
- return path2;
5115
- }
5116
- visited.append(indi);
5117
- const additional = {};
5118
- if (breakOnNext || breakAfterNext) {
5119
- additional.breakOnNext = breakOnNext || breakAfterNext;
5120
- }
5121
- if (inLaw) {
5122
- additional.inLaw = inLaw;
5123
- }
5124
- if (kinship === "spouse" && breakAfterSpouse) {
5125
- if (path2.length <= 2) {
5126
- additional.inLaw = true;
5127
- } else {
5128
- additional.breakOnNext = true;
5329
+ ];
5330
+ let helper = 0;
5331
+ while (queue.length > 0) {
5332
+ if (helper++ > 1e6) {
5333
+ break;
5129
5334
  }
5130
- }
5131
- if (kinship !== "child" || !breakAfterSpouse) {
5132
- indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(indi.getFathers().copy().merge(indi.getMothers())).forEach((relative) => {
5335
+ const {
5336
+ indi,
5337
+ path,
5338
+ kinship,
5339
+ relation,
5340
+ level,
5341
+ levelUp,
5342
+ levelDown,
5343
+ degree,
5344
+ breakOnNext,
5345
+ breakAfterNext,
5346
+ inLaw
5347
+ } = queue.shift();
5348
+ if (usedIndi.id === indi.id) {
5349
+ if (breakOnNext) {
5350
+ return void 0;
5351
+ }
5352
+ return path;
5353
+ }
5354
+ visited.append(indi);
5355
+ const additional = {};
5356
+ if (breakOnNext || breakAfterNext) {
5357
+ additional.breakOnNext = breakOnNext || breakAfterNext;
5358
+ }
5359
+ if (inLaw) {
5360
+ additional.inLaw = inLaw;
5361
+ }
5362
+ if (!biologicalOnly && kinship === "spouse" && breakAfterSpouse) {
5363
+ if (path.length <= 2) {
5364
+ additional.inLaw = true;
5365
+ } else {
5366
+ additional.breakOnNext = true;
5367
+ }
5368
+ }
5369
+ if (kinship !== "child" || !breakAfterSpouse) {
5370
+ indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(indi.getFathers().copy().merge(indi.getMothers())).forEach((relative) => {
5371
+ if (!visited.has(relative)) {
5372
+ const currentRelation = indi.getParentType(relative);
5373
+ const isNonBiological = !!currentRelation && currentRelation !== "biological" /* BIOLOGICAL */;
5374
+ if (biologicalOnly && isNonBiological) {
5375
+ return;
5376
+ }
5377
+ if (!biologicalOnly && breakAfterNonBiological && isNonBiological) {
5378
+ additional.breakAfterNext = true;
5379
+ }
5380
+ const newItem = {
5381
+ indi: relative,
5382
+ kinship: "parent",
5383
+ relation: isNonBiological ? currentRelation : relation,
5384
+ level: level + 1,
5385
+ levelUp: levelUp + 1,
5386
+ levelDown,
5387
+ degree,
5388
+ ...additional
5389
+ };
5390
+ queue.push({
5391
+ ...newItem,
5392
+ path: [...path, newItem]
5393
+ });
5394
+ }
5395
+ });
5396
+ }
5397
+ indi.getChildren().forEach((relative) => {
5133
5398
  if (!visited.has(relative)) {
5134
- const currentRelation = indi.getParentType(relative);
5135
- if (breakAfterNonBiological && currentRelation !== "biological" /* BIOLOGICAL */) {
5399
+ const currentRelation = relative.getParentType(indi);
5400
+ const isNonBiological = !!currentRelation && currentRelation !== "biological" /* BIOLOGICAL */;
5401
+ if (biologicalOnly && isNonBiological) {
5402
+ return;
5403
+ }
5404
+ if (!biologicalOnly && breakAfterNonBiological && isNonBiological) {
5136
5405
  additional.breakAfterNext = true;
5137
5406
  }
5138
5407
  const newItem = {
5139
5408
  indi: relative,
5140
- kinship: "parent",
5141
- relation: currentRelation && currentRelation !== "biological" /* BIOLOGICAL */ ? currentRelation : relation,
5142
- level: level + 1,
5143
- levelUp: levelUp + 1,
5144
- levelDown,
5145
- degree,
5409
+ kinship: "child",
5410
+ relation: isNonBiological ? currentRelation : relation,
5411
+ level: level - 1,
5412
+ levelUp,
5413
+ levelDown: levelDown + 1,
5414
+ degree: levelUp ? level > 0 ? levelUp - level + 1 : levelDown - Math.abs(level) : 0,
5146
5415
  ...additional
5147
5416
  };
5148
5417
  queue.push({
5149
5418
  ...newItem,
5150
- path: [...path2, newItem]
5419
+ path: [...path, newItem]
5151
5420
  });
5152
5421
  }
5153
5422
  });
5154
- }
5155
- indi.getChildren().forEach((relative) => {
5156
- if (!visited.has(relative)) {
5157
- const currentRelation = relative.getParentType(indi);
5158
- if (breakAfterNonBiological && currentRelation !== "biological" /* BIOLOGICAL */) {
5159
- additional.breakAfterNext = true;
5160
- }
5161
- const newItem = {
5162
- indi: relative,
5163
- kinship: "child",
5164
- relation: currentRelation && currentRelation !== "biological" /* BIOLOGICAL */ ? currentRelation : relation,
5165
- level: level - 1,
5166
- levelUp,
5167
- levelDown: levelDown + 1,
5168
- degree: levelUp ? level > 0 ? levelUp - level + 1 : levelDown - Math.abs(level) : 0,
5169
- ...additional
5170
- };
5171
- queue.push({
5172
- ...newItem,
5173
- path: [...path2, newItem]
5174
- });
5423
+ if (biologicalOnly) {
5424
+ continue;
5175
5425
  }
5176
- });
5177
- indi.getCoParents().forEach((relative) => {
5178
- if (!visited.has(relative)) {
5179
- const currentAddition = {};
5180
- if (relation && relation !== "biological" /* BIOLOGICAL */) {
5181
- currentAddition.relation = relation;
5182
- }
5183
- if (inLaw) {
5184
- currentAddition.breakOnNext = true;
5426
+ indi.getCoParents().forEach((relative) => {
5427
+ if (!visited.has(relative)) {
5428
+ const currentAddition = {};
5429
+ if (relation && relation !== "biological" /* BIOLOGICAL */) {
5430
+ currentAddition.relation = relation;
5431
+ }
5432
+ if (inLaw) {
5433
+ currentAddition.breakOnNext = true;
5434
+ }
5435
+ const newItem = {
5436
+ indi: relative,
5437
+ kinship: "spouse",
5438
+ level,
5439
+ levelUp,
5440
+ levelDown,
5441
+ degree,
5442
+ ...additional,
5443
+ ...currentAddition
5444
+ };
5445
+ queue.push({
5446
+ ...newItem,
5447
+ path: [...path, newItem]
5448
+ });
5185
5449
  }
5186
- const newItem = {
5187
- indi: relative,
5188
- kinship: "spouse",
5189
- level,
5190
- levelUp,
5191
- levelDown,
5192
- degree,
5193
- ...additional,
5194
- ...currentAddition
5195
- };
5196
- queue.push({
5197
- ...newItem,
5198
- path: [...path2, newItem]
5199
- });
5200
- }
5201
- });
5450
+ });
5451
+ }
5452
+ return void 0;
5453
+ };
5454
+ const foundPath = bfs(false);
5455
+ const lastItem = foundPath?.[foundPath.length - 1];
5456
+ if (lastItem?.relation && lastItem.relation !== "biological" /* BIOLOGICAL */) {
5457
+ const biologicalPath = bfs(true);
5458
+ if (biologicalPath) {
5459
+ cacheDiscoveredPath(this._gedcom, biologicalPath);
5460
+ return biologicalPath;
5461
+ }
5202
5462
  }
5203
- return void 0;
5463
+ if (foundPath) {
5464
+ cacheDiscoveredPath(this._gedcom, foundPath);
5465
+ }
5466
+ return foundPath;
5204
5467
  }
5205
5468
  kinship(other, showMainPerson, lang = "en", entirePath, displayName = "givenname") {
5206
5469
  const KinshipTranslatorClass2 = getKinshipTranslatorClass();
@@ -6128,20 +6391,22 @@ var KinshipTranslatorDe = class extends KinshipTranslatorBasic {
6128
6391
  return `${prefix}kind`;
6129
6392
  }
6130
6393
  sibling() {
6131
- const parents1 = this.person1?.getBiologicalParents();
6132
- const parentsN = this.personN?.getBiologicalParents();
6133
- const inter = parents1?.intersection(parentsN);
6134
- let prefix = "";
6135
- if (!inter || inter.length < 2) {
6136
- prefix = "Halb";
6137
- }
6138
6394
  if (this.personN?.isMale()) {
6139
- return `${prefix}bruder`;
6395
+ return "bruder";
6140
6396
  }
6141
6397
  if (this.personN?.isFemale()) {
6142
- return `${prefix}schwester`;
6398
+ return "schwester";
6399
+ }
6400
+ return "geschwister";
6401
+ }
6402
+ halfBlood(relation) {
6403
+ if (!relation || !this.isHalfBlood) {
6404
+ return relation ?? "";
6405
+ }
6406
+ if (/^[A-ZÄÖÜ]/.test(relation) || /[-\s]/.test(relation)) {
6407
+ return `Halb-${relation}`;
6143
6408
  }
6144
- return `${prefix}geschwister`;
6409
+ return `Halb${relation}`;
6145
6410
  }
6146
6411
  spouse() {
6147
6412
  if (this.personN?.isMale()) {