@treeviz/gedcom-parser 2.0.10 → 2.1.0

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 (71) hide show
  1. package/README.md +236 -989
  2. package/dist/classes/common.d.ts +10 -5
  3. package/dist/classes/common.d.ts.map +1 -1
  4. package/dist/classes/date.d.ts +2 -0
  5. package/dist/classes/date.d.ts.map +1 -1
  6. package/dist/classes/fam.d.ts +10 -1
  7. package/dist/classes/fam.d.ts.map +1 -1
  8. package/dist/classes/fams.d.ts.map +1 -1
  9. package/dist/classes/gedcom.d.ts +45 -4
  10. package/dist/classes/gedcom.d.ts.map +1 -1
  11. package/dist/classes/index.js +1770 -279
  12. package/dist/classes/indi.d.ts +24 -1
  13. package/dist/classes/indi.d.ts.map +1 -1
  14. package/dist/classes/list.d.ts.map +1 -1
  15. package/dist/classes/note.d.ts.map +1 -1
  16. package/dist/classes/obje.d.ts +2 -1
  17. package/dist/classes/obje.d.ts.map +1 -1
  18. package/dist/cli/index.js +2802 -1296
  19. package/dist/constants/constants.d.ts +7 -0
  20. package/dist/constants/constants.d.ts.map +1 -1
  21. package/dist/constants/index.js +1599 -989
  22. package/dist/factories/index.js +719 -110
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +3837 -2028
  26. package/dist/interfaces/common.d.ts +6 -4
  27. package/dist/interfaces/common.d.ts.map +1 -1
  28. package/dist/interfaces/fam.d.ts +10 -1
  29. package/dist/interfaces/fam.d.ts.map +1 -1
  30. package/dist/interfaces/gedcom.d.ts +25 -1
  31. package/dist/interfaces/gedcom.d.ts.map +1 -1
  32. package/dist/interfaces/indi.d.ts +15 -1
  33. package/dist/interfaces/indi.d.ts.map +1 -1
  34. package/dist/kinship-translator/index.js +719 -110
  35. package/dist/structures/gedcom.d.ts +2 -0
  36. package/dist/structures/gedcom.d.ts.map +1 -1
  37. package/dist/types/types.d.ts +32 -4
  38. package/dist/types/types.d.ts.map +1 -1
  39. package/dist/utils/common-creator.d.ts.map +1 -1
  40. package/dist/utils/fact-edit.d.ts +34 -0
  41. package/dist/utils/fact-edit.d.ts.map +1 -0
  42. package/dist/utils/family-edit.d.ts +23 -0
  43. package/dist/utils/family-edit.d.ts.map +1 -0
  44. package/dist/utils/gedcom-trailer.d.ts +6 -0
  45. package/dist/utils/gedcom-trailer.d.ts.map +1 -0
  46. package/dist/utils/gedcom-version.d.ts +6 -0
  47. package/dist/utils/gedcom-version.d.ts.map +1 -0
  48. package/dist/utils/gedcom7-dates.d.ts +20 -0
  49. package/dist/utils/gedcom7-dates.d.ts.map +1 -0
  50. package/dist/utils/gedcom7-enumerations.d.ts +26 -0
  51. package/dist/utils/gedcom7-enumerations.d.ts.map +1 -0
  52. package/dist/utils/gedcom7-metadata.d.ts +19 -0
  53. package/dist/utils/gedcom7-metadata.d.ts.map +1 -0
  54. package/dist/utils/gedcom7-schema.d.ts +27 -0
  55. package/dist/utils/gedcom7-schema.d.ts.map +1 -0
  56. package/dist/utils/gedzip.d.ts +81 -0
  57. package/dist/utils/gedzip.d.ts.map +1 -0
  58. package/dist/utils/index.d.ts +13 -1
  59. package/dist/utils/index.d.ts.map +1 -1
  60. package/dist/utils/index.js +2225 -416
  61. package/dist/utils/local-media.d.ts +30 -0
  62. package/dist/utils/local-media.d.ts.map +1 -0
  63. package/dist/utils/media-utils.d.ts +10 -6
  64. package/dist/utils/media-utils.d.ts.map +1 -1
  65. package/dist/utils/multimedia.d.ts +38 -0
  66. package/dist/utils/multimedia.d.ts.map +1 -0
  67. package/dist/utils/parser.d.ts +3 -0
  68. package/dist/utils/parser.d.ts.map +1 -1
  69. package/dist/utils/uid.d.ts +6 -0
  70. package/dist/utils/uid.d.ts.map +1 -0
  71. package/package.json +2 -1
package/dist/cli/index.js CHANGED
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  import { Command } from 'commander';
6
6
  import { debounce, set, get, uniqBy, unset, difference, intersectionBy, differenceBy } from 'lodash-es';
7
7
  import { format, isValid, parse } from 'date-fns';
8
+ import JSZip from 'jszip';
8
9
  import chalk from 'chalk';
9
10
  import * as readline from 'readline';
10
11
 
@@ -15,11 +16,31 @@ var __export = (target, all) => {
15
16
  };
16
17
 
17
18
  // src/constants/constants.ts
18
- var REF_LINE_REG = /^0 (?:(@[_a-zA-Z0-9]*@) )?(?<type>_[_A-Z][_a-zA-Z]{2,}|_?[A-Z][a-zA-Z]{2,}) ?(?<value>.*)/gm;
19
- var LINE_REG = /(?<indent>^[0-9]) (?:(@[_a-zA-Z0-9]*@) )?(?<type>_[_A-Z][_a-zA-Z]{2,}|_?[A-Z][a-zA-Z]{2,}) ?(?<value>.*)/;
19
+ var APP_BRANDING = "TreeViz - The Family Tree Visualiser & Editor";
20
+ var REF_LINE_REG = /^0 (?:(@[_a-zA-Z0-9]*@) )?(?<type>_[_A-Z][_a-zA-Z0-9]{2,}|_?[A-Z][A-Za-z0-9]{2,}) ?(?<value>.*)/gm;
21
+ var LINE_REG = /(?<indent>^[0-9]{1,2}) (?:(@[_a-zA-Z0-9]*@) )?(?<type>_[_A-Z][_a-zA-Z0-9]{2,}|_?[A-Z][A-Za-z0-9]{2,}) ?(?<value>.*)/;
20
22
  var ID_REG = /^@[_a-zA-Z0-9]+@/;
21
23
  var ID_GETTER_REG = /^(?<at>@)?(?<letter>[A-Z])?/i;
24
+ var ORIG_HEAD_TAG = "_ORIGHEAD";
22
25
  var MAX_FILE_SIZE_TO_SYNC = 1024 * 1024 * 20;
26
+
27
+ // src/utils/gedcom-trailer.ts
28
+ var TRAILER_LINE = /^0 TRLR\s*$/i;
29
+ var GEDCOM_TRAILER_TAG = "TRLR";
30
+ var isGedcomTrailerTag = (tag) => tag === GEDCOM_TRAILER_TAG;
31
+ var isGedcomTrailerLine = (line) => TRAILER_LINE.test(line);
32
+ var appendGedcomTrailer = (serialized) => {
33
+ const newline = serialized.includes("\r\n") ? "\r\n" : "\n";
34
+ const trimmed = serialized.replace(/(?:\r?\n)+$/, "");
35
+ if (!trimmed) {
36
+ return "0 TRLR";
37
+ }
38
+ const lastLine = trimmed.split(/\r?\n/).at(-1) ?? "";
39
+ if (isGedcomTrailerLine(lastLine)) {
40
+ return trimmed;
41
+ }
42
+ return `${trimmed}${newline}0 TRLR`;
43
+ };
23
44
  var List = class _List {
24
45
  // length = 0;
25
46
  constructor(items) {
@@ -395,11 +416,17 @@ var List = class _List {
395
416
  const gedcom = [];
396
417
  this.entries().forEach(([_, item]) => {
397
418
  const validTag = getValidTag(tag);
398
- const validKey = item.id;
399
- const validValue = validKey ? validTag : item.exportValue();
400
- gedcom.push(
401
- `${level} ${validKey || validTag}${validValue ? ` ${validValue}` : ""}`
402
- );
419
+ const xref = item.id;
420
+ const payload = item.exportValue?.();
421
+ if (xref) {
422
+ gedcom.push(
423
+ `${level} ${xref} ${validTag}${payload ? ` ${payload}` : ""}`
424
+ );
425
+ } else {
426
+ gedcom.push(
427
+ `${level} ${validTag}${payload ? ` ${payload}` : ""}`
428
+ );
429
+ }
403
430
  gedcom.push(
404
431
  ...item.toGedcomLines(
405
432
  validTag,
@@ -530,6 +557,9 @@ var Common = class _Common {
530
557
  delete this._value;
531
558
  }
532
559
  set(name, value) {
560
+ if (isGedcomTrailerTag(name)) {
561
+ return void 0;
562
+ }
533
563
  if (typeof value === "string") {
534
564
  const usedValue = createCommon(this._gedcom, void 0, this.main);
535
565
  usedValue.value = value;
@@ -540,6 +570,9 @@ var Common = class _Common {
540
570
  return get(this, name);
541
571
  }
542
572
  assign(name, value, unique = false) {
573
+ if (isGedcomTrailerTag(name)) {
574
+ return void 0;
575
+ }
543
576
  let curValue = this.get(name);
544
577
  if (curValue?.isListable) {
545
578
  if (curValue instanceof _Common) {
@@ -651,12 +684,14 @@ var Common = class _Common {
651
684
  );
652
685
  }
653
686
  standardizeObject(tag, options) {
654
- if (tag === "OBJE" && !options?.original && options?.obje?.standardize && options?.obje?.namespace && "standardizeMedia" in this) {
687
+ if (tag === "OBJE" && options?.obje?.standardize && "standardizeMedia" in this) {
655
688
  const standardize = this.standardizeMedia;
656
689
  return standardize.call(
657
690
  this,
658
691
  options.obje.namespace,
659
- options.obje.override
692
+ options.obje.override,
693
+ void 0,
694
+ options.gedcomVersion
660
695
  );
661
696
  }
662
697
  }
@@ -683,7 +718,7 @@ var Common = class _Common {
683
718
  if (typeof prop?.toObject === "function") {
684
719
  if (prop instanceof _Common) {
685
720
  json[validKey] = prop.toObject(validKey, options);
686
- } else {
721
+ } else if (prop instanceof List) {
687
722
  json = {
688
723
  ...json,
689
724
  ...prop.toObject(validKey, options)
@@ -741,8 +776,12 @@ var Common = class _Common {
741
776
  this.standardizeObject(tag, options);
742
777
  const validKeys = getValidKeys(this);
743
778
  const gedcom = [];
779
+ const isGedcom7Export = options?.gedcomVersion === "7.0";
744
780
  validKeys.forEach((key) => {
745
781
  const validKey = key;
782
+ if (isGedcom7Export && validKey === "CONC") {
783
+ return;
784
+ }
746
785
  const prop = this.get(validKey);
747
786
  if (typeof prop?.toGedcomLines === "function") {
748
787
  if (prop instanceof _Common) {
@@ -753,7 +792,7 @@ var Common = class _Common {
753
792
  gedcom.push(
754
793
  ...prop.toGedcomLines(validKey, level + 1, options)
755
794
  );
756
- } else {
795
+ } else if (prop instanceof List) {
757
796
  gedcom.push(
758
797
  ...prop.toGedcomLines(validKey, level, options)
759
798
  );
@@ -762,30 +801,47 @@ var Common = class _Common {
762
801
  });
763
802
  return gedcom;
764
803
  }
804
+ getHeadRecord() {
805
+ return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
806
+ }
807
+ getOriginalHeadRecord() {
808
+ return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
809
+ }
810
+ getSourceHeads() {
811
+ const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
812
+ return heads.filter((head, index) => {
813
+ return Boolean(head && heads.indexOf(head) === index);
814
+ });
815
+ }
816
+ getFromSourceHeads(path) {
817
+ for (const head of this.getSourceHeads()) {
818
+ const value = get(head, path);
819
+ if (value !== void 0 && value !== null && value !== "") {
820
+ return value;
821
+ }
822
+ }
823
+ return void 0;
824
+ }
825
+ sourStartsWith(prefix) {
826
+ return this.getSourceHeads().some((head) => {
827
+ const sour = get(head, "SOUR.value");
828
+ return !!sour?.toLowerCase()?.startsWith(prefix);
829
+ });
830
+ }
765
831
  isGenoPro() {
766
- const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
767
- const sour = get(head, "SOUR.value");
768
- return !!sour?.toLowerCase()?.startsWith("genopro");
832
+ return this.sourStartsWith("genopro");
769
833
  }
770
834
  isAhnenblatt() {
771
- const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
772
- const sour = get(head, "SOUR.value");
773
- return !!sour?.toLowerCase()?.startsWith("ahnenblatt");
835
+ return this.sourStartsWith("ahnenblatt");
774
836
  }
775
837
  isGeni() {
776
- const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
777
- const sour = get(head, "SOUR.value");
778
- return !!sour?.toLowerCase()?.startsWith("geni");
838
+ return this.sourStartsWith("geni");
779
839
  }
780
840
  isAncestry() {
781
- const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
782
- const sour = get(head, "SOUR.value");
783
- return !!sour?.toLowerCase()?.startsWith("ancestry");
841
+ return this.sourStartsWith("ancestry");
784
842
  }
785
843
  isMyHeritage() {
786
- const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
787
- const sour = get(head, "SOUR.value");
788
- return !!sour?.toLowerCase()?.startsWith("myheritage");
844
+ return this.sourStartsWith("myheritage");
789
845
  }
790
846
  /**
791
847
  * Get the source type as a string (for prefixing tree IDs and names)
@@ -802,22 +858,22 @@ var Common = class _Common {
802
858
  return void 0;
803
859
  }
804
860
  isFamilySearch() {
805
- const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
806
- const sourName = get(head, "SOUR.NAME.value");
807
- return sourName === "FamilySearch API";
861
+ return this.getSourceHeads().some((head) => {
862
+ const sourName = get(head, "SOUR.NAME.value");
863
+ return sourName === "FamilySearch API";
864
+ });
808
865
  }
809
866
  isGNO2GED() {
810
- const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
811
- const sour = get(head, "SOUR.value");
812
- return sour === "GNO2GED";
867
+ return this.getSourceHeads().some((head) => {
868
+ const sour = get(head, "SOUR.value");
869
+ return sour === "GNO2GED";
870
+ });
813
871
  }
814
872
  getAncestryTreeId() {
815
- const path = "HEAD.SOUR._TREE.RIN.value";
816
- return get(this, path) || get(this.getGedcom(), path);
873
+ return this.getFromSourceHeads("SOUR._TREE.RIN.value") || (get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value"));
817
874
  }
818
875
  getMyHeritageTreeId() {
819
- const path = "HEAD._EXPORTED_FROM_SITE_ID.value";
820
- return get(this, path) || get(this.getGedcom(), path);
876
+ return this.getFromSourceHeads("_EXPORTED_FROM_SITE_ID.value") || (get(this, "HEAD._EXPORTED_FROM_SITE_ID.value") || get(this.getGedcom(), "HEAD._EXPORTED_FROM_SITE_ID.value"));
821
877
  }
822
878
  getTreeId() {
823
879
  if (this?.isAncestry()) {
@@ -851,8 +907,7 @@ var Common = class _Common {
851
907
  return this.getUniversalTreeId();
852
908
  }
853
909
  getAncestryTreeName() {
854
- const path = "HEAD.SOUR._TREE.value";
855
- return get(this, path) || get(this.getGedcom(), path);
910
+ return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
856
911
  }
857
912
  getMyHeritageTreeName() {
858
913
  const path = "HEAD.FILE.value";
@@ -862,14 +917,14 @@ var Common = class _Common {
862
917
  )?.groups?.tree;
863
918
  }
864
919
  getFamilySearchTreeId() {
865
- const rin = get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
920
+ const rin = this.getFromSourceHeads("SOUR._TREE.RIN.value") || get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
866
921
  if (rin) {
867
922
  return rin;
868
923
  }
869
924
  return "familysearch";
870
925
  }
871
926
  getFamilySearchTreeName() {
872
- const treeName = get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
927
+ const treeName = this.getFromSourceHeads("SOUR._TREE.value") || get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
873
928
  if (treeName) {
874
929
  return treeName;
875
930
  }
@@ -961,11 +1016,11 @@ var Common = class _Common {
961
1016
  const cleanName = fileName.replace(/\.ged$/i, "").replace(/_/g, " ");
962
1017
  return `${prefix}${cleanName}`;
963
1018
  }
964
- const sourName = get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
1019
+ const sourName = this.getFromSourceHeads("SOUR.NAME.value") || get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
965
1020
  if (sourName) {
966
1021
  return `${prefix}${sourName}`;
967
1022
  }
968
- const sourValue = get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
1023
+ const sourValue = this.getFromSourceHeads("SOUR.value") || get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
969
1024
  if (sourValue) {
970
1025
  return `${prefix}${sourValue}`;
971
1026
  }
@@ -1031,7 +1086,7 @@ var isOnlyMainProp = (key) => {
1031
1086
  };
1032
1087
  var isValidKey = (common, key) => {
1033
1088
  const prop = get(common, key);
1034
- return key !== "_gedcom" && key !== "_main" && key !== "_parent" && key !== "_uniqueId" && key !== "_refs" && key !== "_type" && (key === "id" || key === "_id" || key === "value" || key === "_value" || prop instanceof Common || prop instanceof List);
1089
+ return key !== "_gedcom" && key !== "_main" && key !== "_parent" && key !== "_uniqueId" && key !== "_refs" && key !== "_type" && !(typeof key === "string" && isGedcomTrailerTag(key)) && (key === "id" || key === "_id" || key === "value" || key === "_value" || prop instanceof Common || prop instanceof List);
1035
1090
  };
1036
1091
  var getValidKeys = (common) => {
1037
1092
  return Object.keys(common).filter((key) => {
@@ -1066,6 +1121,178 @@ var idGetter = (id) => {
1066
1121
  return newId;
1067
1122
  };
1068
1123
 
1124
+ // src/utils/family-edit.ts
1125
+ var PEDIGREE_VALUES = [
1126
+ "birth" /* BIRTH */,
1127
+ "adopted" /* ADOPTED */,
1128
+ "foster" /* FOSTER */,
1129
+ "step" /* STEP */,
1130
+ "sealing" /* SEALING */
1131
+ ];
1132
+ var toGedcomPedigree = (value) => {
1133
+ const normalized = String(value || "birth" /* BIRTH */).toLowerCase();
1134
+ if (normalized === "biological" /* BIOLOGICAL */ || normalized === "birth" /* BIRTH */) {
1135
+ return "birth" /* BIRTH */;
1136
+ }
1137
+ const match = PEDIGREE_VALUES.find((item) => item === normalized);
1138
+ return match ?? "birth" /* BIRTH */;
1139
+ };
1140
+ var pointerIds = (tag) => {
1141
+ if (!tag) {
1142
+ return [];
1143
+ }
1144
+ if (tag instanceof List) {
1145
+ return tag.values().map((item) => item?.toValue?.()).filter((value2) => !!value2);
1146
+ }
1147
+ const value = tag.toValue?.();
1148
+ return value ? [String(value)] : [];
1149
+ };
1150
+ var firstPointerId = (tag) => pointerIds(tag)[0];
1151
+ var makePointer = (gedcom, parent, value, refType) => {
1152
+ const pointer = createCommon(gedcom, void 0, parent);
1153
+ pointer.value = value;
1154
+ pointer.refType = refType;
1155
+ return pointer;
1156
+ };
1157
+ var nextRecordId = (ids, prefix) => {
1158
+ let max = 0;
1159
+ ids.forEach((id) => {
1160
+ const match = String(id).match(/(\d+)/);
1161
+ const n = match ? Number.parseInt(match[1], 10) : 0;
1162
+ if (n > max) {
1163
+ max = n;
1164
+ }
1165
+ });
1166
+ return `@${prefix}${max + 1}@`;
1167
+ };
1168
+ var familyHasParent = (fam, indiId) => pointerIds(fam.get("HUSB")).includes(indiId) || pointerIds(fam.get("WIFE")).includes(indiId);
1169
+ var familyHasChild = (fam, indiId) => pointerIds(fam.get("CHIL")).includes(indiId);
1170
+ var spouseTagFor = (indi, fam) => {
1171
+ const husbId = firstPointerId(fam.get("HUSB"));
1172
+ const wifeId = firstPointerId(fam.get("WIFE"));
1173
+ if (husbId === indi.id) {
1174
+ return "HUSB";
1175
+ }
1176
+ if (wifeId === indi.id) {
1177
+ return "WIFE";
1178
+ }
1179
+ if (indi.isFemale()) {
1180
+ return wifeId && wifeId !== indi.id ? "HUSB" : "WIFE";
1181
+ }
1182
+ if (indi.isMale()) {
1183
+ return husbId && husbId !== indi.id ? "WIFE" : "HUSB";
1184
+ }
1185
+ return husbId ? "WIFE" : "HUSB";
1186
+ };
1187
+ var canAttachAsSpouse = (fam, indi) => {
1188
+ if (!indi.id) {
1189
+ return false;
1190
+ }
1191
+ if (familyHasParent(fam, indi.id)) {
1192
+ return true;
1193
+ }
1194
+ const tag = spouseTagFor(indi, fam);
1195
+ const occupied = firstPointerId(fam.get(tag));
1196
+ return !occupied || occupied === indi.id;
1197
+ };
1198
+ var pointerByValue = (tag, id) => {
1199
+ if (!tag) {
1200
+ return void 0;
1201
+ }
1202
+ const fromValues = tag.toValueList?.().item(id);
1203
+ if (fromValues) {
1204
+ return fromValues;
1205
+ }
1206
+ return tag.toList()?.values().find((item) => item?.toValue?.() === id);
1207
+ };
1208
+ var setChildPedigree = (fam, child, pedigree, parent) => {
1209
+ if (!fam.id || !child.id) {
1210
+ return;
1211
+ }
1212
+ const pedi = toGedcomPedigree(pedigree);
1213
+ const famc = pointerByValue(child.get("FAMC"), fam.id);
1214
+ if (famc) {
1215
+ famc.set("PEDI", pedi);
1216
+ }
1217
+ const chil = pointerByValue(fam.get("CHIL"), child.id);
1218
+ if (!chil) {
1219
+ return;
1220
+ }
1221
+ const setFather = !parent || parent.isMale() || parent.isUnknownSex();
1222
+ const setMother = !parent || parent.isFemale() || parent.isUnknownSex();
1223
+ if (setFather) {
1224
+ chil.set("_FREL", pedi);
1225
+ }
1226
+ if (setMother) {
1227
+ chil.set("_MREL", pedi);
1228
+ }
1229
+ };
1230
+ var attachSpouseToFamily = (fam, indi) => {
1231
+ const gedcom = fam.getGedcom() ?? indi.getGedcom();
1232
+ if (!indi.id || !fam.id || !gedcom) {
1233
+ return false;
1234
+ }
1235
+ if (!canAttachAsSpouse(fam, indi)) {
1236
+ return false;
1237
+ }
1238
+ const tag = spouseTagFor(indi, fam);
1239
+ if (firstPointerId(fam.get(tag)) !== indi.id) {
1240
+ fam.set(tag, makePointer(gedcom, fam, indi.id, "INDI"));
1241
+ }
1242
+ indi.assign("FAMS", makePointer(gedcom, indi, fam.id, "FAM"), true);
1243
+ return true;
1244
+ };
1245
+ var attachChildToFamily = (fam, child, pedigree, parent) => {
1246
+ const gedcom = fam.getGedcom() ?? child.getGedcom();
1247
+ if (!child.id || !fam.id || !gedcom) {
1248
+ return false;
1249
+ }
1250
+ if (!familyHasChild(fam, child.id)) {
1251
+ fam.assign("CHIL", makePointer(gedcom, fam, child.id, "INDI"), true);
1252
+ }
1253
+ const existingFamc = pointerByValue(child.get("FAMC"), fam.id);
1254
+ if (!existingFamc) {
1255
+ child.assign("FAMC", makePointer(gedcom, child, fam.id, "FAM"), true);
1256
+ }
1257
+ setChildPedigree(fam, child, pedigree, parent);
1258
+ return true;
1259
+ };
1260
+ var findReusableParentChildFamily = (parent, child) => {
1261
+ if (!parent.id || !child.id) {
1262
+ return void 0;
1263
+ }
1264
+ let reusableFamc;
1265
+ let already = false;
1266
+ child.getFamilies("FAMC")?.forEach((fam) => {
1267
+ if (!fam) {
1268
+ return;
1269
+ }
1270
+ if (familyHasParent(fam, parent.id) && familyHasChild(fam, child.id)) {
1271
+ already = true;
1272
+ return;
1273
+ }
1274
+ if (!reusableFamc && canAttachAsSpouse(fam, parent)) {
1275
+ reusableFamc = fam;
1276
+ }
1277
+ });
1278
+ if (already) {
1279
+ return "already";
1280
+ }
1281
+ if (reusableFamc) {
1282
+ return reusableFamc;
1283
+ }
1284
+ const parentFams = [];
1285
+ parent.getFamilies("FAMS")?.forEach((fam) => {
1286
+ if (fam) {
1287
+ parentFams.push(fam);
1288
+ }
1289
+ });
1290
+ if (parentFams.length === 1) {
1291
+ return parentFams[0];
1292
+ }
1293
+ return void 0;
1294
+ };
1295
+
1069
1296
  // src/factories/cache-factory.ts
1070
1297
  var defaultCacheFactory = () => {
1071
1298
  let cache = null;
@@ -1139,131 +1366,322 @@ var PARTNER = {
1139
1366
  var SPOUSE = {
1140
1367
  PART: "spouse" /* SPOUSE */
1141
1368
  };
1142
- var getGedcomId = (gedcom) => {
1143
- if (!gedcom) {
1144
- return "unknown";
1145
- }
1146
- const treeId = gedcom.getTreeId?.() || "";
1147
- const treeName = gedcom.getTreeName?.() || "";
1148
- const sanitizedName = treeName.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
1149
- if (treeId && sanitizedName) {
1150
- return `${treeId}_${sanitizedName}`;
1151
- } else if (treeId) {
1152
- return treeId;
1153
- } else if (sanitizedName) {
1154
- return sanitizedName;
1155
- }
1156
- return `gedcom_${gedcom.refcount}`;
1157
- };
1158
- var caches = {
1159
- pathCache: {},
1160
- relativesOnDegreeCache: {},
1161
- relativesOnLevelCache: {},
1162
- profilePictureCache: {}
1369
+
1370
+ // src/utils/get-family-with.ts
1371
+ var getFamilyWith = (person1, person2, famType = "FAMS") => {
1372
+ return person1?.get(famType)?.toValueList().find((fam) => {
1373
+ const family = fam;
1374
+ return famType === "FAMC" || family?.HUSB?.value === person2 || family?.WIFE?.value === person2;
1375
+ });
1163
1376
  };
1164
- var cacheDbs;
1165
- var getCacheDbs = () => {
1166
- if (!cacheDbs) {
1167
- const getInstance = getCacheManagerFactory();
1168
- cacheDbs = {
1169
- pathCache: getInstance(
1170
- "ftv",
1171
- "Main",
1172
- "path",
1173
- true
1174
- ),
1175
- relativesOnDegreeCache: getInstance("ftv", "Main", "path", true),
1176
- relativesOnLevelCache: getInstance(
1177
- "ftv",
1178
- "Main",
1179
- "path",
1180
- true
1181
- ),
1182
- profilePictureCache: getInstance(
1183
- "ftv",
1184
- "Main",
1185
- "images",
1186
- false
1187
- )
1188
- };
1377
+
1378
+ // src/constants/orders.ts
1379
+ var BIRTH_ASC = {
1380
+ "BIRT.DATE": {
1381
+ direction: "ASC",
1382
+ getter: (value, raw) => {
1383
+ if (isCommonDate(raw) && raw.rawValue) {
1384
+ return raw.rawValue.getTime();
1385
+ }
1386
+ return new Date(value).getTime();
1387
+ }
1189
1388
  }
1190
- return cacheDbs;
1191
1389
  };
1192
- var storeCache = {
1193
- // NOTE: pathCache, relativesOnLevelCache, and relativesOnDegreeCache are intentionally
1194
- // kept in memory only. These debounced functions exist to satisfy the type system
1195
- // but are never called.
1196
- pathCache: debounce((value) => {
1197
- if (value) {
1198
- getCacheDbs().pathCache.setItem(value);
1199
- }
1200
- }, 50),
1201
- relativesOnLevelCache: debounce((value) => {
1202
- if (value) {
1203
- getCacheDbs().relativesOnLevelCache.setItem(value);
1204
- }
1205
- }, 50),
1206
- relativesOnDegreeCache: debounce((value) => {
1207
- if (value) {
1208
- getCacheDbs().relativesOnDegreeCache.setItem(value);
1209
- }
1210
- }, 50),
1211
- // profilePictureCache IS persisted to IndexedDB
1212
- profilePictureCache: debounce((value) => {
1213
- if (value) {
1214
- getCacheDbs().profilePictureCache.setItem(value);
1390
+ var BIRTH_DESC = {
1391
+ "BIRT.DATE": {
1392
+ direction: "DESC",
1393
+ getter: (value, raw) => {
1394
+ if (isCommonDate(raw) && raw.rawValue) {
1395
+ return raw.rawValue.getTime();
1396
+ }
1397
+ return new Date(value).getTime();
1215
1398
  }
1216
- }, 100)
1217
- };
1218
- var relativesCache = (cacheKey) => (gedcom, key, subKey, value) => {
1219
- const gedcomId = getGedcomId(gedcom);
1220
- const fullKey = `${gedcomId}:${key}`;
1221
- const cache = caches[cacheKey];
1222
- if (!cache) {
1223
- caches[cacheKey] = {};
1224
1399
  }
1225
- if (value) {
1226
- const typedCache2 = caches[cacheKey];
1227
- if (!typedCache2[fullKey]) {
1228
- typedCache2[fullKey] = {};
1400
+ };
1401
+ var DEATH_ASC = {
1402
+ "DEAT.DATE": {
1403
+ direction: "ASC",
1404
+ getter: (value, raw) => {
1405
+ if (isCommonDate(raw) && raw.rawValue) {
1406
+ return raw.rawValue.getTime();
1407
+ }
1408
+ return new Date(value).getTime();
1229
1409
  }
1230
- typedCache2[fullKey][subKey] = value;
1231
- return typedCache2[fullKey][subKey];
1232
1410
  }
1233
- const typedCache = caches[cacheKey];
1234
- return typedCache?.[fullKey]?.[subKey];
1235
1411
  };
1236
- var pathCache = (gedcom, key, value) => {
1237
- const gedcomId = getGedcomId(gedcom);
1238
- const fullKey = `${gedcomId}:${key}`;
1239
- if (!caches.pathCache) {
1240
- caches.pathCache = {};
1241
- }
1242
- if (value && caches.pathCache) {
1243
- caches.pathCache[fullKey] = value;
1244
- return caches.pathCache[fullKey];
1412
+ var DEATH_DESC = {
1413
+ "DEAT.DATE": {
1414
+ direction: "DESC",
1415
+ getter: (value, raw) => {
1416
+ if (isCommonDate(raw) && raw.rawValue) {
1417
+ return raw.rawValue.getTime();
1418
+ }
1419
+ return new Date(value).getTime();
1420
+ }
1245
1421
  }
1246
- return caches.pathCache?.[fullKey];
1247
1422
  };
1248
- var profilePictureCache = (gedcom, key, value) => {
1249
- const gedcomId = getGedcomId(gedcom);
1250
- const fullKey = `${gedcomId}:${key}`;
1251
- if (!caches.profilePictureCache) {
1252
- caches.profilePictureCache = {};
1253
- }
1254
- if (value && caches.profilePictureCache) {
1255
- caches.profilePictureCache[fullKey] = value;
1256
- storeCache.profilePictureCache(caches.profilePictureCache);
1257
- return caches.profilePictureCache[fullKey];
1423
+ var DATE_ASC = {
1424
+ DATE: {
1425
+ direction: "ASC",
1426
+ getter: (value, raw) => {
1427
+ if (isCommonDate(raw) && raw.rawValue) {
1428
+ return raw.rawValue.getTime();
1429
+ }
1430
+ return new Date(value).getTime();
1431
+ }
1258
1432
  }
1259
- const cached = caches.profilePictureCache?.[fullKey];
1260
- return cached;
1261
1433
  };
1262
- var isNonBiologicalPath = (path) => path.some(
1263
- (item) => item.relation && item.relation !== "biological" /* BIOLOGICAL */
1264
- );
1265
- var invertHop = (kinship) => {
1266
- if (kinship === "parent") {
1434
+ var chars = [
1435
+ "a",
1436
+ "\xE0",
1437
+ "\xE1",
1438
+ "\xE2",
1439
+ "\xE4",
1440
+ "\xE6",
1441
+ "\xE3",
1442
+ "\xE5",
1443
+ "\u0101",
1444
+ "b",
1445
+ "c",
1446
+ "\xE7",
1447
+ "\u0107",
1448
+ "\u010D",
1449
+ "cs",
1450
+ "d",
1451
+ "dz",
1452
+ "dzs",
1453
+ "e",
1454
+ "\xE8",
1455
+ "\xE9",
1456
+ "\xEA",
1457
+ "\xEB",
1458
+ "\u0113",
1459
+ "\u0117",
1460
+ "\u0119",
1461
+ "f",
1462
+ "g",
1463
+ "gy",
1464
+ "h",
1465
+ "i",
1466
+ "\xEE",
1467
+ "\xEF",
1468
+ "\xED",
1469
+ "\u012B",
1470
+ "\u012F",
1471
+ "\xEC",
1472
+ "j",
1473
+ "k",
1474
+ "l",
1475
+ "\u0142",
1476
+ "ly",
1477
+ "m",
1478
+ "n",
1479
+ "\xF1",
1480
+ "\u0144",
1481
+ "ny",
1482
+ "o",
1483
+ "\xF3",
1484
+ "\xF6",
1485
+ "\u0151",
1486
+ "\xF4",
1487
+ "\xF2",
1488
+ "\xF5",
1489
+ "\u0153",
1490
+ "\xF8",
1491
+ "\u014D",
1492
+ "p",
1493
+ "q",
1494
+ "r",
1495
+ "s",
1496
+ "\u015B",
1497
+ "\u0161",
1498
+ "\xDF",
1499
+ "sz",
1500
+ "t",
1501
+ "ty",
1502
+ "u",
1503
+ "\xFA",
1504
+ "\xFC",
1505
+ "\u0171",
1506
+ "\xFB",
1507
+ "\xF9",
1508
+ "\u016B",
1509
+ "v",
1510
+ "w",
1511
+ "x",
1512
+ "y",
1513
+ "z",
1514
+ "zs"
1515
+ ];
1516
+ chars.reduce((acc, curr, idx) => {
1517
+ acc[curr] = idx;
1518
+ return acc;
1519
+ }, {});
1520
+ var getBirthAsc = (itemA, _keyA, itemB, _keyB) => {
1521
+ const birthA = itemA?.BIRT?.index(0);
1522
+ const birthB = itemB?.BIRT?.index(0);
1523
+ const valueA = birthA?.DATE?.rawValue;
1524
+ const valueB = birthB?.DATE?.rawValue;
1525
+ if (valueA?.getTime() === valueB?.getTime()) {
1526
+ return 0;
1527
+ }
1528
+ if (!valueA || valueB && valueA > valueB) {
1529
+ return 1;
1530
+ }
1531
+ return -1;
1532
+ };
1533
+ var getMarriageAsc = (person, famType = "FAMS") => (itemA, _keyA, itemB, _keyB) => {
1534
+ if (!person && famType === "FAMS") {
1535
+ return 0;
1536
+ }
1537
+ const familyA = getFamilyWith(itemA, person);
1538
+ const familyB = getFamilyWith(itemB, person);
1539
+ const marriageA = familyA?.MARR?.DATE?.rawValue;
1540
+ const marriageB = familyB?.MARR?.DATE?.rawValue;
1541
+ if (marriageA?.getTime() === marriageB?.getTime()) {
1542
+ return 0;
1543
+ }
1544
+ if (!marriageA || marriageB && marriageA > marriageB) {
1545
+ return 1;
1546
+ }
1547
+ return -1;
1548
+ };
1549
+ var getMarriageAscAndChildBirth = (person) => (itemA, keyA, itemB, keyB) => {
1550
+ const marriageSort = getMarriageAsc(person)(itemA, keyA, itemB, keyB);
1551
+ if (marriageSort !== 0) {
1552
+ return marriageSort;
1553
+ }
1554
+ const familyA = getFamilyWith(itemA, person);
1555
+ const familyB = getFamilyWith(itemB, person);
1556
+ const childA = familyA?.getChildren().orderBy(BIRTH_ASC).index(0);
1557
+ const childB = familyB?.getChildren().orderBy(BIRTH_ASC).index(0);
1558
+ return getBirthAsc(childA, keyA, childB);
1559
+ };
1560
+ var getGedcomId = (gedcom) => {
1561
+ if (!gedcom) {
1562
+ return "unknown";
1563
+ }
1564
+ const treeId = gedcom.getTreeId?.() || "";
1565
+ const treeName = gedcom.getTreeName?.() || "";
1566
+ const sanitizedName = treeName.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
1567
+ if (treeId && sanitizedName) {
1568
+ return `${treeId}_${sanitizedName}`;
1569
+ } else if (treeId) {
1570
+ return treeId;
1571
+ } else if (sanitizedName) {
1572
+ return sanitizedName;
1573
+ }
1574
+ return `gedcom_${gedcom.refcount}`;
1575
+ };
1576
+ var caches = {
1577
+ pathCache: {},
1578
+ relativesOnDegreeCache: {},
1579
+ relativesOnLevelCache: {},
1580
+ profilePictureCache: {}
1581
+ };
1582
+ var cacheDbs;
1583
+ var getCacheDbs = () => {
1584
+ if (!cacheDbs) {
1585
+ const getInstance = getCacheManagerFactory();
1586
+ cacheDbs = {
1587
+ pathCache: getInstance(
1588
+ "ftv",
1589
+ "Main",
1590
+ "path",
1591
+ true
1592
+ ),
1593
+ relativesOnDegreeCache: getInstance("ftv", "Main", "path", true),
1594
+ relativesOnLevelCache: getInstance(
1595
+ "ftv",
1596
+ "Main",
1597
+ "path",
1598
+ true
1599
+ ),
1600
+ profilePictureCache: getInstance(
1601
+ "ftv",
1602
+ "Main",
1603
+ "images",
1604
+ false
1605
+ )
1606
+ };
1607
+ }
1608
+ return cacheDbs;
1609
+ };
1610
+ var storeCache = {
1611
+ // NOTE: pathCache, relativesOnLevelCache, and relativesOnDegreeCache are intentionally
1612
+ // kept in memory only. These debounced functions exist to satisfy the type system
1613
+ // but are never called.
1614
+ pathCache: debounce((value) => {
1615
+ if (value) {
1616
+ getCacheDbs().pathCache.setItem(value);
1617
+ }
1618
+ }, 50),
1619
+ relativesOnLevelCache: debounce((value) => {
1620
+ if (value) {
1621
+ getCacheDbs().relativesOnLevelCache.setItem(value);
1622
+ }
1623
+ }, 50),
1624
+ relativesOnDegreeCache: debounce((value) => {
1625
+ if (value) {
1626
+ getCacheDbs().relativesOnDegreeCache.setItem(value);
1627
+ }
1628
+ }, 50),
1629
+ // profilePictureCache IS persisted to IndexedDB
1630
+ profilePictureCache: debounce((value) => {
1631
+ if (value) {
1632
+ getCacheDbs().profilePictureCache.setItem(value);
1633
+ }
1634
+ }, 100)
1635
+ };
1636
+ var relativesCache = (cacheKey) => (gedcom, key, subKey, value) => {
1637
+ const gedcomId = getGedcomId(gedcom);
1638
+ const fullKey = `${gedcomId}:${key}`;
1639
+ const cache = caches[cacheKey];
1640
+ if (!cache) {
1641
+ caches[cacheKey] = {};
1642
+ }
1643
+ if (value) {
1644
+ const typedCache2 = caches[cacheKey];
1645
+ if (!typedCache2[fullKey]) {
1646
+ typedCache2[fullKey] = {};
1647
+ }
1648
+ typedCache2[fullKey][subKey] = value;
1649
+ return typedCache2[fullKey][subKey];
1650
+ }
1651
+ const typedCache = caches[cacheKey];
1652
+ return typedCache?.[fullKey]?.[subKey];
1653
+ };
1654
+ var pathCache = (gedcom, key, value) => {
1655
+ const gedcomId = getGedcomId(gedcom);
1656
+ const fullKey = `${gedcomId}:${key}`;
1657
+ if (!caches.pathCache) {
1658
+ caches.pathCache = {};
1659
+ }
1660
+ if (value && caches.pathCache) {
1661
+ caches.pathCache[fullKey] = value;
1662
+ return caches.pathCache[fullKey];
1663
+ }
1664
+ return caches.pathCache?.[fullKey];
1665
+ };
1666
+ var profilePictureCache = (gedcom, key, value) => {
1667
+ const gedcomId = getGedcomId(gedcom);
1668
+ const fullKey = `${gedcomId}:${key}`;
1669
+ if (!caches.profilePictureCache) {
1670
+ caches.profilePictureCache = {};
1671
+ }
1672
+ if (value && caches.profilePictureCache) {
1673
+ caches.profilePictureCache[fullKey] = value;
1674
+ storeCache.profilePictureCache(caches.profilePictureCache);
1675
+ return caches.profilePictureCache[fullKey];
1676
+ }
1677
+ const cached = caches.profilePictureCache?.[fullKey];
1678
+ return cached;
1679
+ };
1680
+ var isNonBiologicalPath = (path) => path.some(
1681
+ (item) => item.relation && item.relation !== "biological" /* BIOLOGICAL */
1682
+ );
1683
+ var invertHop = (kinship) => {
1684
+ if (kinship === "parent") {
1267
1685
  return "child";
1268
1686
  }
1269
1687
  if (kinship === "child") {
@@ -1649,16 +2067,58 @@ var getPlaces = (common, type = ["ALL" /* All */], maxLevel = 1, level = 0, main
1649
2067
  });
1650
2068
  return places;
1651
2069
  };
1652
- var implemented = (type, ...args) => {
1653
- };
1654
2070
 
1655
- // src/utils/media-utils.ts
1656
- var getFileExtension = (filename) => {
1657
- const match = filename.match(/\.([^.]+)$/);
1658
- return match ? match[1] : "";
1659
- };
2071
+ // src/utils/local-media.ts
2072
+ var localMediaResolver;
2073
+ var isRemoteOrEmbeddedMediaUrl = (path) => {
2074
+ if (!path) {
2075
+ return false;
2076
+ }
2077
+ return path.startsWith("data:") || path.startsWith("blob:") || /^https?:\/\//i.test(path);
2078
+ };
2079
+ var resolveLocalMediaUrl = async (path) => {
2080
+ if (!path) {
2081
+ return void 0;
2082
+ }
2083
+ if (isRemoteOrEmbeddedMediaUrl(path)) {
2084
+ return path;
2085
+ }
2086
+ const resolved = await localMediaResolver?.(path);
2087
+ return resolved;
2088
+ };
2089
+ var implemented = (type, ...args) => {
2090
+ };
2091
+
2092
+ // src/utils/media-utils.ts
2093
+ var getFileExtension = (filename) => {
2094
+ if (!filename) {
2095
+ return "";
2096
+ }
2097
+ if (filename.startsWith("data:")) {
2098
+ const mime = filename.slice(5).split(";")[0] || "";
2099
+ const subtype = (mime.split("/")[1] || "").toLowerCase();
2100
+ if (subtype === "jpeg") {
2101
+ return "jpg";
2102
+ }
2103
+ return subtype.split("+")[0] || "";
2104
+ }
2105
+ const withoutQuery = filename.split(/[?#]/)[0] || filename;
2106
+ const match = withoutQuery.match(/\.([^.]+)$/);
2107
+ return match ? match[1].toLowerCase() : "";
2108
+ };
1660
2109
  var isImageFormat = (format2) => {
1661
- if (!format2) return false;
2110
+ if (!format2) {
2111
+ return false;
2112
+ }
2113
+ let normalized = format2.toLowerCase().trim();
2114
+ if (normalized.startsWith("data:")) {
2115
+ normalized = getFileExtension(normalized);
2116
+ } else if (normalized.includes("/")) {
2117
+ normalized = normalized.split("/")[1]?.split("+")[0] || "";
2118
+ if (normalized === "jpeg") {
2119
+ normalized = "jpg";
2120
+ }
2121
+ }
1662
2122
  const imageFormats = [
1663
2123
  "jpg",
1664
2124
  "jpeg",
@@ -1670,178 +2130,731 @@ var isImageFormat = (format2) => {
1670
2130
  "tiff",
1671
2131
  "tif"
1672
2132
  ];
1673
- return imageFormats.includes(format2.toLowerCase());
2133
+ return imageFormats.includes(normalized);
1674
2134
  };
1675
-
1676
- // src/classes/name.ts
1677
- var CommonName = class extends Common {
1678
- constructor(gedcom, id, main, parent) {
1679
- super(gedcom, id, main, parent);
1680
- delete this.id;
1681
- }
1682
- set value(value) {
1683
- if (value && this._main instanceof Indi) {
1684
- const nameParts = value.match(
1685
- /(?<givenname>[^/]*)(\/(?<surname>[^/]*)\/)?(?<suffix>.*)$/
1686
- )?.groups;
1687
- if (nameParts?.givenname?.trim()) {
1688
- this.GIVN = this.GIVN || createCommon(this._gedcom, void 0, this.main);
1689
- this.GIVN.isListable = false;
1690
- this.GIVN.value = nameParts.givenname.trim();
1691
- }
1692
- if (nameParts?.surname?.trim()) {
1693
- this.SURN = this.SURN || createCommon(this._gedcom, void 0, this.main);
1694
- this.SURN.value = nameParts.surname.trim();
1695
- this.SURN.isListable = false;
1696
- }
1697
- if (nameParts?.suffix?.trim()) {
1698
- this.NSFX = this.NSFX || createCommon(this._gedcom, void 0, this.main);
1699
- this.NSFX.value = nameParts.suffix.trim();
1700
- this.NSFX.isListable = false;
2135
+ var resolveObjeForm = (obje) => {
2136
+ const value = obje?.get?.("FILE.FORM")?.toValue?.() ?? obje?.get?.("FORM")?.toValue?.();
2137
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2138
+ };
2139
+ var uniqueItemsCache = /* @__PURE__ */ new WeakMap();
2140
+ var setNestedGroup = (obj, key, value, uniqueCounting = true) => {
2141
+ const parts = Array.isArray(key) ? key : key.split(/,\s*/);
2142
+ set(obj, [...parts, "items"], value);
2143
+ parts.forEach((_, index) => {
2144
+ if (!uniqueCounting) {
2145
+ const key2 = [...parts.toSpliced(index + 1), "length"];
2146
+ const length = get(obj, key2);
2147
+ set(obj, key2, (length ?? 0) + value.length);
2148
+ return;
2149
+ }
2150
+ const pathKey = [...parts.toSpliced(index + 1)];
2151
+ const node = get(obj, pathKey);
2152
+ if (node) {
2153
+ let uniqueItems = uniqueItemsCache.get(node);
2154
+ if (!uniqueItems) {
2155
+ uniqueItems = new Individuals();
2156
+ uniqueItemsCache.set(node, uniqueItems);
1701
2157
  }
2158
+ uniqueItems.merge(value);
2159
+ set(obj, [...pathKey, "length"], uniqueItems.length);
1702
2160
  }
1703
- this._value = value;
2161
+ });
2162
+ };
2163
+
2164
+ // src/utils/place-parser.ts
2165
+ var getPlaceParts = (place = []) => {
2166
+ const partsString = Array.isArray(place) ? place.filter(Boolean).join(", ") : place;
2167
+ if (!partsString) {
2168
+ return [{}];
1704
2169
  }
1705
- get value() {
1706
- if (this._value === void 0 && this.DISPLAY?.value) {
1707
- return this.DISPLAY?.value;
1708
- }
1709
- return this._value;
2170
+ const parts = partsString.split(/,\s*/).map((p) => p.trim()).filter(Boolean);
2171
+ if (parts.length === 0) {
2172
+ return [{}];
1710
2173
  }
1711
- name(value) {
1712
- this.value = value;
1713
- return this;
2174
+ const result = {};
2175
+ if (parts.length === 1) {
2176
+ result.town = parts[0];
2177
+ } else if (parts.length === 2) {
2178
+ result.town = parts[0];
2179
+ result.country = parts[1];
2180
+ } else if (parts.length === 3) {
2181
+ result.town = parts[0];
2182
+ result.county = parts[1];
2183
+ result.country = parts[2];
2184
+ } else {
2185
+ result.leftParts = parts.slice(0, parts.length - 3);
2186
+ result.town = parts[parts.length - 3];
2187
+ result.county = parts[parts.length - 2];
2188
+ result.country = parts[parts.length - 1];
1714
2189
  }
2190
+ return [result];
1715
2191
  };
1716
- var createCommonName = (gedcom, id, main, parent) => {
1717
- return createProxy(
1718
- new CommonName(gedcom, id, main, parent)
1719
- );
2192
+
2193
+ // src/utils/place-translator.ts
2194
+ var placeTranslator = (place) => {
2195
+ return Array.isArray(place) ? place.join(", ") : place;
1720
2196
  };
1721
2197
 
1722
- // src/classes/indi.ts
1723
- var ALLOWED_FACTS = [
1724
- "EVEN",
1725
- "OCCU",
1726
- "OCCUPATIONS",
1727
- "RESI",
1728
- "BAPT",
1729
- "CHRI",
1730
- "CHR",
1731
- "BURI",
1732
- "EDUC",
1733
- "GRAD",
1734
- "DIV",
1735
- "IMMI",
1736
- "RELI",
1737
- "_MILT",
1738
- "_MILTID",
1739
- "FACT",
1740
- "_ORIG"
1741
- ];
1742
- var DISALLOWED_CUSTOM_FACTS = ["DNA Test", "Newspaper"];
1743
- var CustomFactRenderers = {
1744
- AKA: (label, fact, indi) => {
1745
- const originalNameObj = indi?.NAME;
1746
- const note = fact.get("NOTE");
1747
- const factName = note?.toValue();
1748
- const name = createCommonName(fact.getGedcom(), void 0, indi);
1749
- const suffix = originalNameObj?.NSFX?.toValue();
1750
- const surname = originalNameObj?.SURN?.toValue();
1751
- const givenname = originalNameObj?.GIVN?.toValue();
1752
- const nameParts = [
1753
- ...givenname?.split(" ").map((s) => ({ name: s, givenname: true })) ?? [],
1754
- ...surname?.split(" ").map((s) => ({ name: s, surname: true })) ?? [],
1755
- ...suffix?.split(" ").map((s) => ({ name: s, suffix: true })) ?? []
1756
- ].filter(Boolean);
1757
- const factParts = factName?.split(" ");
1758
- if (nameParts.length === factParts?.length && !(note instanceof CommonName)) {
1759
- const guessedSuffix = [];
1760
- const guessedSurname = [];
1761
- const guessedGivenname = [];
1762
- factParts.forEach((f, i) => {
1763
- const namePart = nameParts[i];
1764
- if (!f) {
1765
- return;
1766
- }
1767
- if (namePart.suffix) {
1768
- guessedSuffix.push(f);
1769
- } else if (namePart.givenname) {
1770
- guessedGivenname.push(f);
1771
- } else if (namePart.surname) {
1772
- guessedSurname.push(f);
1773
- }
1774
- });
1775
- const allNamePart = [];
1776
- if (guessedGivenname.length) {
1777
- allNamePart.push(guessedGivenname.join(" "));
1778
- }
1779
- if (guessedSurname.length) {
1780
- allNamePart.push(`/${guessedSurname.join(" ")}/`);
1781
- }
1782
- if (guessedSuffix.length) {
1783
- allNamePart.push(guessedSuffix.join(" "));
1784
- }
1785
- name.value = allNamePart.join(" ");
1786
- } else {
1787
- name.value = factName;
1788
- }
1789
- fact.set("NOTE", name);
1790
- label.value = "AKA";
1791
- fact.set("_LABEL", label);
2198
+ // src/classes/indis.ts
2199
+ var Individuals = class _Individuals extends List {
2200
+ copy() {
2201
+ return super.copy(_Individuals);
1792
2202
  }
1793
- };
1794
- var relativesOnLevelCache = relativesCache("relativesOnLevelCache");
1795
- var relativesOnDegreeCache = relativesCache("relativesOnDegreeCache");
1796
- var Indi = class extends Common {
1797
- toName() {
1798
- return this.get("NAME")?.toValue();
2203
+ except(item) {
2204
+ return super.except(item, _Individuals);
1799
2205
  }
1800
- toNaturalName() {
1801
- return this.get("NAME")?.toValue()?.replaceAll("/", "");
2206
+ filter(filters) {
2207
+ return super.filter(filters, _Individuals);
1802
2208
  }
1803
- toList() {
1804
- return new Individuals().concat(
1805
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1806
- this.id ? { [this.id]: this } : { ...[this] }
1807
- );
2209
+ find(filters) {
2210
+ return super.find(filters, _Individuals);
1808
2211
  }
1809
- generateTree(props) {
1810
- const {
1811
- generations,
1812
- level,
1813
- index,
1814
- showDescendants,
1815
- offspringSpouses,
1816
- ancestorSpouses,
1817
- onlyDescendants,
1818
- maxLevel,
1819
- minLevel,
1820
- drawNonBiologicalAncestors,
1821
- ancestorSiblings
1822
- } = props;
1823
- if (!this.id) {
1824
- throw new Error("Indi must have an id");
2212
+ unattachedFilter(useUnattached) {
2213
+ if (useUnattached) {
2214
+ return this;
1825
2215
  }
1826
- const isMainDescendantLevel = showDescendants && level <= 1;
1827
- const isDescendantLevel = showDescendants && level < 1;
1828
- if (level < 1 && !isDescendantLevel) {
1829
- throw new Error("Arguments 2 must be greater than 0.");
2216
+ return this.filter((item) => !item.isUnattachedMember());
2217
+ }
2218
+ orderBy(orders) {
2219
+ return super.orderBy(orders, _Individuals);
2220
+ }
2221
+ getFirstEvent() {
2222
+ const firstBirthPerson = this.getFirstBirth();
2223
+ const firstDeathPerson = this.getFirstDeath();
2224
+ const firstBirth = firstBirthPerson?.BIRT?.index(0);
2225
+ const firstDeath = firstDeathPerson?.DEAT?.index(0);
2226
+ if (!firstBirth?.DATE?.rawValue && !firstDeath?.DATE?.rawValue) {
2227
+ return void 0;
1830
2228
  }
1831
- if (maxLevel !== void 0 && maxLevel < level || minLevel !== void 0 && minLevel > level) {
1832
- return this;
2229
+ if (!firstBirth?.DATE?.rawValue) {
2230
+ return firstDeathPerson;
1833
2231
  }
1834
- const gens = generations ?? {
1835
- existed: {},
1836
- tree: {},
1837
- halves: {},
1838
- lastItems: {}
1839
- };
1840
- const families = this.getFamiliesBiologicalFirst("FAMC");
1841
- const familiesAllMember = families.getParents();
1842
- families.forEach((fam, famKey, famIndex) => {
1843
- if (!this.id) {
1844
- return;
2232
+ if (!firstDeath?.DATE?.rawValue) {
2233
+ return firstBirthPerson;
2234
+ }
2235
+ if (firstDeath.DATE.rawValue < firstBirth.DATE.rawValue) {
2236
+ return firstDeathPerson;
2237
+ }
2238
+ return firstBirthPerson;
2239
+ }
2240
+ getLastEvent() {
2241
+ const lastDeathPerson = this.getLastDeath();
2242
+ const lastBirthPerson = this.getLastBirth();
2243
+ const lastBirth = lastBirthPerson?.BIRT?.index(0);
2244
+ const lastDeath = lastDeathPerson?.DEAT?.index(0);
2245
+ if (!lastBirth?.DATE?.rawValue && !lastDeath?.DATE?.rawValue) {
2246
+ return void 0;
2247
+ }
2248
+ if (!lastDeath?.DATE?.rawValue) {
2249
+ return lastBirthPerson;
2250
+ }
2251
+ if (!lastBirth?.DATE?.rawValue) {
2252
+ return lastDeathPerson;
2253
+ }
2254
+ if (lastDeath.DATE.rawValue < lastBirth.DATE.rawValue) {
2255
+ return lastBirthPerson;
2256
+ }
2257
+ return lastDeathPerson;
2258
+ }
2259
+ getFirstBirth() {
2260
+ return this.filter((item) => {
2261
+ const birth = item.BIRT?.index(0);
2262
+ if (birth?.DATE?.rawValue?.getTime() === 0) {
2263
+ return true;
2264
+ }
2265
+ return !!birth?.DATE?.rawValue?.getTime();
2266
+ }).orderBy(BIRTH_ASC).index(0);
2267
+ }
2268
+ getLastBirth() {
2269
+ return this.filter((item) => {
2270
+ const birth = item.BIRT?.index(0);
2271
+ if (birth?.DATE?.rawValue?.getTime() === 0) {
2272
+ return true;
2273
+ }
2274
+ return !!birth?.DATE?.rawValue?.getTime();
2275
+ }).orderBy(BIRTH_DESC).index(0);
2276
+ }
2277
+ getFirstDeath() {
2278
+ return this.filter((item) => {
2279
+ const death = item.DEAT?.index(0);
2280
+ if (death?.DATE?.rawValue?.getTime() === 0) {
2281
+ return true;
2282
+ }
2283
+ return !!death?.DATE?.rawValue?.getTime();
2284
+ }).orderBy(DEATH_ASC).index(0);
2285
+ }
2286
+ getLastDeath() {
2287
+ return this.filter((item) => {
2288
+ const death = item.DEAT?.index(0);
2289
+ if (death?.DATE?.rawValue?.getTime() === 0) {
2290
+ return true;
2291
+ }
2292
+ return !!death?.DATE?.rawValue?.getTime();
2293
+ }).orderBy(DEATH_DESC).index(0);
2294
+ }
2295
+ groupBy(group, sort, minOccurance = -1, lessOccuranceLabel) {
2296
+ return super.groupBy(
2297
+ group,
2298
+ sort,
2299
+ minOccurance,
2300
+ lessOccuranceLabel,
2301
+ _Individuals
2302
+ );
2303
+ }
2304
+ groupByFirstLetters(sort = "group", minOccurance = -1, settings) {
2305
+ return this.groupBy(
2306
+ (item) => {
2307
+ const { letter } = nameFormatter(item, settings);
2308
+ return letter.trim() || "Unknown";
2309
+ },
2310
+ sort,
2311
+ minOccurance,
2312
+ "Letters appearing less than 5 times"
2313
+ );
2314
+ }
2315
+ groupBySurnames(sort, minOccurance = -1) {
2316
+ return this.groupBy(
2317
+ "NAME.SURN",
2318
+ sort,
2319
+ minOccurance,
2320
+ "Surnames appearing less than 5 times"
2321
+ );
2322
+ }
2323
+ groupByTimeRanges(range, sort = "group", minOccurance = -1) {
2324
+ return this.groupBy(
2325
+ {
2326
+ ["BIRT.DATE.YEAR"]: {
2327
+ getter: (year) => {
2328
+ if (!Number(year)) {
2329
+ return;
2330
+ }
2331
+ if (range === 1 /* Year */) {
2332
+ return `${Math.floor(Number(year) / range) * range}`;
2333
+ }
2334
+ return `${Math.floor(Number(year) / range) * range + 1}-${Math.ceil((Number(year) + 1) / range) * range}`;
2335
+ }
2336
+ }
2337
+ },
2338
+ sort,
2339
+ minOccurance,
2340
+ "Time ranges appearing less than 5 times"
2341
+ );
2342
+ }
2343
+ nestedGroupByPlacesAndTimeRanges(sort, minOccurance = -1, uniqueCounting = true) {
2344
+ const placesWithYear = this.groupBy(
2345
+ (item) => item.getPlaces().map((place) => {
2346
+ const date = place.obj?.get("DATE");
2347
+ if (date?.YEAR) {
2348
+ return `${place.place}, ${date.YEAR}`;
2349
+ }
2350
+ return `${place.place}, Unknown`;
2351
+ }).filter(Boolean),
2352
+ sort,
2353
+ minOccurance,
2354
+ "Places appearing less than 5 times"
2355
+ );
2356
+ return Object.entries(placesWithYear).reduce(
2357
+ (acc, [place, indis]) => {
2358
+ setNestedGroup(acc, place, indis, uniqueCounting);
2359
+ return acc;
2360
+ },
2361
+ {}
2362
+ );
2363
+ }
2364
+ nestedGroupByTimeRangesAndPlaces(sort, minOccurance = -1, uniqueCounting = true) {
2365
+ const placesWithYear = this.groupBy(
2366
+ (item) => item.getPlaces().map((place) => {
2367
+ const date = place.obj?.get("DATE");
2368
+ if (date?.YEAR) {
2369
+ return `${date.YEAR}, ${place.place}`;
2370
+ }
2371
+ return `Unknown, ${place.place}`;
2372
+ }).filter(Boolean),
2373
+ sort,
2374
+ minOccurance,
2375
+ "Places appearing less than 5 times"
2376
+ );
2377
+ return Object.entries(placesWithYear).reduce(
2378
+ (acc, [place, indis]) => {
2379
+ setNestedGroup(acc, place, indis, uniqueCounting);
2380
+ return acc;
2381
+ },
2382
+ {}
2383
+ );
2384
+ }
2385
+ nestedGroupByPlaces(sort, minOccurance = -1, partOrder = "reverse", translate = true, uniqueCounting = true, groupKeyTranslator) {
2386
+ const places = this.groupByPlaces(
2387
+ sort,
2388
+ minOccurance,
2389
+ partOrder,
2390
+ translate,
2391
+ groupKeyTranslator
2392
+ );
2393
+ return Object.entries(places).reduce(
2394
+ (acc, [place, indis]) => {
2395
+ setNestedGroup(acc, place, indis, uniqueCounting);
2396
+ return acc;
2397
+ },
2398
+ {}
2399
+ );
2400
+ }
2401
+ groupByPlaces(sort, minOccurance = -1, partOrder = "reverse", translate = true, groupKeyTranslator) {
2402
+ return this.groupBy(
2403
+ (item) => item.getPlaces().map((place) => {
2404
+ const placeParts = getPlaceParts(place.place || "");
2405
+ const {
2406
+ leftParts = [],
2407
+ town,
2408
+ county,
2409
+ country
2410
+ } = placeParts[0] || {};
2411
+ const normalizedParts = [
2412
+ ...leftParts,
2413
+ town,
2414
+ county,
2415
+ country
2416
+ ].filter(Boolean);
2417
+ const orderedParts = partOrder === "original" ? normalizedParts : normalizedParts.toReversed();
2418
+ let newPlace = "";
2419
+ if (groupKeyTranslator) {
2420
+ newPlace = groupKeyTranslator(orderedParts);
2421
+ } else if (translate) {
2422
+ {
2423
+ newPlace = placeTranslator(orderedParts);
2424
+ }
2425
+ } else {
2426
+ newPlace = orderedParts.join(", ");
2427
+ }
2428
+ if (!newPlace) {
2429
+ return void 0;
2430
+ }
2431
+ return {
2432
+ marker: place.place,
2433
+ group: newPlace
2434
+ };
2435
+ }).filter(Boolean),
2436
+ sort,
2437
+ minOccurance,
2438
+ "Places appearing less than 5 times"
2439
+ );
2440
+ }
2441
+ getFacts() {
2442
+ const facts = new List();
2443
+ this.values().forEach((indi) => {
2444
+ const indiFacts = indi?.getFacts();
2445
+ if (indi?.id && indiFacts) {
2446
+ facts.merge(indiFacts);
2447
+ }
2448
+ });
2449
+ return facts;
2450
+ }
2451
+ isRelativeOf(type, indi, every = false) {
2452
+ const usedIndi = typeof indi === "string" ? this.index(0)?.getGedcom()?.indi(indi) : indi;
2453
+ let getter;
2454
+ if (type === "sibling") {
2455
+ getter = "getSiblings";
2456
+ }
2457
+ if (type === "parent") {
2458
+ getter = "getParents";
2459
+ }
2460
+ if (type === "child") {
2461
+ getter = "getChildren";
2462
+ }
2463
+ if (type === "spouse") {
2464
+ getter = "getCoParents";
2465
+ }
2466
+ if (type === "parentInLaw") {
2467
+ getter = "getParentsInLaw";
2468
+ }
2469
+ if (type === "childInLaw") {
2470
+ getter = "getChildrenInLaw";
2471
+ }
2472
+ if (!usedIndi || !getter) {
2473
+ return false;
2474
+ }
2475
+ const relatives = usedIndi[getter]();
2476
+ const thisIds = this.keys();
2477
+ if (relatives.length <= 0 || this.length <= 0) {
2478
+ return false;
2479
+ }
2480
+ const filtered = relatives.filter({ id: thisIds });
2481
+ if (every) {
2482
+ return filtered.length === this.length ? filtered.index(0)?.id || true : false;
2483
+ }
2484
+ return filtered.length > 0 ? filtered.index(0)?.id || true : false;
2485
+ }
2486
+ isSiblingOf(indi, every = false) {
2487
+ return this.isRelativeOf("sibling", indi, every);
2488
+ }
2489
+ isSpouseOf(indi, every = false) {
2490
+ return this.isRelativeOf("spouse", indi, every);
2491
+ }
2492
+ isParentOf(indi, every = false) {
2493
+ return this.isRelativeOf("parent", indi, every);
2494
+ }
2495
+ isChildOf(indi, every = false) {
2496
+ return this.isRelativeOf("child", indi, every);
2497
+ }
2498
+ isParentInLawOf(indi, every = false) {
2499
+ return this.isRelativeOf("parentInLaw", indi, every);
2500
+ }
2501
+ isChildInLawOf(indi, every = false) {
2502
+ return this.isRelativeOf("childInLaw", indi, every);
2503
+ }
2504
+ splitByFamily(type, relativeTo) {
2505
+ const splittedList = {};
2506
+ const familiesRelativeTo = relativeTo?.get(type !== "Parents" ? "FAMS" : "FAMC")?.toValueList().keys() ?? [];
2507
+ let lengthOfIndividuals = 0;
2508
+ this.forEach((indi) => {
2509
+ const families = indi.get(type === "Spouses" ? "FAMS" : "FAMC")?.toValueList();
2510
+ if (families) {
2511
+ families.keys().forEach((fKey) => {
2512
+ const famKey = fKey;
2513
+ if (familiesRelativeTo && !familiesRelativeTo.includes(famKey)) {
2514
+ return;
2515
+ }
2516
+ if (!splittedList[famKey]) {
2517
+ splittedList[famKey] = new _Individuals();
2518
+ }
2519
+ splittedList[famKey]?.append(indi);
2520
+ lengthOfIndividuals++;
2521
+ });
2522
+ }
2523
+ });
2524
+ if (type === "Spouses" && relativeTo) {
2525
+ const missingFams = difference(
2526
+ familiesRelativeTo,
2527
+ Object.keys(splittedList)
2528
+ );
2529
+ if (missingFams.length) {
2530
+ missingFams.forEach((fKey) => {
2531
+ const famKey = fKey;
2532
+ if (familiesRelativeTo && !familiesRelativeTo.includes(famKey)) {
2533
+ return;
2534
+ }
2535
+ const missingChildren = relativeTo.getGedcom()?.fam(famKey)?.getChildren();
2536
+ if (!splittedList[famKey] && missingChildren?.length) {
2537
+ splittedList[famKey] = new _Individuals();
2538
+ }
2539
+ });
2540
+ }
2541
+ }
2542
+ return {
2543
+ items: splittedList,
2544
+ lengthOfFamily: Object.keys(splittedList).length,
2545
+ lengthOfIndividuals
2546
+ };
2547
+ }
2548
+ getRelativesOnDegree(degree = 0) {
2549
+ const persons = new _Individuals();
2550
+ this.values().forEach((indi) => {
2551
+ if (indi) {
2552
+ persons.merge(indi.getRelativesOnLevel(degree));
2553
+ }
2554
+ });
2555
+ return persons;
2556
+ }
2557
+ getRelativesOnLevel(level = 0, filter) {
2558
+ const persons = new _Individuals();
2559
+ this.values().forEach((indi) => {
2560
+ if (indi) {
2561
+ persons.merge(indi.getRelativesOnLevel(level, filter));
2562
+ }
2563
+ });
2564
+ return persons;
2565
+ }
2566
+ getAscendants(level = 0, filter) {
2567
+ const persons = new _Individuals();
2568
+ this.values().forEach((indi) => {
2569
+ if (indi) {
2570
+ persons.merge(indi.getAscendants(level, filter));
2571
+ }
2572
+ });
2573
+ return persons;
2574
+ }
2575
+ getDescendants(level = 0, filter) {
2576
+ const persons = new _Individuals();
2577
+ this.values().forEach((indi) => {
2578
+ if (indi) {
2579
+ persons.merge(indi.getDescendants(level, filter));
2580
+ }
2581
+ });
2582
+ return persons;
2583
+ }
2584
+ getAllAscendants(individuals) {
2585
+ const persons = new _Individuals();
2586
+ this.values().forEach((indi) => {
2587
+ if (indi) {
2588
+ persons.merge(indi.getAllAscendants(individuals));
2589
+ }
2590
+ });
2591
+ return persons;
2592
+ }
2593
+ getAllDescendants(individuals, containDescendantsInLaw = false) {
2594
+ const persons = new _Individuals();
2595
+ this.values().forEach((indi) => {
2596
+ if (indi) {
2597
+ persons.merge(
2598
+ indi.getAllDescendants(individuals, containDescendantsInLaw)
2599
+ );
2600
+ }
2601
+ });
2602
+ return persons;
2603
+ }
2604
+ getSiblings() {
2605
+ const persons = new _Individuals();
2606
+ this.values().forEach((indi) => {
2607
+ if (indi) {
2608
+ persons.merge(indi.getSiblings());
2609
+ }
2610
+ });
2611
+ return persons;
2612
+ }
2613
+ getChildren() {
2614
+ const persons = new _Individuals();
2615
+ this.values().forEach((indi) => {
2616
+ if (indi) {
2617
+ persons.merge(indi.getChildren());
2618
+ }
2619
+ });
2620
+ return persons;
2621
+ }
2622
+ getParents() {
2623
+ const persons = new _Individuals();
2624
+ this.values().forEach((indi) => {
2625
+ if (indi) {
2626
+ persons.merge(indi.getParents());
2627
+ }
2628
+ });
2629
+ return persons;
2630
+ }
2631
+ getCoParents() {
2632
+ const persons = new _Individuals();
2633
+ this.values().forEach((indi) => {
2634
+ if (indi) {
2635
+ persons.merge(indi.getCoParents());
2636
+ }
2637
+ });
2638
+ return persons;
2639
+ }
2640
+ getSpouses() {
2641
+ const persons = new _Individuals();
2642
+ this.values().forEach((indi) => {
2643
+ if (indi) {
2644
+ persons.merge(indi.getCoParents());
2645
+ }
2646
+ });
2647
+ return persons;
2648
+ }
2649
+ toName() {
2650
+ return super.toProp("NAME")?.toValue();
2651
+ }
2652
+ toList() {
2653
+ return new _Individuals().concat(this.getItems());
2654
+ }
2655
+ };
2656
+
2657
+ // src/classes/name.ts
2658
+ var CommonName = class extends Common {
2659
+ constructor(gedcom, id, main, parent) {
2660
+ super(gedcom, id, main, parent);
2661
+ delete this.id;
2662
+ }
2663
+ set value(value) {
2664
+ if (value && this._main instanceof Indi) {
2665
+ const nameParts = value.match(
2666
+ /(?<givenname>[^/]*)(\/(?<surname>[^/]*)\/)?(?<suffix>.*)$/
2667
+ )?.groups;
2668
+ if (nameParts?.givenname?.trim()) {
2669
+ this.GIVN = this.GIVN || createCommon(this._gedcom, void 0, this.main);
2670
+ this.GIVN.isListable = false;
2671
+ this.GIVN.value = nameParts.givenname.trim();
2672
+ }
2673
+ if (nameParts?.surname?.trim()) {
2674
+ this.SURN = this.SURN || createCommon(this._gedcom, void 0, this.main);
2675
+ this.SURN.value = nameParts.surname.trim();
2676
+ this.SURN.isListable = false;
2677
+ }
2678
+ if (nameParts?.suffix?.trim()) {
2679
+ this.NSFX = this.NSFX || createCommon(this._gedcom, void 0, this.main);
2680
+ this.NSFX.value = nameParts.suffix.trim();
2681
+ this.NSFX.isListable = false;
2682
+ }
2683
+ }
2684
+ this._value = value;
2685
+ }
2686
+ get value() {
2687
+ if (this._value === void 0 && this.DISPLAY?.value) {
2688
+ return this.DISPLAY?.value;
2689
+ }
2690
+ return this._value;
2691
+ }
2692
+ name(value) {
2693
+ this.value = value;
2694
+ return this;
2695
+ }
2696
+ };
2697
+ var createCommonName = (gedcom, id, main, parent) => {
2698
+ return createProxy(
2699
+ new CommonName(gedcom, id, main, parent)
2700
+ );
2701
+ };
2702
+
2703
+ // src/classes/indi.ts
2704
+ var ALLOWED_FACTS = [
2705
+ "EVEN",
2706
+ "OCCU",
2707
+ "OCCUPATIONS",
2708
+ "RESI",
2709
+ "BIRT",
2710
+ "DEAT",
2711
+ "BAPT",
2712
+ "BAPM",
2713
+ "CHRI",
2714
+ "CHR",
2715
+ "CHRA",
2716
+ "BURI",
2717
+ "CREM",
2718
+ "ADOP",
2719
+ "BARM",
2720
+ "BASM",
2721
+ "BLES",
2722
+ "CONF",
2723
+ "FCOM",
2724
+ "ORDN",
2725
+ "NATU",
2726
+ "EMIG",
2727
+ "IMMI",
2728
+ "CENS",
2729
+ "PROB",
2730
+ "WILL",
2731
+ "GRAD",
2732
+ "RETI",
2733
+ "EDUC",
2734
+ "DIV",
2735
+ "RELI",
2736
+ "CAST",
2737
+ "DSCR",
2738
+ "NATI",
2739
+ "PROP",
2740
+ "SSN",
2741
+ "TITL",
2742
+ "ADDR",
2743
+ "BAPL",
2744
+ "CONL",
2745
+ "ENDL",
2746
+ "SLGC",
2747
+ "_MILT",
2748
+ "_MILTID",
2749
+ "FACT",
2750
+ "_ORIG",
2751
+ "_WLNK",
2752
+ "WWW",
2753
+ "URL"
2754
+ ];
2755
+ var DISALLOWED_CUSTOM_FACTS = ["DNA Test", "Newspaper"];
2756
+ var CustomFactRenderers = {
2757
+ AKA: (label, fact, indi) => {
2758
+ const originalNameObj = indi?.NAME;
2759
+ const note = fact.get("NOTE");
2760
+ const factName = note?.toValue();
2761
+ const name = createCommonName(fact.getGedcom(), void 0, indi);
2762
+ const suffix = originalNameObj?.NSFX?.toValue();
2763
+ const surname = originalNameObj?.SURN?.toValue();
2764
+ const givenname = originalNameObj?.GIVN?.toValue();
2765
+ const nameParts = [
2766
+ ...givenname?.split(" ").map((s) => ({ name: s, givenname: true })) ?? [],
2767
+ ...surname?.split(" ").map((s) => ({ name: s, surname: true })) ?? [],
2768
+ ...suffix?.split(" ").map((s) => ({ name: s, suffix: true })) ?? []
2769
+ ].filter(Boolean);
2770
+ const factParts = factName?.split(" ");
2771
+ if (nameParts.length === factParts?.length && !(note instanceof CommonName)) {
2772
+ const guessedSuffix = [];
2773
+ const guessedSurname = [];
2774
+ const guessedGivenname = [];
2775
+ factParts.forEach((f, i) => {
2776
+ const namePart = nameParts[i];
2777
+ if (!f) {
2778
+ return;
2779
+ }
2780
+ if (namePart.suffix) {
2781
+ guessedSuffix.push(f);
2782
+ } else if (namePart.givenname) {
2783
+ guessedGivenname.push(f);
2784
+ } else if (namePart.surname) {
2785
+ guessedSurname.push(f);
2786
+ }
2787
+ });
2788
+ const allNamePart = [];
2789
+ if (guessedGivenname.length) {
2790
+ allNamePart.push(guessedGivenname.join(" "));
2791
+ }
2792
+ if (guessedSurname.length) {
2793
+ allNamePart.push(`/${guessedSurname.join(" ")}/`);
2794
+ }
2795
+ if (guessedSuffix.length) {
2796
+ allNamePart.push(guessedSuffix.join(" "));
2797
+ }
2798
+ name.value = allNamePart.join(" ");
2799
+ } else {
2800
+ name.value = factName;
2801
+ }
2802
+ fact.set("NOTE", name);
2803
+ label.value = "AKA";
2804
+ fact.set("_LABEL", label);
2805
+ }
2806
+ };
2807
+ var relativesOnLevelCache = relativesCache("relativesOnLevelCache");
2808
+ var relativesOnDegreeCache = relativesCache("relativesOnDegreeCache");
2809
+ var Indi = class extends Common {
2810
+ toName() {
2811
+ return this.get("NAME")?.toValue();
2812
+ }
2813
+ toNaturalName() {
2814
+ return this.get("NAME")?.toValue()?.replaceAll("/", "");
2815
+ }
2816
+ toList() {
2817
+ return new Individuals().concat(
2818
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2819
+ this.id ? { [this.id]: this } : { ...[this] }
2820
+ );
2821
+ }
2822
+ generateTree(props) {
2823
+ const {
2824
+ generations,
2825
+ level,
2826
+ index,
2827
+ showDescendants,
2828
+ offspringSpouses,
2829
+ ancestorSpouses,
2830
+ onlyDescendants,
2831
+ maxLevel,
2832
+ minLevel,
2833
+ drawNonBiologicalAncestors,
2834
+ ancestorSiblings
2835
+ } = props;
2836
+ if (!this.id) {
2837
+ throw new Error("Indi must have an id");
2838
+ }
2839
+ const isMainDescendantLevel = showDescendants && level <= 1;
2840
+ const isDescendantLevel = showDescendants && level < 1;
2841
+ if (level < 1 && !isDescendantLevel) {
2842
+ throw new Error("Arguments 2 must be greater than 0.");
2843
+ }
2844
+ if (maxLevel !== void 0 && maxLevel < level || minLevel !== void 0 && minLevel > level) {
2845
+ return this;
2846
+ }
2847
+ const gens = generations ?? {
2848
+ existed: {},
2849
+ tree: {},
2850
+ halves: {},
2851
+ lastItems: {}
2852
+ };
2853
+ const families = this.getFamiliesBiologicalFirst("FAMC");
2854
+ const familiesAllMember = families.getParents();
2855
+ families.forEach((fam, famKey, famIndex) => {
2856
+ if (!this.id) {
2857
+ return;
1845
2858
  }
1846
2859
  const id = fam.id;
1847
2860
  let father = isDescendantLevel ? void 0 : fam.getHusband().index(0);
@@ -2281,7 +3294,7 @@ var Indi = class extends Common {
2281
3294
  return result;
2282
3295
  }
2283
3296
  ancestryLink() {
2284
- const www = this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
3297
+ const www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
2285
3298
  const tree = this.getAncestryTreeId();
2286
3299
  if (this.id) {
2287
3300
  return `https://${www}/family-tree/person/tree/${tree}/person/${this.id.replace(
@@ -2293,7 +3306,7 @@ var Indi = class extends Common {
2293
3306
  async ancestryMedia(namespace) {
2294
3307
  const list = {};
2295
3308
  const objeList = this.get("OBJE")?.toList().copy();
2296
- const www = this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
3309
+ const www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
2297
3310
  const tree = this.getAncestryTreeId();
2298
3311
  if (objeList) {
2299
3312
  await Promise.all(
@@ -2311,10 +3324,14 @@ var Indi = class extends Common {
2311
3324
  const clone = obje?.get("_CLON._OID")?.toValue();
2312
3325
  const mser = obje?.get("_MSER._LKID")?.toValue();
2313
3326
  let url = obje?.get("FILE")?.toValue();
2314
- const title = obje?.get("TITL")?.toValue() ?? "";
2315
- const type = obje?.get("FORM")?.toValue() ?? "raw";
2316
- const imgId = clone || mser;
2317
- if (!www || !tree || !this.id) {
3327
+ const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
3328
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3329
+ let imgId = clone || mser;
3330
+ const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
3331
+ if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
3332
+ return;
3333
+ }
3334
+ if (!this.id) {
2318
3335
  return;
2319
3336
  }
2320
3337
  if (!namespace && !url) {
@@ -2332,13 +3349,16 @@ var Indi = class extends Common {
2332
3349
  }
2333
3350
  url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
2334
3351
  }
3352
+ if (!imgId && hasEmbeddedOrLocalFile && url) {
3353
+ imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
3354
+ }
2335
3355
  if (url && imgId) {
2336
- const id = `${tree}-${this.id}-${imgId}`;
3356
+ const id = `${tree || "gedzip"}-${this.id}-${imgId}`;
2337
3357
  list[id] = {
2338
3358
  key,
2339
3359
  isPrimary,
2340
3360
  id,
2341
- tree,
3361
+ tree: tree || "gedzip",
2342
3362
  imgId,
2343
3363
  person: this.id,
2344
3364
  title,
@@ -2353,7 +3373,7 @@ var Indi = class extends Common {
2353
3373
  return list;
2354
3374
  }
2355
3375
  myheritageLink(poolId = 0) {
2356
- const www = this._gedcom?.HEAD?.SOUR?.CORP?.value?.toLowerCase().replace(/^www\./gi, "");
3376
+ const www = (this.getFromSourceHeads("SOUR.CORP.value") || this._gedcom?.HEAD?.SOUR?.CORP?.value)?.toLowerCase().replace(/^www\./gi, "");
2357
3377
  const site = this.getMyHeritageTreeId();
2358
3378
  const file = this._gedcom?.HEAD?.get("FILE")?.toValue()?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
2359
3379
  const normalizedFile = file?.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
@@ -2384,9 +3404,11 @@ var Indi = class extends Common {
2384
3404
  obje.standardizeMedia();
2385
3405
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
2386
3406
  const url = obje?.get("FILE")?.toValue();
2387
- const title = obje?.get("NOTE")?.toValue() ?? "";
2388
- const type = obje?.get("FORM")?.toValue() ?? "raw";
2389
- const imgId = obje?.get("_PHOTO_RIN")?.toValue();
3407
+ const title = obje?.get("FILE.NOTE")?.toValue() ?? obje?.get("NOTE")?.toValue() ?? "";
3408
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
3409
+ const photoRin = obje?.get("_PHOTO_RIN")?.toValue();
3410
+ const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
3411
+ const imgId = photoRin || (hasEmbeddedOrLocalFile && url ? `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}` : void 0);
2390
3412
  if (url && imgId) {
2391
3413
  const id = `${tree}-${this.id}-${imgId}`;
2392
3414
  list[id] = {
@@ -2509,10 +3531,10 @@ var Indi = class extends Common {
2509
3531
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
2510
3532
  const url = obje?.get("FILE")?.toValue();
2511
3533
  const title = obje?.get("TITL")?.toValue() ?? "";
2512
- const type = obje?.get("FORM")?.toValue() ?? "raw";
3534
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
2513
3535
  if (url) {
2514
3536
  const urlMatch = url.match(/\/([^/]+)\?hash=/);
2515
- const imgId = urlMatch?.[1] || `img-${index}-${Date.now().toString(36)}`;
3537
+ const imgId = urlMatch?.[1] || (url.startsWith("data:") ? `data-${index}-${getFileExtension(url) || "bin"}` : `img-${index}-${Date.now().toString(36)}`);
2516
3538
  const id = `geni-${geniId}-${imgId}`;
2517
3539
  list[id] = {
2518
3540
  isPrimary,
@@ -2549,10 +3571,10 @@ var Indi = class extends Common {
2549
3571
  obje.standardizeMedia();
2550
3572
  const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
2551
3573
  const url = obje?.get("FILE")?.toValue();
2552
- const title = obje?.get("TITL")?.toValue() ?? "";
2553
- const type = obje?.get("FORM")?.toValue() ?? "raw";
3574
+ const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
3575
+ const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
2554
3576
  if (url) {
2555
- const imgId = `media-${index}-${url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
3577
+ const imgId = `media-${index}-${url.startsWith("data:") ? getFileExtension(url) || "bin" : url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
2556
3578
  const id = `${treeId}-${this.id}-${imgId}`;
2557
3579
  list[id] = {
2558
3580
  isPrimary,
@@ -2592,7 +3614,20 @@ var Indi = class extends Common {
2592
3614
  cacheKey
2593
3615
  );
2594
3616
  if (cached !== void 0) {
2595
- return cached;
3617
+ if (cached?.file && !isRemoteOrEmbeddedMediaUrl(cached.file)) {
3618
+ const resolvedCached = await resolveLocalMediaUrl(cached.file);
3619
+ if (resolvedCached && isRemoteOrEmbeddedMediaUrl(resolvedCached)) {
3620
+ const refreshed = { ...cached, file: resolvedCached };
3621
+ profilePictureCache(
3622
+ this._gedcom,
3623
+ cacheKey,
3624
+ refreshed
3625
+ );
3626
+ return refreshed;
3627
+ }
3628
+ } else {
3629
+ return cached;
3630
+ }
2596
3631
  }
2597
3632
  const mediaList = await this.multimedia(namespace);
2598
3633
  if (!mediaList) {
@@ -2604,39 +3639,40 @@ var Indi = class extends Common {
2604
3639
  return void 0;
2605
3640
  }
2606
3641
  const mediaArray = Object.values(mediaList);
2607
- const primaryMedia = mediaArray.find(
2608
- (media) => media.isPrimary && isImageFormat(media.contentType || getFileExtension(media.url))
2609
- );
2610
- if (primaryMedia) {
2611
- const result = {
2612
- file: primaryMedia.url,
2613
- form: primaryMedia.contentType,
2614
- title: primaryMedia.title,
2615
- isPrimary: true
3642
+ const toDisplayableProfile = async (media, isPrimary) => {
3643
+ const resolvedFile = await resolveLocalMediaUrl(media.url);
3644
+ if (!resolvedFile || !isRemoteOrEmbeddedMediaUrl(resolvedFile)) {
3645
+ return void 0;
3646
+ }
3647
+ return {
3648
+ file: resolvedFile,
3649
+ form: media.contentType,
3650
+ title: media.title,
3651
+ isPrimary
2616
3652
  };
2617
- profilePictureCache(this._gedcom, cacheKey, result);
2618
- return result;
2619
- }
2620
- if (onlyPrimary) {
2621
- profilePictureCache(
2622
- this._gedcom,
2623
- cacheKey,
2624
- void 0
2625
- );
2626
- return void 0;
2627
- }
2628
- const secondaryMedia = mediaArray.find(
2629
- (media) => isImageFormat(media.contentType || getFileExtension(media.url))
3653
+ };
3654
+ const candidates = mediaArray.filter(
3655
+ (media) => isImageFormat(
3656
+ media.contentType || media.url || getFileExtension(media.url)
3657
+ )
2630
3658
  );
2631
- if (secondaryMedia) {
2632
- const result = {
2633
- file: secondaryMedia.url,
2634
- form: secondaryMedia.contentType,
2635
- title: secondaryMedia.title,
2636
- isPrimary: false
2637
- };
2638
- profilePictureCache(this._gedcom, cacheKey, result);
2639
- return result;
3659
+ const ordered = [
3660
+ ...candidates.filter((media) => media.isPrimary),
3661
+ ...candidates.filter((media) => !media.isPrimary)
3662
+ ];
3663
+ for (const media of ordered) {
3664
+ if (onlyPrimary && !media.isPrimary) {
3665
+ break;
3666
+ }
3667
+ const result = await toDisplayableProfile(media, !!media.isPrimary);
3668
+ if (result) {
3669
+ profilePictureCache(
3670
+ this._gedcom,
3671
+ cacheKey,
3672
+ result
3673
+ );
3674
+ return result;
3675
+ }
2640
3676
  }
2641
3677
  profilePictureCache(
2642
3678
  this._gedcom,
@@ -2868,11 +3904,161 @@ var Indi = class extends Common {
2868
3904
  isMale() {
2869
3905
  return this.get("SEX")?.toValue() === "M";
2870
3906
  }
2871
- isFemale() {
2872
- return this.get("SEX")?.toValue() === "F";
3907
+ isFemale() {
3908
+ return this.get("SEX")?.toValue() === "F";
3909
+ }
3910
+ isUnknownSex() {
3911
+ return !this.isMale() && !this.isFemale();
3912
+ }
3913
+ addSpouse(other) {
3914
+ if (!this.id || !other?.id || this.id === other.id || !this._gedcom) {
3915
+ return void 0;
3916
+ }
3917
+ const existing = getFamilyWith(this, other.id);
3918
+ if (existing) {
3919
+ return existing;
3920
+ }
3921
+ const fam = this._gedcom.createFamily();
3922
+ if (!fam.addSpouse(this) || !fam.addSpouse(other)) {
3923
+ return void 0;
3924
+ }
3925
+ return fam;
3926
+ }
3927
+ addChild(child, pedigree) {
3928
+ if (!this.id || !child?.id || this.id === child.id || !this._gedcom) {
3929
+ return void 0;
3930
+ }
3931
+ const existing = findReusableParentChildFamily(
3932
+ this,
3933
+ child
3934
+ );
3935
+ if (existing === "already") {
3936
+ const fam2 = child.getFamilies("FAMC")?.find(
3937
+ (item) => !!item && item.hasParent(this.id) && item.hasChild(child.id)
3938
+ );
3939
+ if (fam2) {
3940
+ setChildPedigree(
3941
+ fam2,
3942
+ child,
3943
+ pedigree,
3944
+ this
3945
+ );
3946
+ }
3947
+ return fam2;
3948
+ }
3949
+ const fam = existing ?? this._gedcom.createFamily();
3950
+ if (!fam.addSpouse(this)) {
3951
+ return void 0;
3952
+ }
3953
+ if (!fam.addChild(child, pedigree, this)) {
3954
+ return void 0;
3955
+ }
3956
+ return fam;
3957
+ }
3958
+ addParent(parent, pedigree) {
3959
+ return parent.addChild(this, pedigree);
3960
+ }
3961
+ /**
3962
+ * Link an existing top-level OBJE record to this individual (`1 OBJE @On@`).
3963
+ */
3964
+ attachMultimedia(objeOrKey, options) {
3965
+ if (!this._gedcom || !this.id) {
3966
+ return void 0;
3967
+ }
3968
+ const obje = typeof objeOrKey === "string" ? this._gedcom.obje(objeOrKey) : objeOrKey;
3969
+ if (!obje?.id) {
3970
+ return void 0;
3971
+ }
3972
+ const already = this.get("OBJE")?.toList()?.values()?.some((item) => item?.toValue?.() === obje.id);
3973
+ if (!already) {
3974
+ const pointer = makePointer(
3975
+ this._gedcom,
3976
+ this,
3977
+ obje.id,
3978
+ "OBJE"
3979
+ );
3980
+ this.assign("OBJE", pointer);
3981
+ }
3982
+ if (options?.primary) {
3983
+ this.get("OBJE")?.toList()?.forEach((item) => {
3984
+ const target = item?.refType === "OBJE" ? this._gedcom?.obje(
3985
+ String(item.toValue())
3986
+ ) : item;
3987
+ if (!target) {
3988
+ return;
3989
+ }
3990
+ if (target.id === obje.id) {
3991
+ target.set("_PRIM", "Y");
3992
+ } else if (target.get("_PRIM")?.toValue() === "Y") {
3993
+ target.set("_PRIM", "N");
3994
+ }
3995
+ });
3996
+ obje.set("_PRIM", "Y");
3997
+ }
3998
+ return obje;
3999
+ }
4000
+ detachMultimedia(objeKey) {
4001
+ const list = this.get("OBJE")?.toList();
4002
+ if (!list) {
4003
+ return;
4004
+ }
4005
+ const toRemove = list.values().filter(
4006
+ (item) => item?.toValue?.() === objeKey || item?.id === objeKey
4007
+ );
4008
+ toRemove.forEach((item) => {
4009
+ if (item) {
4010
+ list.delete(item);
4011
+ }
4012
+ });
4013
+ if (list.length === 0) {
4014
+ this.remove("OBJE");
4015
+ }
4016
+ }
4017
+ /**
4018
+ * Create a multimedia record and attach it to this person.
4019
+ */
4020
+ attachMediaFromUrl(url, options) {
4021
+ if (!this._gedcom || !url) {
4022
+ return void 0;
4023
+ }
4024
+ const obje = this._gedcom.createMultimediaRecord({
4025
+ file: url,
4026
+ form: options?.form,
4027
+ title: options?.title,
4028
+ mediType: options?.mediType,
4029
+ primary: options?.primary,
4030
+ gedcomVersion: options?.gedcomVersion
4031
+ });
4032
+ return this.attachMultimedia(obje, { primary: options?.primary });
4033
+ }
4034
+ /**
4035
+ * Link a shared SNOTE record via `1 NOTE @Nn@` (GEDCOM 7).
4036
+ */
4037
+ attachSharedNote(noteOrKey) {
4038
+ if (!this._gedcom || !this.id) {
4039
+ return void 0;
4040
+ }
4041
+ const note = typeof noteOrKey === "string" ? this._gedcom.snote(noteOrKey) : noteOrKey;
4042
+ if (!note?.id) {
4043
+ return void 0;
4044
+ }
4045
+ const already = this.get("NOTE")?.toList()?.values()?.some((item) => item?.toValue?.() === note.id);
4046
+ if (!already) {
4047
+ const pointer = makePointer(
4048
+ this._gedcom,
4049
+ this,
4050
+ note.id,
4051
+ "SNOTE"
4052
+ );
4053
+ this.assign("NOTE", pointer);
4054
+ }
4055
+ return note;
4056
+ }
4057
+ addFact(input) {
4058
+ return addIndividualFact(this, input);
2873
4059
  }
2874
- isUnknownSex() {
2875
- return !this.isMale() && !this.isFemale();
4060
+ addNonEvent(input) {
4061
+ return addNonEvent(this, input);
2876
4062
  }
2877
4063
  getParentType(id) {
2878
4064
  let indi;
@@ -2914,7 +4100,7 @@ var Indi = class extends Common {
2914
4100
  if (!famChild) {
2915
4101
  const childIndi = this._gedcom?.indi(child.id);
2916
4102
  const childState = childIndi?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
2917
- childType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
4103
+ childType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
2918
4104
  } else {
2919
4105
  childType = famChild.get(usedRel)?.toValue() || "biological" /* BIOLOGICAL */;
2920
4106
  }
@@ -3074,7 +4260,9 @@ var Indi = class extends Common {
3074
4260
  }
3075
4261
  }
3076
4262
  if (kinship !== "child" || !breakAfterSpouse) {
3077
- indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(indi.getFathers().copy().merge(indi.getMothers())).forEach((relative) => {
4263
+ indi.getBiologicalFathers().copy().merge(indi.getBiologicalMothers()).merge(
4264
+ indi.getFathers().copy().merge(indi.getMothers())
4265
+ ).forEach((relative) => {
3078
4266
  if (!visited.has(relative)) {
3079
4267
  const currentRelation = indi.getParentType(relative);
3080
4268
  const isNonBiological = !!currentRelation && currentRelation !== "biological" /* BIOLOGICAL */;
@@ -3473,7 +4661,7 @@ var Indi = class extends Common {
3473
4661
  return;
3474
4662
  }
3475
4663
  const childState = child?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
3476
- const childType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
4664
+ const childType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
3477
4665
  if (childType?.toLowerCase() === filter.PEDI.toLowerCase()) {
3478
4666
  children.append(child);
3479
4667
  }
@@ -3581,7 +4769,7 @@ var Indi = class extends Common {
3581
4769
  const child = this.id && family.CHIL?.toValueList()?.item(this.id);
3582
4770
  if (!child) {
3583
4771
  const childState = this?.get("FAMC")?.toList()?.filter((item) => item.value === family.id).index(0);
3584
- const parentType = childState?.get("PEDI")?.toValue() || "biological" /* BIOLOGICAL */;
4772
+ const parentType = (childState?.get("PEDI") ?? childState?.get("PEDT"))?.toValue() || "biological" /* BIOLOGICAL */;
3585
4773
  if (parentType?.toLowerCase() === filter.PEDI.toLowerCase()) {
3586
4774
  parents.merge(family.getParents());
3587
4775
  }
@@ -5780,7 +6968,11 @@ var STANDARD_QUALIFIERS = {
5780
6968
  BEF: "Bef.",
5781
6969
  BEFORE: "Bef.",
5782
6970
  AFT: "Aft.",
5783
- AFTER: "Aft."
6971
+ AFTER: "Aft.",
6972
+ CAL: "Abt.",
6973
+ // calculated ≈ about for display
6974
+ EST: "Abt."
6975
+ // estimated ≈ about for display
5784
6976
  };
5785
6977
  var EXPORT_QUALIFIERS = {
5786
6978
  "Abt.": "ABT",
@@ -5788,6 +6980,11 @@ var EXPORT_QUALIFIERS = {
5788
6980
  "Aft.": "AFT"
5789
6981
  };
5790
6982
  var GEDCOM_MONTHS = /\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/g;
6983
+ var CALENDAR_PREFIX = /^(?<calendar>GREGORIAN|JULIAN|FRENCH_R|HEBREW)\b\s+/i;
6984
+ var isGedcomDateValueForm = (value) => (
6985
+ // Require space/end after the token so display forms like "Abt." are not opaque.
6986
+ /^(FROM|TO|BET|AFT|BEF|ABT|CAL|EST|INT)(\s|$)/i.test(value) || /\bAND\b/i.test(value)
6987
+ );
5791
6988
  var NOTE_MARKER = "####";
5792
6989
  var formatDateWithComponents = (date, hasDay, hasMonth, hasYear, noteValue, baseFormat = "dd MMM yyyy", locale) => {
5793
6990
  const hasNote = baseFormat.includes("NOTE");
@@ -5812,29 +7009,45 @@ var CommonDate = class extends Common {
5812
7009
  super(gedcom, id, main, parent);
5813
7010
  delete this.id;
5814
7011
  }
7012
+ get calendar() {
7013
+ return this._calendar;
7014
+ }
5815
7015
  set value(value) {
5816
7016
  if (value) {
5817
- const noteRegExp = /^(?<note>[a-zA-Z]+\.)/;
5818
- const noteMatch = value.match(noteRegExp)?.groups;
5819
7017
  let validValue = value;
7018
+ const calendarMatch = validValue.match(CALENDAR_PREFIX);
7019
+ if (calendarMatch?.groups?.calendar) {
7020
+ this._calendar = calendarMatch.groups.calendar.toUpperCase();
7021
+ validValue = validValue.slice(calendarMatch[0].length);
7022
+ } else {
7023
+ this._calendar = void 0;
7024
+ }
7025
+ const noteRegExp = /^(?<note>[a-zA-Z]+\.)/;
7026
+ const noteMatch = validValue.match(noteRegExp)?.groups;
5820
7027
  if (noteMatch?.note) {
5821
7028
  this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
5822
7029
  this.NOTE.value = noteMatch?.note;
5823
- validValue = value.replace(noteRegExp, "");
7030
+ validValue = validValue.replace(noteRegExp, "");
5824
7031
  } else {
5825
- const qualifierMatch = value.match(
5826
- /^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER)\b\s*/i
7032
+ const qualifierMatch = validValue.match(
7033
+ /^(?<qualifier>ABT|ABOUT|BEF|BEFORE|AFT|AFTER|CAL|EST)\b\s*/i
5827
7034
  );
5828
7035
  const qualifier = qualifierMatch?.groups?.qualifier?.toUpperCase();
5829
7036
  const note = qualifier ? STANDARD_QUALIFIERS[qualifier] : void 0;
5830
7037
  if (note) {
5831
7038
  this.NOTE = this.NOTE || createCommon(this._gedcom, void 0, this.main);
5832
7039
  this.NOTE.value = note;
5833
- validValue = value.slice(qualifierMatch[0].length);
7040
+ validValue = validValue.slice(qualifierMatch[0].length);
5834
7041
  }
5835
7042
  }
5836
7043
  const acceptedDate = this.isValidDateFormat(validValue);
5837
- if (acceptedDate) {
7044
+ if (isGedcomDateValueForm(validValue.trim())) {
7045
+ delete this.DAY;
7046
+ delete this.MONTH;
7047
+ delete this.YEAR;
7048
+ this._date = void 0;
7049
+ this._value = value;
7050
+ } else if (acceptedDate) {
5838
7051
  this.DAY = this.DAY || createCommon(this._gedcom, void 0, this.main);
5839
7052
  this.DAY.value = format(acceptedDate, "dd");
5840
7053
  this.MONTH = this.MONTH || createCommon(this._gedcom, void 0, this.main);
@@ -5937,6 +7150,15 @@ var CommonDate = class extends Common {
5937
7150
  );
5938
7151
  }
5939
7152
  exportValue() {
7153
+ if (typeof this._value === "string") {
7154
+ const withoutCalendar = this._value.replace(CALENDAR_PREFIX, "");
7155
+ if (isGedcomDateValueForm(withoutCalendar.trim())) {
7156
+ return this._value.replace(
7157
+ /^((?:GREGORIAN|JULIAN|FRENCH_R|HEBREW)\s+)?(FROM|TO|BET|AFT|BEF|ABT|CAL|EST|INT)\b/i,
7158
+ (_m, cal, q) => `${cal || ""}${q.toUpperCase()}`
7159
+ );
7160
+ }
7161
+ }
5940
7162
  const formatted = this.toValue("NOTE dd MMM yyyy", null);
5941
7163
  if (!formatted) {
5942
7164
  return formatted;
@@ -5944,826 +7166,987 @@ var CommonDate = class extends Common {
5944
7166
  const note = this.NOTE?.value?.trim();
5945
7167
  const qualifier = note ? EXPORT_QUALIFIERS[note] : void 0;
5946
7168
  const standardized = qualifier ? formatted.replace(note, qualifier) : formatted;
5947
- return standardized.replace(
7169
+ const withMonths = standardized.replace(
5948
7170
  GEDCOM_MONTHS,
5949
7171
  (month) => month.toUpperCase()
5950
7172
  );
7173
+ if (this._calendar && this._calendar !== "GREGORIAN") {
7174
+ return `${this._calendar} ${withMonths}`;
7175
+ }
7176
+ return withMonths;
5951
7177
  }
5952
- toGedcomLines(tag, level = 0, options) {
5953
- const internal = new RegExp(
5954
- `^${level} (DAY|MONTH|YEAR)( |$)|^${level} NOTE (Abt\\.|Bef\\.|Aft\\.)$`
5955
- );
5956
- return super.toGedcomLines(tag, level, options).filter((line) => !internal.test(line));
5957
- }
5958
- inRange(range, trueIfNoYear = false) {
5959
- return inRange(this.YEAR?.value, range, trueIfNoYear);
5960
- }
5961
- };
5962
- var createCommonDate = (gedcom, id, main, parent) => {
5963
- return createProxy(
5964
- new CommonDate(gedcom, id, main, parent)
5965
- );
5966
- };
5967
- var isCommonDate = (value) => {
5968
- return !!value && value !== null && typeof value === "object" && "_date" in value;
5969
- };
5970
-
5971
- // src/utils/get-family-with.ts
5972
- var getFamilyWith = (person1, person2, famType = "FAMS") => {
5973
- return person1?.get(famType)?.toValueList().find((fam) => {
5974
- const family = fam;
5975
- return famType === "FAMC" || family?.HUSB?.value === person2 || family?.WIFE?.value === person2;
5976
- });
5977
- };
5978
-
5979
- // src/constants/orders.ts
5980
- var BIRTH_ASC = {
5981
- "BIRT.DATE": {
5982
- direction: "ASC",
5983
- getter: (value, raw) => {
5984
- if (isCommonDate(raw) && raw.rawValue) {
5985
- return raw.rawValue.getTime();
5986
- }
5987
- return new Date(value).getTime();
5988
- }
5989
- }
5990
- };
5991
- var BIRTH_DESC = {
5992
- "BIRT.DATE": {
5993
- direction: "DESC",
5994
- getter: (value, raw) => {
5995
- if (isCommonDate(raw) && raw.rawValue) {
5996
- return raw.rawValue.getTime();
5997
- }
5998
- return new Date(value).getTime();
5999
- }
6000
- }
6001
- };
6002
- var DEATH_ASC = {
6003
- "DEAT.DATE": {
6004
- direction: "ASC",
6005
- getter: (value, raw) => {
6006
- if (isCommonDate(raw) && raw.rawValue) {
6007
- return raw.rawValue.getTime();
6008
- }
6009
- return new Date(value).getTime();
6010
- }
6011
- }
6012
- };
6013
- var DEATH_DESC = {
6014
- "DEAT.DATE": {
6015
- direction: "DESC",
6016
- getter: (value, raw) => {
6017
- if (isCommonDate(raw) && raw.rawValue) {
6018
- return raw.rawValue.getTime();
6019
- }
6020
- return new Date(value).getTime();
6021
- }
6022
- }
6023
- };
6024
- var DATE_ASC = {
6025
- DATE: {
6026
- direction: "ASC",
6027
- getter: (value, raw) => {
6028
- if (isCommonDate(raw) && raw.rawValue) {
6029
- return raw.rawValue.getTime();
6030
- }
6031
- return new Date(value).getTime();
6032
- }
6033
- }
6034
- };
6035
- var chars = [
6036
- "a",
6037
- "\xE0",
6038
- "\xE1",
6039
- "\xE2",
6040
- "\xE4",
6041
- "\xE6",
6042
- "\xE3",
6043
- "\xE5",
6044
- "\u0101",
6045
- "b",
6046
- "c",
6047
- "\xE7",
6048
- "\u0107",
6049
- "\u010D",
6050
- "cs",
6051
- "d",
6052
- "dz",
6053
- "dzs",
6054
- "e",
6055
- "\xE8",
6056
- "\xE9",
6057
- "\xEA",
6058
- "\xEB",
6059
- "\u0113",
6060
- "\u0117",
6061
- "\u0119",
6062
- "f",
6063
- "g",
6064
- "gy",
6065
- "h",
6066
- "i",
6067
- "\xEE",
6068
- "\xEF",
6069
- "\xED",
6070
- "\u012B",
6071
- "\u012F",
6072
- "\xEC",
6073
- "j",
6074
- "k",
6075
- "l",
6076
- "\u0142",
6077
- "ly",
6078
- "m",
6079
- "n",
6080
- "\xF1",
6081
- "\u0144",
6082
- "ny",
6083
- "o",
6084
- "\xF3",
6085
- "\xF6",
6086
- "\u0151",
6087
- "\xF4",
6088
- "\xF2",
6089
- "\xF5",
6090
- "\u0153",
6091
- "\xF8",
6092
- "\u014D",
6093
- "p",
6094
- "q",
6095
- "r",
6096
- "s",
6097
- "\u015B",
6098
- "\u0161",
6099
- "\xDF",
6100
- "sz",
6101
- "t",
6102
- "ty",
6103
- "u",
6104
- "\xFA",
6105
- "\xFC",
6106
- "\u0171",
6107
- "\xFB",
6108
- "\xF9",
6109
- "\u016B",
6110
- "v",
6111
- "w",
6112
- "x",
6113
- "y",
6114
- "z",
6115
- "zs"
6116
- ];
6117
- chars.reduce((acc, curr, idx) => {
6118
- acc[curr] = idx;
6119
- return acc;
6120
- }, {});
6121
- var getBirthAsc = (itemA, _keyA, itemB, _keyB) => {
6122
- const birthA = itemA?.BIRT?.index(0);
6123
- const birthB = itemB?.BIRT?.index(0);
6124
- const valueA = birthA?.DATE?.rawValue;
6125
- const valueB = birthB?.DATE?.rawValue;
6126
- if (valueA?.getTime() === valueB?.getTime()) {
6127
- return 0;
6128
- }
6129
- if (!valueA || valueB && valueA > valueB) {
6130
- return 1;
6131
- }
6132
- return -1;
6133
- };
6134
- var getMarriageAsc = (person, famType = "FAMS") => (itemA, _keyA, itemB, _keyB) => {
6135
- if (!person && famType === "FAMS") {
6136
- return 0;
6137
- }
6138
- const familyA = getFamilyWith(itemA, person);
6139
- const familyB = getFamilyWith(itemB, person);
6140
- const marriageA = familyA?.MARR?.DATE?.rawValue;
6141
- const marriageB = familyB?.MARR?.DATE?.rawValue;
6142
- if (marriageA?.getTime() === marriageB?.getTime()) {
6143
- return 0;
6144
- }
6145
- if (!marriageA || marriageB && marriageA > marriageB) {
6146
- return 1;
6147
- }
6148
- return -1;
6149
- };
6150
- var getMarriageAscAndChildBirth = (person) => (itemA, keyA, itemB, keyB) => {
6151
- const marriageSort = getMarriageAsc(person)(itemA, keyA, itemB, keyB);
6152
- if (marriageSort !== 0) {
6153
- return marriageSort;
6154
- }
6155
- const familyA = getFamilyWith(itemA, person);
6156
- const familyB = getFamilyWith(itemB, person);
6157
- const childA = familyA?.getChildren().orderBy(BIRTH_ASC).index(0);
6158
- const childB = familyB?.getChildren().orderBy(BIRTH_ASC).index(0);
6159
- return getBirthAsc(childA, keyA, childB);
6160
- };
6161
- var uniqueItemsCache = /* @__PURE__ */ new WeakMap();
6162
- var setNestedGroup = (obj, key, value, uniqueCounting = true) => {
6163
- const parts = Array.isArray(key) ? key : key.split(/,\s*/);
6164
- set(obj, [...parts, "items"], value);
6165
- parts.forEach((_, index) => {
6166
- if (!uniqueCounting) {
6167
- const key2 = [...parts.toSpliced(index + 1), "length"];
6168
- const length = get(obj, key2);
6169
- set(obj, key2, (length ?? 0) + value.length);
6170
- return;
6171
- }
6172
- const pathKey = [...parts.toSpliced(index + 1)];
6173
- const node = get(obj, pathKey);
6174
- if (node) {
6175
- let uniqueItems = uniqueItemsCache.get(node);
6176
- if (!uniqueItems) {
6177
- uniqueItems = new Individuals();
6178
- uniqueItemsCache.set(node, uniqueItems);
6179
- }
6180
- uniqueItems.merge(value);
6181
- set(obj, [...pathKey, "length"], uniqueItems.length);
6182
- }
6183
- });
6184
- };
6185
-
6186
- // src/utils/place-parser.ts
6187
- var getPlaceParts = (place = []) => {
6188
- const partsString = Array.isArray(place) ? place.filter(Boolean).join(", ") : place;
6189
- if (!partsString) {
6190
- return [{}];
6191
- }
6192
- const parts = partsString.split(/,\s*/).map((p) => p.trim()).filter(Boolean);
6193
- if (parts.length === 0) {
6194
- return [{}];
7178
+ toGedcomLines(tag, level = 0, options) {
7179
+ const internal = new RegExp(
7180
+ `^${level} (DAY|MONTH|YEAR)( |$)|^${level} NOTE (Abt\\.|Bef\\.|Aft\\.)$`
7181
+ );
7182
+ return super.toGedcomLines(tag, level, options).filter((line) => !internal.test(line));
6195
7183
  }
6196
- const result = {};
6197
- if (parts.length === 1) {
6198
- result.town = parts[0];
6199
- } else if (parts.length === 2) {
6200
- result.town = parts[0];
6201
- result.country = parts[1];
6202
- } else if (parts.length === 3) {
6203
- result.town = parts[0];
6204
- result.county = parts[1];
6205
- result.country = parts[2];
6206
- } else {
6207
- result.leftParts = parts.slice(0, parts.length - 3);
6208
- result.town = parts[parts.length - 3];
6209
- result.county = parts[parts.length - 2];
6210
- result.country = parts[parts.length - 1];
7184
+ inRange(range, trueIfNoYear = false) {
7185
+ return inRange(this.YEAR?.value, range, trueIfNoYear);
6211
7186
  }
6212
- return [result];
6213
7187
  };
6214
-
6215
- // src/utils/place-translator.ts
6216
- var placeTranslator = (place) => {
6217
- return Array.isArray(place) ? place.join(", ") : place;
7188
+ var createCommonDate = (gedcom, id, main, parent) => {
7189
+ return createProxy(
7190
+ new CommonDate(gedcom, id, main, parent)
7191
+ );
7192
+ };
7193
+ var isCommonDate = (value) => {
7194
+ return !!value && value !== null && typeof value === "object" && "_date" in value;
6218
7195
  };
6219
7196
 
6220
- // src/classes/indis.ts
6221
- var Individuals = class _Individuals extends List {
6222
- copy() {
6223
- return super.copy(_Individuals);
7197
+ // src/utils/fact-edit.ts
7198
+ var SINGLETON_TAGS = /* @__PURE__ */ new Set(["BIRT", "DEAT", "SSN", "SEX", "DSCR"]);
7199
+ var firstRecord = (node) => {
7200
+ if (!node) {
7201
+ return void 0;
6224
7202
  }
6225
- except(item) {
6226
- return super.except(item, _Individuals);
7203
+ if (node instanceof List) {
7204
+ return node.index(0);
6227
7205
  }
6228
- filter(filters) {
6229
- return super.filter(filters, _Individuals);
7206
+ return node.index(0) ?? node;
7207
+ };
7208
+ var setDateOn = (gedcom, owner, parent, date) => {
7209
+ const trimmed = date.trim();
7210
+ if (!trimmed) {
7211
+ return;
6230
7212
  }
6231
- find(filters) {
6232
- return super.find(filters, _Individuals);
7213
+ let dateNode = parent.get("DATE");
7214
+ if (!dateNode || dateNode instanceof List) {
7215
+ dateNode = createCommonDate(gedcom, void 0, owner, parent);
7216
+ dateNode.type = "DATE";
7217
+ parent.set("DATE", dateNode);
6233
7218
  }
6234
- unattachedFilter(useUnattached) {
6235
- if (useUnattached) {
6236
- return this;
6237
- }
6238
- return this.filter((item) => !item.isUnattachedMember());
7219
+ dateNode.value = trimmed;
7220
+ };
7221
+ var fillFact = (gedcom, owner, event, input) => {
7222
+ if (input.value?.trim()) {
7223
+ event.value = input.value.trim();
6239
7224
  }
6240
- orderBy(orders) {
6241
- return super.orderBy(orders, _Individuals);
7225
+ if (input.type?.trim()) {
7226
+ event.set("TYPE", input.type.trim());
6242
7227
  }
6243
- getFirstEvent() {
6244
- const firstBirthPerson = this.getFirstBirth();
6245
- const firstDeathPerson = this.getFirstDeath();
6246
- const firstBirth = firstBirthPerson?.BIRT?.index(0);
6247
- const firstDeath = firstDeathPerson?.DEAT?.index(0);
6248
- if (!firstBirth?.DATE?.rawValue && !firstDeath?.DATE?.rawValue) {
6249
- return void 0;
6250
- }
6251
- if (!firstBirth?.DATE?.rawValue) {
6252
- return firstDeathPerson;
6253
- }
6254
- if (!firstDeath?.DATE?.rawValue) {
6255
- return firstBirthPerson;
6256
- }
6257
- if (firstDeath.DATE.rawValue < firstBirth.DATE.rawValue) {
6258
- return firstDeathPerson;
6259
- }
6260
- return firstBirthPerson;
7228
+ if (input.date) {
7229
+ setDateOn(gedcom, owner, event, input.date);
6261
7230
  }
6262
- getLastEvent() {
6263
- const lastDeathPerson = this.getLastDeath();
6264
- const lastBirthPerson = this.getLastBirth();
6265
- const lastBirth = lastBirthPerson?.BIRT?.index(0);
6266
- const lastDeath = lastDeathPerson?.DEAT?.index(0);
6267
- if (!lastBirth?.DATE?.rawValue && !lastDeath?.DATE?.rawValue) {
6268
- return void 0;
6269
- }
6270
- if (!lastDeath?.DATE?.rawValue) {
6271
- return lastBirthPerson;
6272
- }
6273
- if (!lastBirth?.DATE?.rawValue) {
6274
- return lastDeathPerson;
6275
- }
6276
- if (lastDeath.DATE.rawValue < lastBirth.DATE.rawValue) {
6277
- return lastBirthPerson;
6278
- }
6279
- return lastDeathPerson;
7231
+ if (input.place?.trim()) {
7232
+ event.set("PLAC", input.place.trim());
6280
7233
  }
6281
- getFirstBirth() {
6282
- return this.filter((item) => {
6283
- const birth = item.BIRT?.index(0);
6284
- if (birth?.DATE?.rawValue?.getTime() === 0) {
6285
- return true;
6286
- }
6287
- return !!birth?.DATE?.rawValue?.getTime();
6288
- }).orderBy(BIRTH_ASC).index(0);
7234
+ if (input.note?.trim()) {
7235
+ event.set("NOTE", input.note.trim());
6289
7236
  }
6290
- getLastBirth() {
6291
- return this.filter((item) => {
6292
- const birth = item.BIRT?.index(0);
6293
- if (birth?.DATE?.rawValue?.getTime() === 0) {
6294
- return true;
6295
- }
6296
- return !!birth?.DATE?.rawValue?.getTime();
6297
- }).orderBy(BIRTH_DESC).index(0);
7237
+ };
7238
+ var addIndividualFact = (indi, input) => {
7239
+ const gedcom = indi.getGedcom();
7240
+ if (!gedcom) {
7241
+ return void 0;
6298
7242
  }
6299
- getFirstDeath() {
6300
- return this.filter((item) => {
6301
- const death = item.DEAT?.index(0);
6302
- if (death?.DATE?.rawValue?.getTime() === 0) {
6303
- return true;
6304
- }
6305
- return !!death?.DATE?.rawValue?.getTime();
6306
- }).orderBy(DEATH_ASC).index(0);
7243
+ const tag = input.tag;
7244
+ let event = SINGLETON_TAGS.has(tag) ? firstRecord(indi.get(tag)) : void 0;
7245
+ if (!event) {
7246
+ event = createCommon(gedcom, void 0, indi);
7247
+ event.type = tag;
7248
+ if (SINGLETON_TAGS.has(tag)) {
7249
+ indi.set(tag, event);
7250
+ } else {
7251
+ indi.assign(tag, event);
7252
+ }
6307
7253
  }
6308
- getLastDeath() {
6309
- return this.filter((item) => {
6310
- const death = item.DEAT?.index(0);
6311
- if (death?.DATE?.rawValue?.getTime() === 0) {
6312
- return true;
6313
- }
6314
- return !!death?.DATE?.rawValue?.getTime();
6315
- }).orderBy(DEATH_DESC).index(0);
7254
+ fillFact(gedcom, indi, event, input);
7255
+ return event;
7256
+ };
7257
+ var addFamilyFact = (fam, input) => {
7258
+ const gedcom = fam.getGedcom();
7259
+ if (!gedcom) {
7260
+ return void 0;
6316
7261
  }
6317
- groupBy(group, sort, minOccurance = -1, lessOccuranceLabel) {
6318
- return super.groupBy(
6319
- group,
6320
- sort,
6321
- minOccurance,
6322
- lessOccuranceLabel,
6323
- _Individuals
6324
- );
7262
+ const event = createCommon(gedcom, void 0, fam);
7263
+ event.type = input.tag;
7264
+ fam.assign(input.tag, event);
7265
+ fillFact(gedcom, fam, event, input);
7266
+ return event;
7267
+ };
7268
+ var addNonEvent = (owner, input) => {
7269
+ const gedcom = owner.getGedcom();
7270
+ const eventType = input.event?.trim().toUpperCase();
7271
+ if (!gedcom || !eventType) {
7272
+ return void 0;
6325
7273
  }
6326
- groupByFirstLetters(sort = "group", minOccurance = -1, settings) {
6327
- return this.groupBy(
6328
- (item) => {
6329
- const { letter } = nameFormatter(item, settings);
6330
- return letter.trim() || "Unknown";
6331
- },
6332
- sort,
6333
- minOccurance,
6334
- "Letters appearing less than 5 times"
6335
- );
7274
+ const no = createCommon(gedcom, void 0, owner);
7275
+ no.type = "NO";
7276
+ no.value = eventType;
7277
+ if (input.date?.trim()) {
7278
+ setDateOn(gedcom, owner, no, input.date);
6336
7279
  }
6337
- groupBySurnames(sort, minOccurance = -1) {
6338
- return this.groupBy(
6339
- "NAME.SURN",
6340
- sort,
6341
- minOccurance,
6342
- "Surnames appearing less than 5 times"
6343
- );
7280
+ if (input.note?.trim()) {
7281
+ no.set("NOTE", input.note.trim());
6344
7282
  }
6345
- groupByTimeRanges(range, sort = "group", minOccurance = -1) {
6346
- return this.groupBy(
6347
- {
6348
- ["BIRT.DATE.YEAR"]: {
6349
- getter: (year) => {
6350
- if (!Number(year)) {
6351
- return;
6352
- }
6353
- if (range === 1 /* Year */) {
6354
- return `${Math.floor(Number(year) / range) * range}`;
6355
- }
6356
- return `${Math.floor(Number(year) / range) * range + 1}-${Math.ceil((Number(year) + 1) / range) * range}`;
6357
- }
6358
- }
6359
- },
6360
- sort,
6361
- minOccurance,
6362
- "Time ranges appearing less than 5 times"
6363
- );
7283
+ owner.assign("NO", no);
7284
+ return no;
7285
+ };
7286
+
7287
+ // src/classes/fam.ts
7288
+ var Fam = class extends Common {
7289
+ getFamilyMembers(type) {
7290
+ const familyMembers = new Individuals();
7291
+ this.get(type)?.toList().forEach((item) => {
7292
+ const indiId = item.value;
7293
+ const indi = this._gedcom?.indi(indiId);
7294
+ if (indi) {
7295
+ familyMembers.item(indiId, indi);
7296
+ }
7297
+ });
7298
+ return familyMembers;
6364
7299
  }
6365
- nestedGroupByPlacesAndTimeRanges(sort, minOccurance = -1, uniqueCounting = true) {
6366
- const placesWithYear = this.groupBy(
6367
- (item) => item.getPlaces().map((place) => {
6368
- const date = place.obj?.get("DATE");
6369
- if (date?.YEAR) {
6370
- return `${place.place}, ${date.YEAR}`;
6371
- }
6372
- return `${place.place}, Unknown`;
6373
- }).filter(Boolean),
6374
- sort,
6375
- minOccurance,
6376
- "Places appearing less than 5 times"
6377
- );
6378
- return Object.entries(placesWithYear).reduce(
6379
- (acc, [place, indis]) => {
6380
- setNestedGroup(acc, place, indis, uniqueCounting);
6381
- return acc;
6382
- },
6383
- {}
6384
- );
7300
+ getChildren() {
7301
+ return this.getFamilyMembers("CHIL");
6385
7302
  }
6386
- nestedGroupByTimeRangesAndPlaces(sort, minOccurance = -1, uniqueCounting = true) {
6387
- const placesWithYear = this.groupBy(
6388
- (item) => item.getPlaces().map((place) => {
6389
- const date = place.obj?.get("DATE");
6390
- if (date?.YEAR) {
6391
- return `${date.YEAR}, ${place.place}`;
6392
- }
6393
- return `Unknown, ${place.place}`;
6394
- }).filter(Boolean),
6395
- sort,
6396
- minOccurance,
6397
- "Places appearing less than 5 times"
6398
- );
6399
- return Object.entries(placesWithYear).reduce(
6400
- (acc, [place, indis]) => {
6401
- setNestedGroup(acc, place, indis, uniqueCounting);
6402
- return acc;
6403
- },
6404
- {}
6405
- );
7303
+ getHusband() {
7304
+ return this.getFamilyMembers("HUSB");
6406
7305
  }
6407
- nestedGroupByPlaces(sort, minOccurance = -1, partOrder = "reverse", translate = true, uniqueCounting = true, groupKeyTranslator) {
6408
- const places = this.groupByPlaces(
6409
- sort,
6410
- minOccurance,
6411
- partOrder,
6412
- translate,
6413
- groupKeyTranslator
6414
- );
6415
- return Object.entries(places).reduce(
6416
- (acc, [place, indis]) => {
6417
- setNestedGroup(acc, place, indis, uniqueCounting);
6418
- return acc;
6419
- },
6420
- {}
7306
+ getWife() {
7307
+ return this.getFamilyMembers("WIFE");
7308
+ }
7309
+ getParents() {
7310
+ return this.getHusband().copy().merge(this.getWife());
7311
+ }
7312
+ hasParent(indi) {
7313
+ const indiId = typeof indi === "string" ? indi : indi?.id;
7314
+ return !!indiId && familyHasParent(this, indiId);
7315
+ }
7316
+ hasChild(indi) {
7317
+ const indiId = typeof indi === "string" ? indi : indi?.id;
7318
+ return !!indiId && familyHasChild(this, indiId);
7319
+ }
7320
+ canAddSpouse(indi) {
7321
+ return canAttachAsSpouse(this, indi);
7322
+ }
7323
+ addSpouse(indi) {
7324
+ return attachSpouseToFamily(this, indi);
7325
+ }
7326
+ addChild(child, pedigree, parent) {
7327
+ return attachChildToFamily(
7328
+ this,
7329
+ child,
7330
+ pedigree,
7331
+ parent
6421
7332
  );
6422
7333
  }
6423
- groupByPlaces(sort, minOccurance = -1, partOrder = "reverse", translate = true, groupKeyTranslator) {
6424
- return this.groupBy(
6425
- (item) => item.getPlaces().map((place) => {
6426
- const placeParts = getPlaceParts(place.place || "");
6427
- const {
6428
- leftParts = [],
6429
- town,
6430
- county,
6431
- country
6432
- } = placeParts[0] || {};
6433
- const normalizedParts = [
6434
- ...leftParts,
6435
- town,
6436
- county,
6437
- country
6438
- ].filter(Boolean);
6439
- const orderedParts = partOrder === "original" ? normalizedParts : normalizedParts.toReversed();
6440
- let newPlace = "";
6441
- if (groupKeyTranslator) {
6442
- newPlace = groupKeyTranslator(orderedParts);
6443
- } else if (translate) {
6444
- {
6445
- newPlace = placeTranslator(orderedParts);
6446
- }
6447
- } else {
6448
- newPlace = orderedParts.join(", ");
6449
- }
6450
- if (!newPlace) {
6451
- return void 0;
6452
- }
6453
- return {
6454
- marker: place.place,
6455
- group: newPlace
6456
- };
6457
- }).filter(Boolean),
6458
- sort,
6459
- minOccurance,
6460
- "Places appearing less than 5 times"
7334
+ addFact(input) {
7335
+ return addFamilyFact(this, input);
7336
+ }
7337
+ addNonEvent(input) {
7338
+ return addNonEvent(this, input);
7339
+ }
7340
+ toList() {
7341
+ return new Families().concat(
7342
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7343
+ this.id ? { [this.id]: this } : { ...[this] }
6461
7344
  );
6462
7345
  }
6463
- getFacts() {
6464
- const facts = new List();
6465
- this.values().forEach((indi) => {
6466
- const indiFacts = indi?.getFacts();
6467
- if (indi?.id && indiFacts) {
6468
- facts.merge(indiFacts);
7346
+ };
7347
+ var createFam = (gedcom, id, main, parent) => {
7348
+ return createProxy(
7349
+ new Fam(gedcom, id, main, parent)
7350
+ );
7351
+ };
7352
+
7353
+ // src/classes/fams.ts
7354
+ var Families = class _Families extends List {
7355
+ copy() {
7356
+ return super.copy(_Families);
7357
+ }
7358
+ except(item) {
7359
+ return super.except(item, _Families);
7360
+ }
7361
+ filter(filters) {
7362
+ return super.filter(filters, _Families);
7363
+ }
7364
+ find(filters) {
7365
+ return super.find(filters, _Families);
7366
+ }
7367
+ orderBy(orders) {
7368
+ return super.orderBy(orders, _Families);
7369
+ }
7370
+ getParents() {
7371
+ const persons = new Individuals();
7372
+ this.values().forEach((fam) => {
7373
+ if (fam && fam instanceof Fam) {
7374
+ persons.merge(fam.getParents());
6469
7375
  }
6470
7376
  });
6471
- return facts;
7377
+ return persons;
6472
7378
  }
6473
- isRelativeOf(type, indi, every = false) {
6474
- const usedIndi = typeof indi === "string" ? this.index(0)?.getGedcom()?.indi(indi) : indi;
6475
- let getter;
6476
- if (type === "sibling") {
6477
- getter = "getSiblings";
6478
- }
6479
- if (type === "parent") {
6480
- getter = "getParents";
6481
- }
6482
- if (type === "child") {
6483
- getter = "getChildren";
6484
- }
6485
- if (type === "spouse") {
6486
- getter = "getCoParents";
6487
- }
6488
- if (type === "parentInLaw") {
6489
- getter = "getParentsInLaw";
6490
- }
6491
- if (type === "childInLaw") {
6492
- getter = "getChildrenInLaw";
6493
- }
6494
- if (!usedIndi || !getter) {
6495
- return false;
6496
- }
6497
- const relatives = usedIndi[getter]();
6498
- const thisIds = this.keys();
6499
- if (relatives.length <= 0 || this.length <= 0) {
6500
- return false;
7379
+ getChildren() {
7380
+ const persons = new Individuals();
7381
+ this.values().forEach((fam) => {
7382
+ if (fam && fam instanceof Fam) {
7383
+ persons.merge(fam.getChildren());
7384
+ }
7385
+ });
7386
+ return persons;
7387
+ }
7388
+ toList() {
7389
+ return new _Families().concat(this.getItems());
7390
+ }
7391
+ };
7392
+
7393
+ // src/utils/gedcom-version.ts
7394
+ var normalizeGedcomVersion = (value) => {
7395
+ const trimmed = value?.trim() ?? "";
7396
+ if (trimmed.startsWith("7")) {
7397
+ return "7.0";
7398
+ }
7399
+ return "5.5.1";
7400
+ };
7401
+ var GEDZIP_GEDCOM_ENTRY = "gedcom.ged";
7402
+ var sanitizePathSegment = (name) => name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^\.+/, "") || "file";
7403
+ var extensionFor = (contentType) => {
7404
+ const raw = (contentType || "bin").replace(/^\./, "").toLowerCase();
7405
+ if (raw.includes("/")) {
7406
+ return raw.split("/").pop() || "bin";
7407
+ }
7408
+ return raw || "bin";
7409
+ };
7410
+ var rewriteGedcomFilePaths = (gedcomText, urlToPath) => {
7411
+ const entries = urlToPath instanceof Map ? urlToPath : new Map(Object.entries(urlToPath));
7412
+ let text = gedcomText;
7413
+ entries.forEach((path, url) => {
7414
+ const escaped = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7415
+ text = text.replace(
7416
+ new RegExp(`(^|\\r?\\n)(\\d+ FILE )${escaped}`, "g"),
7417
+ `$1$2${path}`
7418
+ );
7419
+ });
7420
+ return text;
7421
+ };
7422
+ var assignMediaPaths = (mediaFiles) => {
7423
+ const urlToPath = /* @__PURE__ */ new Map();
7424
+ const usedPaths = /* @__PURE__ */ new Set([GEDZIP_GEDCOM_ENTRY]);
7425
+ const files = [];
7426
+ for (const file of mediaFiles) {
7427
+ if (!file.content || !file.url) {
7428
+ continue;
6501
7429
  }
6502
- const filtered = relatives.filter({ id: thisIds });
6503
- if (every) {
6504
- return filtered.length === this.length ? filtered.index(0)?.id || true : false;
7430
+ const ext = extensionFor(file.contentType);
7431
+ const base = sanitizePathSegment(
7432
+ file.imgId || file.title || file.id || "media"
7433
+ );
7434
+ let path = `media/${base}.${ext}`;
7435
+ let suffix = 1;
7436
+ while (usedPaths.has(path)) {
7437
+ path = `media/${base}-${suffix++}.${ext}`;
7438
+ }
7439
+ usedPaths.add(path);
7440
+ urlToPath.set(file.url, path);
7441
+ const marker = "base64,";
7442
+ const idx = file.content.indexOf(marker);
7443
+ if (idx >= 0) {
7444
+ files.push({
7445
+ path,
7446
+ url: file.url,
7447
+ content: file.content.substring(idx + marker.length),
7448
+ base64: true
7449
+ });
7450
+ } else {
7451
+ files.push({
7452
+ path,
7453
+ url: file.url,
7454
+ content: file.content,
7455
+ base64: false
7456
+ });
6505
7457
  }
6506
- return filtered.length > 0 ? filtered.index(0)?.id || true : false;
6507
7458
  }
6508
- isSiblingOf(indi, every = false) {
6509
- return this.isRelativeOf("sibling", indi, every);
7459
+ return { urlToPath, files };
7460
+ };
7461
+ var buildGedzip = async (gedcomText, mediaFiles = []) => {
7462
+ const zip = new JSZip();
7463
+ const { urlToPath, files } = assignMediaPaths(mediaFiles);
7464
+ for (const file of files) {
7465
+ zip.file(file.path, file.content, { base64: file.base64 });
6510
7466
  }
6511
- isSpouseOf(indi, every = false) {
6512
- return this.isRelativeOf("spouse", indi, every);
7467
+ zip.file(GEDZIP_GEDCOM_ENTRY, rewriteGedcomFilePaths(gedcomText, urlToPath));
7468
+ return zip.generateAsync({ type: "uint8array" });
7469
+ };
7470
+
7471
+ // src/utils/gedcom7-enumerations.ts
7472
+ var GEDCOM7_SEX_VALUES = ["M", "F", "U", "X", "N"];
7473
+ var GEDCOM7_PEDI_VALUES = [
7474
+ "adopted",
7475
+ "birth",
7476
+ "foster",
7477
+ "sealing"
7478
+ ];
7479
+ var GEDCOM7_ROLE_VALUES = [
7480
+ "CHIL",
7481
+ "CLERGY",
7482
+ "FATH",
7483
+ "FRIEND",
7484
+ "GODP",
7485
+ "HUSB",
7486
+ "MOTH",
7487
+ "MULTIPLE",
7488
+ "NGHBR",
7489
+ "OFFICIATOR",
7490
+ "OTHER",
7491
+ "PARENT",
7492
+ "SPOU",
7493
+ "WIFE",
7494
+ "WITN"
7495
+ ];
7496
+ var GEDCOM7_RESN_VALUES = [
7497
+ "CONFIDENTIAL",
7498
+ "LOCKED",
7499
+ "PRIVACY"
7500
+ ];
7501
+ var isAllowed = (value, allowed) => allowed.includes(value);
7502
+ var moveToPhrase = (node, phrase) => {
7503
+ const previousValue = node.value;
7504
+ const previousPhrase = node.get("PHRASE");
7505
+ const previousPhraseValue = previousPhrase?.toValue();
7506
+ node.removeValue();
7507
+ if (previousPhrase) {
7508
+ previousPhrase.value = phrase;
7509
+ } else {
7510
+ const phraseNode = createCommon(node.getGedcom(), void 0, node.main);
7511
+ phraseNode.value = phrase;
7512
+ node.set("PHRASE", phraseNode);
6513
7513
  }
6514
- isParentOf(indi, every = false) {
6515
- return this.isRelativeOf("parent", indi, every);
7514
+ return () => {
7515
+ if (previousValue === void 0) {
7516
+ node.removeValue();
7517
+ } else {
7518
+ node.value = previousValue;
7519
+ }
7520
+ if (previousPhrase) {
7521
+ previousPhrase.value = previousPhraseValue;
7522
+ } else {
7523
+ node.remove("PHRASE");
7524
+ }
7525
+ };
7526
+ };
7527
+ var normalizeEnum = (node, allowed, mode, restores) => {
7528
+ const value = node?.toValue();
7529
+ if (!node || typeof value !== "string" || !value.trim()) {
7530
+ return;
6516
7531
  }
6517
- isChildOf(indi, every = false) {
6518
- return this.isRelativeOf("child", indi, every);
7532
+ const normalized = mode === "upper" ? value.trim().toUpperCase() : value.trim().toLowerCase();
7533
+ if (isAllowed(normalized, allowed)) {
7534
+ if (value !== normalized) {
7535
+ const previous = node.value;
7536
+ node.value = normalized;
7537
+ restores.push(() => {
7538
+ node.value = previous;
7539
+ });
7540
+ }
7541
+ return;
6519
7542
  }
6520
- isParentInLawOf(indi, every = false) {
6521
- return this.isRelativeOf("parentInLaw", indi, every);
7543
+ restores.push(moveToPhrase(node, value.trim()));
7544
+ };
7545
+ var applyGedcom7Enumerations = (gedcom) => {
7546
+ const restores = [];
7547
+ gedcom.indis()?.forEach((indi) => {
7548
+ if (!indi) return;
7549
+ normalizeEnum(indi.get("SEX"), GEDCOM7_SEX_VALUES, "upper", restores);
7550
+ normalizeEnum(indi.get("RESN"), GEDCOM7_RESN_VALUES, "upper", restores);
7551
+ indi.get("FAMC")?.toList()?.forEach((famc) => {
7552
+ normalizeEnum(
7553
+ famc?.get("PEDI") ?? famc?.get("PEDT"),
7554
+ GEDCOM7_PEDI_VALUES,
7555
+ "lower",
7556
+ restores
7557
+ );
7558
+ });
7559
+ indi.get("ASSO")?.toList()?.forEach((asso) => {
7560
+ normalizeEnum(
7561
+ asso?.get("ROLE"),
7562
+ GEDCOM7_ROLE_VALUES,
7563
+ "upper",
7564
+ restores
7565
+ );
7566
+ });
7567
+ });
7568
+ gedcom.fams()?.forEach((fam) => {
7569
+ if (!fam) return;
7570
+ normalizeEnum(fam.get("RESN"), GEDCOM7_RESN_VALUES, "upper", restores);
7571
+ fam.get("ASSO")?.toList()?.forEach((asso) => {
7572
+ normalizeEnum(
7573
+ asso?.get("ROLE"),
7574
+ GEDCOM7_ROLE_VALUES,
7575
+ "upper",
7576
+ restores
7577
+ );
7578
+ });
7579
+ });
7580
+ return () => {
7581
+ for (let i = restores.length - 1; i >= 0; i -= 1) {
7582
+ restores[i]?.();
7583
+ }
7584
+ };
7585
+ };
7586
+
7587
+ // src/utils/gedcom7-dates.ts
7588
+ var GEDCOM7_CALENDARS = [
7589
+ "GREGORIAN",
7590
+ "JULIAN",
7591
+ "FRENCH_R",
7592
+ "HEBREW"
7593
+ ];
7594
+ var CALENDAR_PREFIX2 = /^(?<calendar>GREGORIAN|JULIAN|FRENCH_R|HEBREW)\b\s+/i;
7595
+ var parseGedcom7CalendarPrefix = (value) => {
7596
+ const match = value.match(CALENDAR_PREFIX2);
7597
+ if (!match?.groups?.calendar) {
7598
+ return { calendar: void 0, rest: value };
6522
7599
  }
6523
- isChildInLawOf(indi, every = false) {
6524
- return this.isRelativeOf("childInLaw", indi, every);
7600
+ return {
7601
+ calendar: match.groups.calendar.toUpperCase(),
7602
+ rest: value.slice(match[0].length)
7603
+ };
7604
+ };
7605
+ var withGedcom7Calendar = (value, calendar) => {
7606
+ if (!calendar || calendar.toUpperCase() === "GREGORIAN") {
7607
+ return value;
6525
7608
  }
6526
- splitByFamily(type, relativeTo) {
6527
- const splittedList = {};
6528
- const familiesRelativeTo = relativeTo?.get(type !== "Parents" ? "FAMS" : "FAMC")?.toValueList().keys() ?? [];
6529
- let lengthOfIndividuals = 0;
6530
- this.forEach((indi) => {
6531
- const families = indi.get(type === "Spouses" ? "FAMS" : "FAMC")?.toValueList();
6532
- if (families) {
6533
- families.keys().forEach((fKey) => {
6534
- const famKey = fKey;
6535
- if (familiesRelativeTo && !familiesRelativeTo.includes(famKey)) {
6536
- return;
6537
- }
6538
- if (!splittedList[famKey]) {
6539
- splittedList[famKey] = new _Individuals();
6540
- }
6541
- splittedList[famKey]?.append(indi);
6542
- lengthOfIndividuals++;
6543
- });
7609
+ const upper = calendar.toUpperCase();
7610
+ if (GEDCOM7_CALENDARS.includes(upper)) {
7611
+ const { rest } = parseGedcom7CalendarPrefix(value);
7612
+ return `${upper} ${rest}`.trim();
7613
+ }
7614
+ return value;
7615
+ };
7616
+ var applyGedcom7DatePhrases = (gedcom) => {
7617
+ const restores = [];
7618
+ const visitDate = (dateNode) => {
7619
+ if (!dateNode || typeof dateNode.toValue !== "function") {
7620
+ return;
7621
+ }
7622
+ const asDate = dateNode;
7623
+ const hasComponents = !!(asDate.DAY || asDate.MONTH || asDate.YEAR);
7624
+ const raw = dateNode.exportValue?.() ?? dateNode.toValue();
7625
+ if (typeof raw !== "string" || !raw.trim()) {
7626
+ return;
7627
+ }
7628
+ const { calendar, rest } = parseGedcom7CalendarPrefix(raw.trim());
7629
+ const looksStructured = hasComponents || /^(ABT|CAL|EST|BEF|AFT|FROM|TO|BET|INT)(\s|$)/i.test(rest) || /\bAND\b/i.test(rest) || /^\d{1,2}\s+[A-Z]{3}\s+\d{1,4}/i.test(rest) || /^[A-Z]{3}\s+\d{1,4}/i.test(rest) || /^\d{1,4}$/.test(rest);
7630
+ if (looksStructured) {
7631
+ if (calendar && calendar !== "GREGORIAN") {
7632
+ const previous = dateNode.value;
7633
+ const next = withGedcom7Calendar(rest, calendar);
7634
+ if (previous !== next) {
7635
+ dateNode.value = next;
7636
+ restores.push(() => {
7637
+ dateNode.value = previous;
7638
+ });
7639
+ }
6544
7640
  }
6545
- });
6546
- if (type === "Spouses" && relativeTo) {
6547
- const missingFams = difference(
6548
- familiesRelativeTo,
6549
- Object.keys(splittedList)
7641
+ return;
7642
+ }
7643
+ const previousValue = dateNode.value;
7644
+ const previousPhrase = dateNode.get("PHRASE");
7645
+ const previousPhraseValue = previousPhrase?.toValue();
7646
+ dateNode.removeValue();
7647
+ if (previousPhrase) {
7648
+ previousPhrase.value = raw.trim();
7649
+ } else {
7650
+ const phrase = createCommon(
7651
+ dateNode.getGedcom(),
7652
+ void 0,
7653
+ dateNode.main
6550
7654
  );
6551
- if (missingFams.length) {
6552
- missingFams.forEach((fKey) => {
6553
- const famKey = fKey;
6554
- if (familiesRelativeTo && !familiesRelativeTo.includes(famKey)) {
6555
- return;
6556
- }
6557
- const missingChildren = relativeTo.getGedcom()?.fam(famKey)?.getChildren();
6558
- if (!splittedList[famKey] && missingChildren?.length) {
6559
- splittedList[famKey] = new _Individuals();
6560
- }
6561
- });
6562
- }
7655
+ phrase.value = raw.trim();
7656
+ dateNode.set("PHRASE", phrase);
6563
7657
  }
6564
- return {
6565
- items: splittedList,
6566
- lengthOfFamily: Object.keys(splittedList).length,
6567
- lengthOfIndividuals
6568
- };
6569
- }
6570
- getRelativesOnDegree(degree = 0) {
6571
- const persons = new _Individuals();
6572
- this.values().forEach((indi) => {
6573
- if (indi) {
6574
- persons.merge(indi.getRelativesOnLevel(degree));
7658
+ restores.push(() => {
7659
+ if (previousValue === void 0) {
7660
+ dateNode.removeValue();
7661
+ } else {
7662
+ dateNode.value = previousValue;
6575
7663
  }
6576
- });
6577
- return persons;
6578
- }
6579
- getRelativesOnLevel(level = 0, filter) {
6580
- const persons = new _Individuals();
6581
- this.values().forEach((indi) => {
6582
- if (indi) {
6583
- persons.merge(indi.getRelativesOnLevel(level, filter));
7664
+ if (previousPhrase) {
7665
+ previousPhrase.value = previousPhraseValue;
7666
+ } else {
7667
+ dateNode.remove("PHRASE");
6584
7668
  }
6585
7669
  });
6586
- return persons;
6587
- }
6588
- getAscendants(level = 0, filter) {
6589
- const persons = new _Individuals();
6590
- this.values().forEach((indi) => {
6591
- if (indi) {
6592
- persons.merge(indi.getAscendants(level, filter));
6593
- }
7670
+ };
7671
+ const walk = (node) => {
7672
+ if (!node) return;
7673
+ node.get("DATE")?.toList()?.forEach((item) => visitDate(item));
7674
+ node.get("SDATE")?.toList()?.forEach((item) => visitDate(item));
7675
+ };
7676
+ gedcom.indis()?.forEach((indi) => {
7677
+ if (!indi) return;
7678
+ walk(indi);
7679
+ [
7680
+ "BIRT",
7681
+ "DEAT",
7682
+ "CHR",
7683
+ "BAPM",
7684
+ "BURI",
7685
+ "CREM",
7686
+ "ADOP",
7687
+ "EVEN",
7688
+ "RESI",
7689
+ "OCCU",
7690
+ "MARR"
7691
+ ].forEach((tag) => {
7692
+ indi.get(tag)?.toList()?.forEach((event) => walk(event));
6594
7693
  });
6595
- return persons;
6596
- }
6597
- getDescendants(level = 0, filter) {
6598
- const persons = new _Individuals();
6599
- this.values().forEach((indi) => {
6600
- if (indi) {
6601
- persons.merge(indi.getDescendants(level, filter));
6602
- }
7694
+ });
7695
+ gedcom.fams()?.forEach((fam) => {
7696
+ if (!fam) return;
7697
+ ["MARR", "DIV", "ENGA", "ANUL", "EVEN"].forEach((tag) => {
7698
+ fam.get(tag)?.toList()?.forEach((event) => walk(event));
6603
7699
  });
6604
- return persons;
7700
+ });
7701
+ return () => {
7702
+ for (let i = restores.length - 1; i >= 0; i -= 1) {
7703
+ restores[i]?.();
7704
+ }
7705
+ };
7706
+ };
7707
+
7708
+ // src/utils/uid.ts
7709
+ var createGedcomUid = () => {
7710
+ const cryptoObj = typeof globalThis !== "undefined" ? globalThis.crypto : void 0;
7711
+ if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
7712
+ return cryptoObj.randomUUID();
7713
+ }
7714
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
7715
+ const rand = Math.random() * 16 | 0;
7716
+ const value = char === "x" ? rand : rand & 3 | 8;
7717
+ return value.toString(16);
7718
+ });
7719
+ };
7720
+
7721
+ // src/utils/gedcom7-metadata.ts
7722
+ var GEDCOM_MONTHS2 = [
7723
+ "JAN",
7724
+ "FEB",
7725
+ "MAR",
7726
+ "APR",
7727
+ "MAY",
7728
+ "JUN",
7729
+ "JUL",
7730
+ "AUG",
7731
+ "SEP",
7732
+ "OCT",
7733
+ "NOV",
7734
+ "DEC"
7735
+ ];
7736
+ var formatGedcom7Timestamp = (date = /* @__PURE__ */ new Date()) => {
7737
+ const day = String(date.getUTCDate());
7738
+ const month = GEDCOM_MONTHS2[date.getUTCMonth()];
7739
+ const year = String(date.getUTCFullYear());
7740
+ const hh = String(date.getUTCHours()).padStart(2, "0");
7741
+ const mm = String(date.getUTCMinutes()).padStart(2, "0");
7742
+ const ss = String(date.getUTCSeconds()).padStart(2, "0");
7743
+ return {
7744
+ date: `${day} ${month} ${year}`,
7745
+ time: `${hh}:${mm}:${ss}Z`
7746
+ };
7747
+ };
7748
+ var ensureMetaDate = (gedcom, record, tag, when, restores) => {
7749
+ if (record.get(tag)) {
7750
+ return;
6605
7751
  }
6606
- getAllAscendants(individuals) {
6607
- const persons = new _Individuals();
6608
- this.values().forEach((indi) => {
6609
- if (indi) {
6610
- persons.merge(indi.getAllAscendants(individuals));
6611
- }
6612
- });
6613
- return persons;
7752
+ const { date, time } = formatGedcom7Timestamp(when);
7753
+ const meta = createCommon(gedcom, void 0, record);
7754
+ meta.type = tag;
7755
+ const dateNode = createCommonDate(gedcom, void 0, record, meta);
7756
+ dateNode.type = "DATE";
7757
+ dateNode.value = date;
7758
+ dateNode.set("TIME", time);
7759
+ meta.set("DATE", dateNode);
7760
+ record.set(tag, meta);
7761
+ restores.push(() => {
7762
+ record.remove(tag);
7763
+ });
7764
+ };
7765
+ var ensureUid = (record, restores) => {
7766
+ const existing = record.get("UID")?.toValue();
7767
+ if (typeof existing === "string" && existing.trim()) {
7768
+ return;
6614
7769
  }
6615
- getAllDescendants(individuals, containDescendantsInLaw = false) {
6616
- const persons = new _Individuals();
6617
- this.values().forEach((indi) => {
6618
- if (indi) {
6619
- persons.merge(
6620
- indi.getAllDescendants(individuals, containDescendantsInLaw)
6621
- );
6622
- }
6623
- });
6624
- return persons;
7770
+ const uid = createGedcomUid();
7771
+ record.set("UID", uid);
7772
+ restores.push(() => {
7773
+ record.remove("UID");
7774
+ });
7775
+ };
7776
+ var applyGedcom7RecordMetadata = (gedcom, options) => {
7777
+ const restores = [];
7778
+ const now = /* @__PURE__ */ new Date();
7779
+ const visit = (record) => {
7780
+ if (!record?.id) {
7781
+ return;
7782
+ }
7783
+ ensureUid(record, restores);
7784
+ ensureMetaDate(gedcom, record, "CREA", now, restores);
7785
+ ensureMetaDate(gedcom, record, "CHAN", now, restores);
7786
+ };
7787
+ gedcom.indis()?.forEach((indi) => visit(indi));
7788
+ gedcom.fams()?.forEach((fam) => visit(fam));
7789
+ gedcom.objes()?.forEach((obje) => visit(obje));
7790
+ gedcom.sours()?.forEach((sour) => visit(sour));
7791
+ gedcom.repos()?.forEach((repo) => visit(repo));
7792
+ gedcom.subms()?.forEach((subm) => visit(subm));
7793
+ gedcom.snotes()?.forEach((note) => visit(note));
7794
+ return () => {
7795
+ for (let i = restores.length - 1; i >= 0; i -= 1) {
7796
+ restores[i]?.();
7797
+ }
7798
+ };
7799
+ };
7800
+
7801
+ // src/utils/gedcom7-schema.ts
7802
+ var TREEVIZ_EXTENSION_BASE_URI = "https://treeviz.com/gedcom";
7803
+ var TREEVIZ_EXTENSION_URIS = {
7804
+ _ORIGHEAD: `${TREEVIZ_EXTENSION_BASE_URI}#_ORIGHEAD`,
7805
+ _TREE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREE`,
7806
+ _TID: `${TREEVIZ_EXTENSION_BASE_URI}#_TID`,
7807
+ _PRIM: `${TREEVIZ_EXTENSION_BASE_URI}#_PRIM`,
7808
+ _FREL: `${TREEVIZ_EXTENSION_BASE_URI}#_FREL`,
7809
+ _MREL: `${TREEVIZ_EXTENSION_BASE_URI}#_MREL`,
7810
+ _SREL: `${TREEVIZ_EXTENSION_BASE_URI}#_SREL`,
7811
+ _UID: `${TREEVIZ_EXTENSION_BASE_URI}#_UID`,
7812
+ _WLNK: `${TREEVIZ_EXTENSION_BASE_URI}#_WLNK`,
7813
+ _MTTAG: `${TREEVIZ_EXTENSION_BASE_URI}#_MTTAG`,
7814
+ _MTCAT: `${TREEVIZ_EXTENSION_BASE_URI}#_MTCAT`,
7815
+ _CLON: `${TREEVIZ_EXTENSION_BASE_URI}#_CLON`,
7816
+ _MSER: `${TREEVIZ_EXTENSION_BASE_URI}#_MSER`,
7817
+ _OID: `${TREEVIZ_EXTENSION_BASE_URI}#_OID`,
7818
+ _LKID: `${TREEVIZ_EXTENSION_BASE_URI}#_LKID`,
7819
+ _PHOTO_RIN: `${TREEVIZ_EXTENSION_BASE_URI}#_PHOTO_RIN`,
7820
+ _EXPORTED_FROM_SITE_ID: `${TREEVIZ_EXTENSION_BASE_URI}#_EXPORTED_FROM_SITE_ID`,
7821
+ _FS_ID: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_ID`,
7822
+ _FS_LINK: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_LINK`,
7823
+ _FS_MATCH: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_MATCH`,
7824
+ _FS_SOUR: `${TREEVIZ_EXTENSION_BASE_URI}#_FS_SOUR`,
7825
+ _IS_FS: `${TREEVIZ_EXTENSION_BASE_URI}#_IS_FS`,
7826
+ _LABEL: `${TREEVIZ_EXTENSION_BASE_URI}#_LABEL`,
7827
+ _MILT: `${TREEVIZ_EXTENSION_BASE_URI}#_MILT`,
7828
+ _MILTID: `${TREEVIZ_EXTENSION_BASE_URI}#_MILTID`,
7829
+ _ORIG: `${TREEVIZ_EXTENSION_BASE_URI}#_ORIG`,
7830
+ _ENV: `${TREEVIZ_EXTENSION_BASE_URI}#_ENV`,
7831
+ _TREEVIZ_SETTINGS: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_SETTINGS`,
7832
+ _TREEVIZ_VIEW: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_VIEW`,
7833
+ _TREEVIZ_DETECTIVE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_DETECTIVE`,
7834
+ _TREEVIZ_DETECTIVE_STATE: `${TREEVIZ_EXTENSION_BASE_URI}#_TREEVIZ_DETECTIVE_STATE`
7835
+ };
7836
+ var parseTagDefinition = (payload) => {
7837
+ const trimmed = payload.trim();
7838
+ const space = trimmed.indexOf(" ");
7839
+ if (space <= 0) {
7840
+ return void 0;
6625
7841
  }
6626
- getSiblings() {
6627
- const persons = new _Individuals();
6628
- this.values().forEach((indi) => {
6629
- if (indi) {
6630
- persons.merge(indi.getSiblings());
6631
- }
6632
- });
6633
- return persons;
7842
+ const tag = trimmed.slice(0, space).trim();
7843
+ const uri = trimmed.slice(space + 1).trim();
7844
+ if (!tag || !uri) {
7845
+ return void 0;
6634
7846
  }
6635
- getChildren() {
6636
- const persons = new _Individuals();
6637
- this.values().forEach((indi) => {
6638
- if (indi) {
6639
- persons.merge(indi.getChildren());
6640
- }
6641
- });
6642
- return persons;
7847
+ return { tag, uri };
7848
+ };
7849
+ var getExtensionSchema = (gedcom) => {
7850
+ const map = /* @__PURE__ */ new Map();
7851
+ const schma = gedcom.get("HEAD")?.get("SCHMA");
7852
+ if (!schma) {
7853
+ return map;
6643
7854
  }
6644
- getParents() {
6645
- const persons = new _Individuals();
6646
- this.values().forEach((indi) => {
6647
- if (indi) {
6648
- persons.merge(indi.getParents());
6649
- }
6650
- });
6651
- return persons;
7855
+ schma.get("TAG")?.toList()?.forEach((tagNode) => {
7856
+ const payload = tagNode?.toValue();
7857
+ if (typeof payload !== "string") {
7858
+ return;
7859
+ }
7860
+ const parsed = parseTagDefinition(payload);
7861
+ if (parsed) {
7862
+ map.set(parsed.tag.toUpperCase(), parsed.uri);
7863
+ }
7864
+ });
7865
+ return map;
7866
+ };
7867
+ var ensureSchemaNode = (gedcom) => {
7868
+ const head = gedcom.get("HEAD");
7869
+ if (!head) {
7870
+ return void 0;
6652
7871
  }
6653
- getCoParents() {
6654
- const persons = new _Individuals();
6655
- this.values().forEach((indi) => {
6656
- if (indi) {
6657
- persons.merge(indi.getCoParents());
7872
+ let schma = head.get("SCHMA");
7873
+ if (!schma) {
7874
+ schma = createCommon(gedcom, void 0, head);
7875
+ head.set("SCHMA", schma);
7876
+ }
7877
+ return schma;
7878
+ };
7879
+ var registerExtensionTag = (gedcom, tag, uri) => {
7880
+ const normalizedTag = tag.trim().toUpperCase();
7881
+ const normalizedUri = uri.trim();
7882
+ if (!normalizedTag.startsWith("_") || !normalizedUri) {
7883
+ return void 0;
7884
+ }
7885
+ const schma = ensureSchemaNode(gedcom);
7886
+ if (!schma) {
7887
+ return void 0;
7888
+ }
7889
+ const payload = `${normalizedTag} ${normalizedUri}`;
7890
+ const existingList = schma.get("TAG")?.toList();
7891
+ const existing = existingList?.values().find((node) => {
7892
+ const value = node?.toValue();
7893
+ return typeof value === "string" && value.trim().toUpperCase().startsWith(`${normalizedTag} `);
7894
+ });
7895
+ if (existing) {
7896
+ existing.value = payload;
7897
+ return existing;
7898
+ }
7899
+ const tagNode = createCommon(gedcom, void 0, schma);
7900
+ tagNode.value = payload;
7901
+ schma.assign("TAG", tagNode);
7902
+ return tagNode;
7903
+ };
7904
+ var ensureExtensionSchema = (gedcom, extraTags) => {
7905
+ const head = gedcom.get("HEAD");
7906
+ const hadSchma = !!head?.get("SCHMA");
7907
+ const previousPayloads = head?.get("SCHMA")?.get("TAG")?.toList()?.values().map((node) => ({
7908
+ node,
7909
+ value: node?.toValue()
7910
+ })) ?? [];
7911
+ const tags = /* @__PURE__ */ new Set([
7912
+ ...Object.keys(TREEVIZ_EXTENSION_URIS),
7913
+ ...(extraTags ?? []).map((tag) => tag.toUpperCase())
7914
+ ]);
7915
+ tags.forEach((tag) => {
7916
+ const uri = TREEVIZ_EXTENSION_URIS[tag] ?? `${TREEVIZ_EXTENSION_BASE_URI}#${tag}`;
7917
+ if (tag.startsWith("_")) {
7918
+ registerExtensionTag(gedcom, tag, uri);
7919
+ }
7920
+ });
7921
+ return () => {
7922
+ if (!head) {
7923
+ return;
7924
+ }
7925
+ if (!hadSchma) {
7926
+ head.remove("SCHMA");
7927
+ return;
7928
+ }
7929
+ const schma = head.get("SCHMA");
7930
+ const list = schma?.get("TAG")?.toList();
7931
+ const keep = new Set(
7932
+ previousPayloads.map(
7933
+ (item) => typeof item.value === "string" ? item.value : void 0
7934
+ ).filter((value) => !!value)
7935
+ );
7936
+ list?.values().forEach((node) => {
7937
+ const value = node?.toValue();
7938
+ if (typeof value === "string" && !keep.has(value) && node) {
7939
+ list.delete(node);
6658
7940
  }
6659
7941
  });
6660
- return persons;
6661
- }
6662
- getSpouses() {
6663
- const persons = new _Individuals();
6664
- this.values().forEach((indi) => {
6665
- if (indi) {
6666
- persons.merge(indi.getCoParents());
7942
+ previousPayloads.forEach(({ node, value }) => {
7943
+ if (node && value !== void 0) {
7944
+ node.value = value;
6667
7945
  }
6668
7946
  });
6669
- return persons;
6670
- }
6671
- toName() {
6672
- return super.toProp("NAME")?.toValue();
7947
+ };
7948
+ };
7949
+
7950
+ // package.json
7951
+ var package_default = {
7952
+ version: "2.1.0"};
7953
+
7954
+ // src/utils/get-product-details.ts
7955
+ var isDevelopment = () => {
7956
+ return !process.env.NODE_ENV || process.env.NODE_ENV === "development";
7957
+ };
7958
+ var getVersion = () => package_default.version;
7959
+
7960
+ // src/utils/multimedia.ts
7961
+ var inferMediaForm = (file, fallback = "bin") => {
7962
+ const withoutQuery = file.split("?")[0] || file;
7963
+ const ext = getFileExtension(withoutQuery);
7964
+ if (ext) {
7965
+ return ext.toLowerCase() === "jpeg" ? "jpg" : ext.toLowerCase();
6673
7966
  }
6674
- toList() {
6675
- return new _Individuals().concat(this.getItems());
7967
+ return fallback;
7968
+ };
7969
+ var mergeMediaLists = (...lists) => {
7970
+ const merged = {};
7971
+ for (const list of lists) {
7972
+ if (!list) continue;
7973
+ Object.assign(merged, list);
6676
7974
  }
7975
+ return merged;
6677
7976
  };
6678
7977
 
6679
- // src/classes/fam.ts
6680
- var Fam = class extends Common {
6681
- getFamilyMembers(type) {
6682
- const familyMembers = new Individuals();
6683
- this.get(type)?.toList().forEach((item) => {
6684
- const indiId = item.value;
6685
- const indi = this._gedcom?.indi(indiId);
6686
- if (indi) {
6687
- familyMembers.item(indiId, indi);
6688
- }
6689
- });
6690
- return familyMembers;
6691
- }
6692
- getChildren() {
6693
- return this.getFamilyMembers("CHIL");
7978
+ // src/classes/note.ts
7979
+ var CommonNote = class extends Common {
7980
+ constructor(gedcom, id, main, parent) {
7981
+ super(gedcom, id, main, parent);
7982
+ if (!id) {
7983
+ delete this.id;
7984
+ }
6694
7985
  }
6695
- getHusband() {
6696
- return this.getFamilyMembers("HUSB");
7986
+ set value(value) {
7987
+ const [note, ...contents] = value?.split(/\r?\n/) ?? [];
7988
+ this._value = note;
7989
+ if (contents.length) {
7990
+ const newContents = new List();
7991
+ contents.forEach((c, i) => {
7992
+ const newContent = createCommon(
7993
+ this._gedcom,
7994
+ void 0,
7995
+ this.main
7996
+ );
7997
+ newContent.id = `@U${i}@`;
7998
+ newContent.value = c;
7999
+ newContents.append(newContent);
8000
+ });
8001
+ const firstItem = newContents.index(0);
8002
+ if (firstItem) {
8003
+ if (newContents.length === 1) {
8004
+ this.set("CONT", firstItem);
8005
+ } else {
8006
+ this.set("CONT", newContents);
8007
+ }
8008
+ }
8009
+ }
6697
8010
  }
6698
- getWife() {
6699
- return this.getFamilyMembers("WIFE");
8011
+ get value() {
8012
+ const contents = this.get("CONT")?.toList().map((content) => content.value).join("\n");
8013
+ if (contents) {
8014
+ return `${this._value}
8015
+ ${contents}`;
8016
+ }
8017
+ return this._value;
6700
8018
  }
6701
- getParents() {
6702
- return this.getHusband().copy().merge(this.getWife());
8019
+ exportValue() {
8020
+ return this._value;
6703
8021
  }
6704
- toList() {
6705
- return new Families().concat(
6706
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6707
- this.id ? { [this.id]: this } : { ...[this] }
8022
+ };
8023
+ var createCommonNote = (gedcom, id, main, parent) => {
8024
+ return createProxy(
8025
+ new CommonNote(gedcom, id, main, parent)
8026
+ );
8027
+ };
8028
+
8029
+ // src/classes/obje.ts
8030
+ var Obje = class extends Common {
8031
+ standardizeMedia(namespace, override = true, urlGetter, gedcomVersion) {
8032
+ if (!this._gedcom) {
8033
+ return this;
8034
+ }
8035
+ const rin = this?.get("RIN")?.toValue();
8036
+ const clone = this?.get("_CLON._OID")?.toValue();
8037
+ const mser = this?.get("_MSER._LKID")?.toValue();
8038
+ const title = this?.get("FILE.TITL")?.toValue() ?? this?.get("TITL")?.toValue() ?? "";
8039
+ const note = this?.get("FILE.NOTE")?.toValue() ?? this?.get("NOTE")?.toValue() ?? "";
8040
+ const formRaw = this?.get("FILE.FORM")?.toValue() ?? this?.get("FORM")?.toValue();
8041
+ const mediType = this?.get("FILE.FORM.TYPE")?.toValue() ?? this?.get("FORM.TYPE")?.toValue() ?? this?.get("MEDI")?.toValue();
8042
+ const file = this?.get("FILE")?.toValue();
8043
+ const imgId = rin || clone || mser;
8044
+ const url = file || namespace && urlGetter?.(namespace, imgId);
8045
+ if (!url) {
8046
+ return this;
8047
+ }
8048
+ const version = normalizeGedcomVersion(
8049
+ gedcomVersion ?? this._gedcom.getGedcomVersion?.()
6708
8050
  );
8051
+ const form = formRaw || inferMediaForm(String(url));
8052
+ const newObject = createObje(this._gedcom, this.id, this.main);
8053
+ if (!override) {
8054
+ Object.assign(newObject, this);
8055
+ }
8056
+ const fileNode = createCommon(this._gedcom, void 0, this.main);
8057
+ fileNode.value = url;
8058
+ if (version === "7.0") {
8059
+ const formNode = createCommon(this._gedcom, void 0, fileNode);
8060
+ formNode.value = form;
8061
+ if (mediType) {
8062
+ formNode.set("TYPE", String(mediType));
8063
+ }
8064
+ fileNode.set("FORM", formNode);
8065
+ if (title) {
8066
+ fileNode.set("TITL", String(title));
8067
+ }
8068
+ if (note) {
8069
+ fileNode.set("NOTE", String(note));
8070
+ }
8071
+ newObject.set("FILE", fileNode);
8072
+ } else {
8073
+ newObject.set("FILE", fileNode);
8074
+ newObject.set("FORM", form);
8075
+ if (mediType) {
8076
+ newObject.set("MEDI", String(mediType));
8077
+ }
8078
+ if (title) {
8079
+ newObject.set("TITL", String(title));
8080
+ if (!note) {
8081
+ newObject.set("NOTE", String(title));
8082
+ }
8083
+ }
8084
+ if (note) {
8085
+ newObject.set("NOTE", String(note));
8086
+ if (!title) {
8087
+ newObject.set("TITL", String(note));
8088
+ }
8089
+ }
8090
+ }
8091
+ const prim = this.get("_PRIM")?.toValue();
8092
+ if (prim === "Y" || prim === "N") {
8093
+ newObject.set("_PRIM", prim);
8094
+ }
8095
+ const photoRin = this.get("_PHOTO_RIN")?.toValue();
8096
+ if (rin) {
8097
+ newObject.set("RIN", String(rin));
8098
+ }
8099
+ if (photoRin) {
8100
+ newObject.set("_PHOTO_RIN", String(photoRin));
8101
+ }
8102
+ const clonNode = this.get("_CLON");
8103
+ if (clonNode) {
8104
+ newObject.set("_CLON", clonNode);
8105
+ }
8106
+ const mserNode = this.get("_MSER");
8107
+ if (mserNode) {
8108
+ newObject.set("_MSER", mserNode);
8109
+ }
8110
+ const oidNode = this.get("_OID");
8111
+ if (oidNode && !newObject.get("_OID")) {
8112
+ newObject.set("_OID", oidNode);
8113
+ }
8114
+ const lkidNode = this.get("_LKID");
8115
+ if (lkidNode && !newObject.get("_LKID")) {
8116
+ newObject.set("_LKID", lkidNode);
8117
+ }
8118
+ if (override) {
8119
+ this.remove("FILE");
8120
+ this.remove("FORM");
8121
+ this.remove("MEDI");
8122
+ this.remove("TITL");
8123
+ this.remove("NOTE");
8124
+ Object.assign(this, newObject);
8125
+ return this;
8126
+ }
8127
+ return newObject;
6709
8128
  }
6710
8129
  };
6711
- var createFam = (gedcom, id, main, parent) => {
8130
+ var createObje = (gedcom, id, main, parent) => {
6712
8131
  return createProxy(
6713
- new Fam(gedcom, id, main, parent)
8132
+ new Obje(gedcom, id, main, parent)
6714
8133
  );
6715
8134
  };
6716
8135
 
6717
- // src/classes/fams.ts
6718
- var Families = class _Families extends List {
8136
+ // src/classes/objes.ts
8137
+ var Objects = class _Objects extends List {
6719
8138
  copy() {
6720
- return super.copy(_Families);
6721
- }
6722
- except(item) {
6723
- return super.except(item, _Families);
6724
- }
6725
- filter(filters) {
6726
- return super.filter(filters, _Families);
6727
- }
6728
- find(filters) {
6729
- return super.find(filters, _Families);
6730
- }
6731
- orderBy(orders) {
6732
- return super.orderBy(orders, _Families);
6733
- }
6734
- getParents() {
6735
- const persons = new Individuals();
6736
- this.values().forEach((fam) => {
6737
- if (fam && fam instanceof Fam) {
6738
- persons.merge(fam.getParents());
6739
- }
6740
- });
6741
- return persons;
6742
- }
6743
- getChildren() {
6744
- const persons = new Individuals();
6745
- this.values().forEach((fam) => {
6746
- if (fam && fam instanceof Fam) {
6747
- persons.merge(fam.getChildren());
6748
- }
8139
+ const newList = new _Objects();
8140
+ this.entries().forEach(([key, value]) => {
8141
+ newList.item(key, value);
6749
8142
  });
6750
- return persons;
8143
+ return newList;
6751
8144
  }
6752
- toList() {
6753
- return new _Families().concat(this.getItems());
8145
+ except(item) {
8146
+ return this.copy().delete(item);
6754
8147
  }
6755
8148
  };
6756
8149
 
6757
- // package.json
6758
- var package_default = {
6759
- version: "2.0.10"};
6760
-
6761
- // src/utils/get-product-details.ts
6762
- var isDevelopment = () => {
6763
- return !process.env.NODE_ENV || process.env.NODE_ENV === "development";
6764
- };
6765
- var getVersion = () => package_default.version;
6766
-
6767
8150
  // src/classes/gedcom.ts
6768
8151
  var isObjectPatch = (value) => {
6769
8152
  return !!value && typeof value === "object" && !Array.isArray(value);
@@ -6959,6 +8342,189 @@ var GedCom = class extends Common {
6959
8342
  fams() {
6960
8343
  return this.getList("@@FAM");
6961
8344
  }
8345
+ nextIndiKey() {
8346
+ const ids = [];
8347
+ this.indis()?.forEach((_indi, id) => {
8348
+ ids.push(String(id));
8349
+ });
8350
+ return nextRecordId(ids, "I");
8351
+ }
8352
+ nextFamKey() {
8353
+ const ids = [];
8354
+ this.fams()?.forEach((_fam, id) => {
8355
+ ids.push(String(id));
8356
+ });
8357
+ return nextRecordId(ids, "F");
8358
+ }
8359
+ createIndividual() {
8360
+ const existing = this.indis();
8361
+ const indis = existing ?? new Individuals();
8362
+ if (!existing) {
8363
+ this.set("@@INDI", indis);
8364
+ }
8365
+ const id = this.nextIndiKey();
8366
+ const indi = createIndi(this, id);
8367
+ indi.type = "INDI";
8368
+ if (this.getGedcomVersion() === "7.0") {
8369
+ indi.set("UID", createGedcomUid());
8370
+ }
8371
+ indis.item(id, indi);
8372
+ return indi;
8373
+ }
8374
+ createFamily() {
8375
+ const existing = this.fams();
8376
+ const fams = existing ?? new Families();
8377
+ if (!existing) {
8378
+ this.set("@@FAM", fams);
8379
+ }
8380
+ const id = this.nextFamKey();
8381
+ const fam = createFam(this, id);
8382
+ fam.type = "FAM";
8383
+ if (this.getGedcomVersion() === "7.0") {
8384
+ fam.set("UID", createGedcomUid());
8385
+ }
8386
+ fams.item(id, fam);
8387
+ return fam;
8388
+ }
8389
+ nextObjeKey() {
8390
+ const ids = [];
8391
+ this.objes()?.forEach((_obje, id) => {
8392
+ ids.push(String(id));
8393
+ });
8394
+ return nextRecordId(ids, "O");
8395
+ }
8396
+ /**
8397
+ * Create a top-level multimedia record (`0 @On@ OBJE`) with FILE/FORM/TITL.
8398
+ * GEDCOM 7 uses nested `FILE → FORM [→ TYPE]`; 5.5.1 uses sibling FORM/TITL.
8399
+ */
8400
+ createMultimediaRecord(input) {
8401
+ const existing = this.objes();
8402
+ const objes = existing ?? new Objects();
8403
+ if (!existing) {
8404
+ this.set("@@OBJE", objes);
8405
+ }
8406
+ const id = this.nextObjeKey();
8407
+ const obje = createObje(this, id);
8408
+ obje.type = "OBJE";
8409
+ objes.item(id, obje);
8410
+ const version = normalizeGedcomVersion(
8411
+ input.gedcomVersion ?? this.getGedcomVersion()
8412
+ );
8413
+ const form = input.form || inferMediaForm(input.file);
8414
+ const fileNode = createCommon(this, void 0, obje);
8415
+ fileNode.value = input.file;
8416
+ if (version === "7.0") {
8417
+ const formNode = createCommon(
8418
+ this,
8419
+ void 0,
8420
+ fileNode
8421
+ );
8422
+ formNode.value = form;
8423
+ if (input.mediType) {
8424
+ formNode.set("TYPE", input.mediType);
8425
+ }
8426
+ fileNode.set("FORM", formNode);
8427
+ if (input.title) {
8428
+ fileNode.set("TITL", input.title);
8429
+ }
8430
+ obje.set("FILE", fileNode);
8431
+ } else {
8432
+ obje.set("FILE", fileNode);
8433
+ obje.set("FORM", form);
8434
+ if (input.mediType) {
8435
+ obje.set("MEDI", input.mediType);
8436
+ }
8437
+ if (input.title) {
8438
+ obje.set("TITL", input.title);
8439
+ }
8440
+ }
8441
+ if (input.primary) {
8442
+ obje.set("_PRIM", "Y");
8443
+ }
8444
+ if (normalizeGedcomVersion(
8445
+ input.gedcomVersion ?? this.getGedcomVersion()
8446
+ ) === "7.0") {
8447
+ obje.set("UID", createGedcomUid());
8448
+ }
8449
+ return obje;
8450
+ }
8451
+ nextSnoteKey() {
8452
+ const ids = [];
8453
+ this.snotes()?.forEach((_note, id) => {
8454
+ ids.push(String(id));
8455
+ });
8456
+ return nextRecordId(ids, "N");
8457
+ }
8458
+ snotes() {
8459
+ return this.getList("@@SNOTE");
8460
+ }
8461
+ snote(index) {
8462
+ return this.getMain(this.snotes(), index);
8463
+ }
8464
+ /**
8465
+ * Create a top-level shared note record (`0 @Nn@ SNOTE` for GEDCOM 7).
8466
+ */
8467
+ createSharedNote(text) {
8468
+ const existing = this.snotes();
8469
+ const notes = existing ?? new List();
8470
+ if (!existing) {
8471
+ this.set("@@SNOTE", notes);
8472
+ }
8473
+ const id = this.nextSnoteKey();
8474
+ const note = createCommonNote(this, id);
8475
+ note.type = "SNOTE";
8476
+ note.value = text;
8477
+ if (this.getGedcomVersion() === "7.0") {
8478
+ note.set("UID", createGedcomUid());
8479
+ }
8480
+ notes.item(id, note);
8481
+ return note;
8482
+ }
8483
+ registerExtensionTag(tag, uri) {
8484
+ return registerExtensionTag(this, tag, uri);
8485
+ }
8486
+ getExtensionSchema() {
8487
+ return getExtensionSchema(this);
8488
+ }
8489
+ ensureExtensionSchema(extraTags) {
8490
+ ensureExtensionSchema(this, extraTags);
8491
+ return getExtensionSchema(this);
8492
+ }
8493
+ /**
8494
+ * Collect multimedia descriptors via each individual's `multimedia()`.
8495
+ */
8496
+ async collectMultimedia(options) {
8497
+ const people = [];
8498
+ if (options?.indiIds?.length) {
8499
+ options.indiIds.forEach((id) => {
8500
+ const indi = this.indi(id);
8501
+ if (indi) {
8502
+ people.push(indi);
8503
+ }
8504
+ });
8505
+ } else {
8506
+ this.indis()?.forEach((indi) => {
8507
+ if (indi) {
8508
+ people.push(indi);
8509
+ }
8510
+ });
8511
+ }
8512
+ const lists = await Promise.all(
8513
+ people.map((indi) => indi.multimedia(options?.namespace))
8514
+ );
8515
+ return mergeMediaLists(...lists);
8516
+ }
8517
+ /**
8518
+ * Serialize as GEDCOM 7 and pack a FamilySearch GEDZIP (`.gdz`).
8519
+ * Media bytes must be supplied by the caller (cache/fetch outside the parser).
8520
+ */
8521
+ async toGedzip(options) {
8522
+ const text = this.toGedcom(void 0, 0, {
8523
+ ...options,
8524
+ gedcomVersion: "7.0"
8525
+ });
8526
+ return buildGedzip(text, options?.media ?? []);
8527
+ }
6962
8528
  objes() {
6963
8529
  return this.getList("@@OBJE");
6964
8530
  }
@@ -7043,18 +8609,70 @@ var GedCom = class extends Common {
7043
8609
  });
7044
8610
  return lists;
7045
8611
  }
7046
- getDownloadHeader() {
8612
+ getGedcomVersion() {
8613
+ const raw = this.get("HEAD")?.get("GEDC")?.get("VERS")?.toValue();
8614
+ return normalizeGedcomVersion(
8615
+ typeof raw === "string" ? raw : void 0
8616
+ );
8617
+ }
8618
+ /** Rewrite HEAD.GEDC (and CHAR/FORM) for the requested export version. */
8619
+ applyExportVersion(version) {
8620
+ const head = this.get("HEAD");
8621
+ if (!head) {
8622
+ return;
8623
+ }
8624
+ this.applyGedcomSpecToHead(head, normalizeGedcomVersion(version));
8625
+ }
8626
+ applyGedcomSpecToHead(head, version) {
8627
+ const previousGedc = head.get("GEDC");
8628
+ const previousForm = previousGedc?.get("FORM")?.toValue();
8629
+ const previousChar = head.get("CHAR")?.toValue();
8630
+ head.remove("GEDC");
8631
+ const gedc = head.set("GEDC", "");
8632
+ if (!gedc) {
8633
+ return;
8634
+ }
8635
+ gedc.set("VERS", version);
8636
+ if (version === "7.0") {
8637
+ head.remove("CHAR");
8638
+ return;
8639
+ }
8640
+ gedc.set(
8641
+ "FORM",
8642
+ typeof previousForm === "string" && previousForm ? previousForm : "LINEAGE-LINKED"
8643
+ );
8644
+ if (!head.get("CHAR")?.toValue()) {
8645
+ head.set(
8646
+ "CHAR",
8647
+ typeof previousChar === "string" && previousChar ? previousChar : "UTF-8"
8648
+ );
8649
+ }
8650
+ }
8651
+ getDownloadHeader(gedcomVersion) {
7047
8652
  const newHead = createCommon();
7048
8653
  Object.assign(newHead, this.get("HEAD") ?? {});
8654
+ this.applyGedcomSpecToHead(
8655
+ newHead,
8656
+ gedcomVersion ?? this.getGedcomVersion()
8657
+ );
8658
+ const existingSour = this.get("HEAD")?.get("SOUR");
8659
+ const existingTreeName = existingSour?.get("_TREE")?.toValue();
8660
+ const existingTreeUniqueId = existingSour?.get("_TID")?.toValue();
7049
8661
  const newSour = createCommon();
7050
- newSour.set("CORP", createCommon());
7051
- newSour.set("CORP.WWW", createCommon());
7052
- newSour.set("NAME", createCommon());
7053
- newSour.set("VERS", createCommon());
7054
- newSour.CORP.value = "TreeViz - The Family Tree Visualiser";
7055
- newSour.CORP.WWW.value = "treeviz.com";
7056
- newSour.NAME.value = "TreeViz - The Family Tree Visualiser";
7057
- newSour.VERS.value = getVersion();
8662
+ newSour.value = APP_BRANDING;
8663
+ newSour.set("NAME", APP_BRANDING);
8664
+ newSour.set("VERS", getVersion());
8665
+ if (typeof existingTreeName === "string" && existingTreeName.trim()) {
8666
+ newSour.set("_TREE", existingTreeName.trim());
8667
+ }
8668
+ if (typeof existingTreeUniqueId === "string" && existingTreeUniqueId.trim()) {
8669
+ newSour.set("_TID", existingTreeUniqueId.trim());
8670
+ }
8671
+ const corp = createCommon();
8672
+ corp.value = APP_BRANDING;
8673
+ corp.set("WWW", "treeviz.com");
8674
+ corp.set("EMAIL", "info@treeviz.com");
8675
+ newSour.set("CORP", corp);
7058
8676
  newHead.set("SOUR", newSour);
7059
8677
  return newHead;
7060
8678
  }
@@ -7083,20 +8701,45 @@ var GedCom = class extends Common {
7083
8701
  }
7084
8702
  toGedcom(tag, level, options) {
7085
8703
  if (options?.super) {
7086
- return super.toGedcom(tag, level, options);
8704
+ return appendGedcomTrailer(super.toGedcom(tag, level, options));
7087
8705
  }
8706
+ const requestedVersion = options?.gedcomVersion;
8707
+ const exportVersion = requestedVersion ? normalizeGedcomVersion(requestedVersion) : this.getGedcomVersion();
8708
+ const exportOptions = {
8709
+ ...options,
8710
+ obje: {
8711
+ standardize: options?.obje?.standardize ?? (requestedVersion !== void 0 || !options?.original),
8712
+ override: options?.obje?.override,
8713
+ namespace: options?.obje?.namespace
8714
+ }
8715
+ };
7088
8716
  const newGedcom = createGedCom();
7089
- if (!options?.original) {
8717
+ Object.assign(newGedcom, this);
8718
+ if (!exportOptions.original) {
7090
8719
  Object.assign(newGedcom, {
7091
- HEAD: this.getDownloadHeader()
8720
+ HEAD: this.getDownloadHeader(exportVersion)
7092
8721
  });
7093
8722
  }
7094
- Object.assign(newGedcom, this);
7095
- if (options?.indis?.length) {
7096
- const newContent = this.getIndiRelatedLists(options.indis);
8723
+ if (exportOptions.indis?.length) {
8724
+ const newContent = this.getIndiRelatedLists(exportOptions.indis);
7097
8725
  Object.assign(newGedcom, newContent);
7098
8726
  }
7099
- return newGedcom.toGedcom(tag, level, { ...options, super: true });
8727
+ const restoreEnums = exportVersion === "7.0" ? applyGedcom7Enumerations(newGedcom) : void 0;
8728
+ const restoreDates = exportVersion === "7.0" ? applyGedcom7DatePhrases(newGedcom) : void 0;
8729
+ const restoreMetadata = exportVersion === "7.0" ? applyGedcom7RecordMetadata(newGedcom) : void 0;
8730
+ const restoreSchema = exportVersion === "7.0" ? ensureExtensionSchema(newGedcom) : void 0;
8731
+ try {
8732
+ return newGedcom.toGedcom(tag, level, {
8733
+ ...exportOptions,
8734
+ gedcomVersion: exportVersion,
8735
+ super: true
8736
+ });
8737
+ } finally {
8738
+ restoreSchema?.();
8739
+ restoreMetadata?.();
8740
+ restoreDates?.();
8741
+ restoreEnums?.();
8742
+ }
7100
8743
  }
7101
8744
  hasTag(tag) {
7102
8745
  const tagName = typeof tag === "string" ? tag : tag?.get("NAME")?.toValue();
@@ -7540,20 +9183,6 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
7540
9183
  return mergedGedcom;
7541
9184
  };
7542
9185
 
7543
- // src/classes/objes.ts
7544
- var Objects = class _Objects extends List {
7545
- copy() {
7546
- const newList = new _Objects();
7547
- this.entries().forEach(([key, value]) => {
7548
- newList.item(key, value);
7549
- });
7550
- return newList;
7551
- }
7552
- except(item) {
7553
- return this.copy().delete(item);
7554
- }
7555
- };
7556
-
7557
9186
  // src/classes/repos.ts
7558
9187
  var Repositories = class _Repositories extends List {
7559
9188
  copy() {
@@ -7596,144 +9225,6 @@ var Submitters = class _Submitters extends List {
7596
9225
  }
7597
9226
  };
7598
9227
 
7599
- // src/classes/note.ts
7600
- var CommonNote = class extends Common {
7601
- constructor(gedcom, id, main, parent) {
7602
- super(gedcom, id, main, parent);
7603
- delete this.id;
7604
- }
7605
- set value(value) {
7606
- const [note, ...contents] = value?.split(/\r?\n/) ?? [];
7607
- this._value = note;
7608
- if (contents.length) {
7609
- const newContents = new List();
7610
- contents.forEach((c, i) => {
7611
- const newContent = createCommon(
7612
- this._gedcom,
7613
- void 0,
7614
- this.main
7615
- );
7616
- newContent.id = `@U${i}@`;
7617
- newContent.value = c;
7618
- newContents.append(newContent);
7619
- });
7620
- const firstItem = newContents.index(0);
7621
- if (firstItem) {
7622
- if (newContents.length === 1) {
7623
- this.set("CONT", firstItem);
7624
- } else {
7625
- this.set("CONT", newContents);
7626
- }
7627
- }
7628
- }
7629
- }
7630
- get value() {
7631
- const contents = this.get("CONT")?.toList().map((content) => content.value).join("\n");
7632
- if (contents) {
7633
- return `${this._value}
7634
- ${contents}`;
7635
- }
7636
- return this._value;
7637
- }
7638
- exportValue() {
7639
- return this._value;
7640
- }
7641
- };
7642
- var createCommonNote = (gedcom, id, main, parent) => {
7643
- return createProxy(
7644
- new CommonNote(gedcom, id, main, parent)
7645
- );
7646
- };
7647
-
7648
- // src/classes/obje.ts
7649
- var Obje = class extends Common {
7650
- standardizeMedia(namespace, override = true, urlGetter) {
7651
- if (!this._gedcom) {
7652
- return this;
7653
- }
7654
- const rin = this?.get("RIN")?.toValue();
7655
- const clone = this?.get("_CLON._OID")?.toValue();
7656
- const mser = this?.get("_MSER._LKID")?.toValue();
7657
- const title = this?.get("FILE.TITL")?.toValue() ?? this?.get("TITL")?.toValue() ?? "";
7658
- const note = this?.get("FILE.NOTE")?.toValue() ?? this?.get("NOTE")?.toValue() ?? "";
7659
- const form = this?.get("FILE.FORM")?.toValue();
7660
- const file = this?.get("FILE")?.toValue();
7661
- const imgId = rin || clone || mser;
7662
- const url = file || namespace && urlGetter?.(namespace, imgId);
7663
- if (!url) {
7664
- return this;
7665
- }
7666
- const newObject = createObje(this._gedcom, this.id, this.main);
7667
- if (!override) {
7668
- Object.assign(newObject, this);
7669
- }
7670
- if (form) {
7671
- if (typeof form === "string") {
7672
- const newForm = createCommon(
7673
- this._gedcom,
7674
- void 0,
7675
- this.main
7676
- );
7677
- newForm.value = form;
7678
- newObject.set("FORM", newForm);
7679
- } else {
7680
- newObject.set("FORM", form);
7681
- }
7682
- }
7683
- if (title) {
7684
- if (typeof title === "string") {
7685
- const newTitle = createCommon(
7686
- this._gedcom,
7687
- void 0,
7688
- this.main
7689
- );
7690
- newTitle.value = title;
7691
- newObject.set("TITL", newTitle);
7692
- if (!note) {
7693
- newObject.set("NOTE", newTitle);
7694
- }
7695
- } else {
7696
- newObject.set("TITL", title);
7697
- if (!note) {
7698
- newObject.set("NOTE", title);
7699
- }
7700
- }
7701
- }
7702
- if (note) {
7703
- if (typeof note === "string") {
7704
- const newNote = createCommon(
7705
- this._gedcom,
7706
- void 0,
7707
- this.main
7708
- );
7709
- newNote.value = note;
7710
- newObject.set("NOTE", newNote);
7711
- if (!title) {
7712
- newObject.set("TITL", newNote);
7713
- }
7714
- } else {
7715
- newObject.set("NOTE", note);
7716
- if (!title) {
7717
- newObject.set("TITL", note);
7718
- }
7719
- }
7720
- }
7721
- const newUrl = createCommon(this._gedcom, void 0, this.main);
7722
- newUrl.value = url;
7723
- newObject.set("FILE", newUrl);
7724
- if (override) {
7725
- Object.assign(this, newObject);
7726
- return this;
7727
- }
7728
- return newObject;
7729
- }
7730
- };
7731
- var createObje = (gedcom, id, main, parent) => {
7732
- return createProxy(
7733
- new Obje(gedcom, id, main, parent)
7734
- );
7735
- };
7736
-
7737
9228
  // src/classes/repo.ts
7738
9229
  var Repo = class extends Common {
7739
9230
  };
@@ -7782,6 +9273,8 @@ var create = (gedcom, type, id, nodes) => {
7782
9273
  prevNode = createIndi(gedcom, id);
7783
9274
  } else if (convertType === "FAM") {
7784
9275
  prevNode = createFam(gedcom, id);
9276
+ } else if (convertType === "SNOTE" || convertType === "NOTE") {
9277
+ prevNode = createCommonNote(gedcom, id);
7785
9278
  } else {
7786
9279
  prevNode = createCommon(gedcom, id);
7787
9280
  }
@@ -7797,7 +9290,7 @@ var create = (gedcom, type, id, nodes) => {
7797
9290
  prevNode = createObje(gedcom, void 0, mainNode, curNode);
7798
9291
  } else if (type === "DATE") {
7799
9292
  prevNode = createCommonDate(gedcom, void 0, mainNode, curNode);
7800
- } else if (type === "NOTE") {
9293
+ } else if (type === "NOTE" || type === "SNOTE") {
7801
9294
  prevNode = createCommonNote(gedcom, void 0, mainNode, curNode);
7802
9295
  } else if (type === "NAME" && mainNode instanceof Indi) {
7803
9296
  prevNode = createCommonName(gedcom, void 0, mainNode, curNode);
@@ -7849,9 +9342,7 @@ var GedcomTree = {
7849
9342
  }, {}) : {};
7850
9343
  const links = new Individuals();
7851
9344
  const tags = [];
7852
- let lines = `${content.replace(/\n0 TRLR(\r?\n)*$/, "")}
7853
- 0 TRLR
7854
- `.split(/\r?\n/).reduce((acc, line) => {
9345
+ let lines = content.split(/\r?\n/).reduce((acc, line) => {
7855
9346
  const lineMatch = line.match(LINE_REG);
7856
9347
  if (lineMatch) {
7857
9348
  const lineIndent = Number(lineMatch?.groups?.indent ?? 0);
@@ -7864,6 +9355,13 @@ var GedcomTree = {
7864
9355
  linesAcc._hasFile = false;
7865
9356
  return acc;
7866
9357
  }
9358
+ if (lineIndent === 0 && lineType === "TRLR") {
9359
+ if (linesAcc._inHead && filename && !linesAcc._hasFile) {
9360
+ acc.push(`1 FILE ${filename}`);
9361
+ }
9362
+ linesAcc._inHead = false;
9363
+ return acc;
9364
+ }
7867
9365
  if (lineIndent === 0 && linesAcc._inHead) {
7868
9366
  if (filename && !linesAcc._hasFile) {
7869
9367
  acc.push(`1 FILE ${filename}`);
@@ -7875,6 +9373,13 @@ var GedcomTree = {
7875
9373
  if (linesAcc._inHead && lineIndent === 1 && lineType === "FILE") {
7876
9374
  linesAcc._hasFile = true;
7877
9375
  }
9376
+ if (lineType.toUpperCase() === "CONC") {
9377
+ const last = acc[acc.length - 1];
9378
+ if (last !== void 0) {
9379
+ acc[acc.length - 1] = `${last}${lineValue}`;
9380
+ return acc;
9381
+ }
9382
+ }
7878
9383
  if (lineIndent > 0 && lineIndent > prevLineIndent && lineValue && isId(lineValue)) {
7879
9384
  const refLines = lineValue.split(/,\s*/).map((id) => line.replace(lineValue, id));
7880
9385
  if (refLines.length > 1) {
@@ -7918,8 +9423,9 @@ var GedcomTree = {
7918
9423
  ).replace(/0\s(@[^@]+@)(\sSOUR[^\n]*\n)([123456789]\s.+\n)*/, "").replace(/0 HEAD(.*)\n/, "0 HEAD$1\n1 _IS_PURGED true\n");
7919
9424
  lines = linesJoined.split("\n");
7920
9425
  }
9426
+ lines = lines.filter((line) => !isGedcomTrailerLine(line));
7921
9427
  lines.forEach((line, index) => {
7922
- if (line.length === 0) {
9428
+ if (line.length === 0 || isGedcomTrailerLine(line)) {
7923
9429
  return;
7924
9430
  }
7925
9431
  const match = reg.exec(line);