@treeviz/gedcom-parser 1.0.23 → 2.0.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.
@@ -23,70 +23,143 @@ var getCacheManagerFactory = () => {
23
23
  };
24
24
 
25
25
  // src/utils/cache.ts
26
+ var getGedcomId = (gedcom) => {
27
+ if (!gedcom) {
28
+ return "unknown";
29
+ }
30
+ const treeId = gedcom.getTreeId?.() || "";
31
+ const treeName = gedcom.getTreeName?.() || "";
32
+ const sanitizedName = treeName.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
33
+ if (treeId && sanitizedName) {
34
+ return `${treeId}_${sanitizedName}`;
35
+ } else if (treeId) {
36
+ return treeId;
37
+ } else if (sanitizedName) {
38
+ return sanitizedName;
39
+ }
40
+ return `gedcom_${gedcom.refcount}`;
41
+ };
26
42
  var caches = {
27
43
  pathCache: {},
28
44
  relativesOnDegreeCache: {},
29
- relativesOnLevelCache: {}
45
+ relativesOnLevelCache: {},
46
+ profilePictureCache: {}
30
47
  };
31
- var getInstance = getCacheManagerFactory();
32
- var cacheDbs = {
33
- pathCache: getInstance("ftv", "Main", "path", true),
34
- relativesOnDegreeCache: getInstance(
35
- "ftv",
36
- "Main",
37
- "path",
38
- true
39
- ),
40
- relativesOnLevelCache: getInstance(
41
- "ftv",
42
- "Main",
43
- "path",
44
- true
45
- )
48
+ var cacheDbs;
49
+ var getCacheDbs = () => {
50
+ if (!cacheDbs) {
51
+ const getInstance = getCacheManagerFactory();
52
+ cacheDbs = {
53
+ pathCache: getInstance(
54
+ "ftv",
55
+ "Main",
56
+ "path",
57
+ true
58
+ ),
59
+ relativesOnDegreeCache: getInstance("ftv", "Main", "path", true),
60
+ relativesOnLevelCache: getInstance(
61
+ "ftv",
62
+ "Main",
63
+ "path",
64
+ true
65
+ ),
66
+ profilePictureCache: getInstance(
67
+ "ftv",
68
+ "Main",
69
+ "images",
70
+ false
71
+ )
72
+ };
73
+ }
74
+ return cacheDbs;
46
75
  };
47
- ({
76
+ var storeCache = {
77
+ // NOTE: pathCache, relativesOnLevelCache, and relativesOnDegreeCache are intentionally
78
+ // kept in memory only. These debounced functions exist to satisfy the type system
79
+ // but are never called.
48
80
  pathCache: debounce((value) => {
49
81
  if (value) {
50
- cacheDbs.pathCache.setItem(value);
82
+ getCacheDbs().pathCache.setItem(value);
51
83
  }
52
84
  }, 50),
53
85
  relativesOnLevelCache: debounce((value) => {
54
86
  if (value) {
55
- cacheDbs.relativesOnLevelCache.setItem(value);
87
+ getCacheDbs().relativesOnLevelCache.setItem(value);
56
88
  }
57
89
  }, 50),
58
90
  relativesOnDegreeCache: debounce((value) => {
59
91
  if (value) {
60
- cacheDbs.relativesOnDegreeCache.setItem(value);
92
+ getCacheDbs().relativesOnDegreeCache.setItem(value);
61
93
  }
62
- }, 50)
63
- });
94
+ }, 50),
95
+ // profilePictureCache IS persisted to IndexedDB
96
+ profilePictureCache: debounce((value) => {
97
+ if (value) {
98
+ getCacheDbs().profilePictureCache.setItem(value);
99
+ }
100
+ }, 100)
101
+ };
102
+ var cacheInitialized = false;
103
+ var initializeCache = async () => {
104
+ if (cacheInitialized) {
105
+ return;
106
+ }
107
+ cacheInitialized = true;
108
+ try {
109
+ const profilePictureData = await getCacheDbs().profilePictureCache.getItem();
110
+ if (profilePictureData) {
111
+ caches.profilePictureCache = profilePictureData;
112
+ }
113
+ } catch (_error) {
114
+ }
115
+ };
64
116
  var resetRelativesCache = () => {
65
117
  caches.relativesOnDegreeCache = {};
66
118
  caches.relativesOnLevelCache = {};
67
119
  };
68
- var relativesCache = (cacheKey) => (key, subKey, value) => {
69
- if (!caches[cacheKey]) {
120
+ var relativesCache = (cacheKey) => (gedcom, key, subKey, value) => {
121
+ const gedcomId = getGedcomId(gedcom);
122
+ const fullKey = `${gedcomId}:${key}`;
123
+ const cache = caches[cacheKey];
124
+ if (!cache) {
70
125
  caches[cacheKey] = {};
71
126
  }
72
- if (value && caches[cacheKey]) {
73
- if (!caches[cacheKey][key]) {
74
- caches[cacheKey][key] = {};
127
+ if (value) {
128
+ const typedCache2 = caches[cacheKey];
129
+ if (!typedCache2[fullKey]) {
130
+ typedCache2[fullKey] = {};
75
131
  }
76
- caches[cacheKey][key][subKey] = value;
77
- return caches[cacheKey][key][subKey];
132
+ typedCache2[fullKey][subKey] = value;
133
+ return typedCache2[fullKey][subKey];
78
134
  }
79
- return caches[cacheKey]?.[key]?.[subKey];
135
+ const typedCache = caches[cacheKey];
136
+ return typedCache?.[fullKey]?.[subKey];
80
137
  };
81
- var pathCache = (key, value) => {
138
+ var pathCache = (gedcom, key, value) => {
139
+ const gedcomId = getGedcomId(gedcom);
140
+ const fullKey = `${gedcomId}:${key}`;
82
141
  if (!caches.pathCache) {
83
142
  caches.pathCache = {};
84
143
  }
85
144
  if (value && caches.pathCache) {
86
- caches.pathCache[key] = value;
87
- return caches.pathCache[key];
145
+ caches.pathCache[fullKey] = value;
146
+ return caches.pathCache[fullKey];
88
147
  }
89
- return caches.pathCache?.[key];
148
+ return caches.pathCache?.[fullKey];
149
+ };
150
+ var profilePictureCache = (gedcom, key, value) => {
151
+ const gedcomId = getGedcomId(gedcom);
152
+ const fullKey = `${gedcomId}:${key}`;
153
+ if (!caches.profilePictureCache) {
154
+ caches.profilePictureCache = {};
155
+ }
156
+ if (value && caches.profilePictureCache) {
157
+ caches.profilePictureCache[fullKey] = value;
158
+ storeCache.profilePictureCache(caches.profilePictureCache);
159
+ return caches.profilePictureCache[fullKey];
160
+ }
161
+ const cached = caches.profilePictureCache?.[fullKey];
162
+ return cached;
90
163
  };
91
164
 
92
165
  // src/constants/constants.ts
@@ -862,11 +935,30 @@ var Common = class _Common {
862
935
  const sour = get(head, "SOUR.value");
863
936
  return !!sour?.toLowerCase()?.startsWith("myheritage");
864
937
  }
938
+ /**
939
+ * Get the source type as a string (for prefixing tree IDs and names)
940
+ * Returns the detected source type or undefined if unknown
941
+ */
942
+ getSourceType() {
943
+ if (this.isAncestry()) return "Ancestry";
944
+ if (this.isMyHeritage()) return "MyHeritage";
945
+ if (this.isFamilySearch()) return "FamilySearch";
946
+ if (this.isGNO2GED()) return "GNO2GED";
947
+ if (this.isGenoPro()) return "GenoPro";
948
+ if (this.isAhnenblatt()) return "Ahnenblatt";
949
+ if (this.isGeni()) return "Geni";
950
+ return void 0;
951
+ }
865
952
  isFamilySearch() {
866
953
  const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
867
954
  const sourName = get(head, "SOUR.NAME.value");
868
955
  return sourName === "FamilySearch API";
869
956
  }
957
+ isGNO2GED() {
958
+ const head = get(this, "HEAD") || get(this.getGedcom(), "HEAD");
959
+ const sour = get(head, "SOUR.value");
960
+ return sour === "GNO2GED";
961
+ }
870
962
  getAncestryTreeId() {
871
963
  const path = "HEAD.SOUR._TREE.RIN.value";
872
964
  return get(this, path) || get(this.getGedcom(), path);
@@ -877,11 +969,34 @@ var Common = class _Common {
877
969
  }
878
970
  getTreeId() {
879
971
  if (this?.isAncestry()) {
880
- return this.getAncestryTreeId();
972
+ const id = this.getAncestryTreeId();
973
+ if (id !== void 0) return id;
881
974
  }
882
975
  if (this?.isMyHeritage()) {
883
- return this.getMyHeritageTreeId();
976
+ const id = this.getMyHeritageTreeId();
977
+ if (id !== void 0) return id;
978
+ }
979
+ if (this?.isFamilySearch()) {
980
+ const id = this.getFamilySearchTreeId();
981
+ if (id !== void 0) return id;
982
+ }
983
+ if (this?.isGNO2GED()) {
984
+ const id = this.getGNO2GEDTreeId();
985
+ if (id !== void 0) return id;
884
986
  }
987
+ if (this?.isAhnenblatt()) {
988
+ const id = this.getAhnenblattTreeId();
989
+ if (id !== void 0) return id;
990
+ }
991
+ if (this?.isGeni()) {
992
+ const id = this.getGeniTreeId();
993
+ if (id !== void 0) return id;
994
+ }
995
+ if (this?.isGenoPro()) {
996
+ const id = this.getGenoProTreeId();
997
+ if (id !== void 0) return id;
998
+ }
999
+ return this.getUniversalTreeId();
885
1000
  }
886
1001
  getAncestryTreeName() {
887
1002
  const path = "HEAD.SOUR._TREE.value";
@@ -894,13 +1009,146 @@ var Common = class _Common {
894
1009
  /Exported by MyHeritage.com from (?<tree>.+) in.+$/
895
1010
  )?.groups?.tree;
896
1011
  }
1012
+ getFamilySearchTreeId() {
1013
+ const rin = get(this, "HEAD.SOUR._TREE.RIN.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.RIN.value");
1014
+ if (rin) {
1015
+ return rin;
1016
+ }
1017
+ return "familysearch";
1018
+ }
1019
+ getFamilySearchTreeName() {
1020
+ const treeName = get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value");
1021
+ if (treeName) {
1022
+ return treeName;
1023
+ }
1024
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1025
+ return fileName || "FamilySearch Import";
1026
+ }
1027
+ getAhnenblattTreeId() {
1028
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1029
+ if (fileName) {
1030
+ const idMatch = fileName.match(/_(\d+)/);
1031
+ if (idMatch) {
1032
+ return idMatch[1];
1033
+ }
1034
+ }
1035
+ return void 0;
1036
+ }
1037
+ getAhnenblattTreeName() {
1038
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1039
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
1040
+ }
1041
+ getGeniTreeId() {
1042
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1043
+ if (fileName) {
1044
+ const idMatch = fileName.match(/_(\d+)/);
1045
+ if (idMatch) {
1046
+ return idMatch[1];
1047
+ }
1048
+ }
1049
+ return void 0;
1050
+ }
1051
+ getGeniTreeName() {
1052
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1053
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
1054
+ }
1055
+ getGenoProTreeId() {
1056
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1057
+ if (fileName) {
1058
+ const idMatch = fileName.match(/_(\d+)/);
1059
+ if (idMatch) {
1060
+ return idMatch[1];
1061
+ }
1062
+ }
1063
+ return void 0;
1064
+ }
1065
+ getGenoProTreeName() {
1066
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1067
+ return fileName?.replace(/\.ged$/i, "").replace(/_/g, " ");
1068
+ }
1069
+ getGNO2GEDTreeId() {
1070
+ const rin = get(this, "HEAD._TREE.RIN.value") || get(this.getGedcom(), "HEAD._TREE.RIN.value");
1071
+ if (rin) {
1072
+ return rin;
1073
+ }
1074
+ return `gno_${this._gedcom?.refcount || "unknown"}`;
1075
+ }
1076
+ getGNO2GEDTreeName() {
1077
+ const treeName = get(this, "HEAD._TREE.value") || get(this.getGedcom(), "HEAD._TREE.value");
1078
+ if (treeName) {
1079
+ return treeName;
1080
+ }
1081
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1082
+ return fileName || "GNO2GED Export";
1083
+ }
1084
+ /**
1085
+ * Universal tree ID getter for unknown/unrecognized GEDCOM sources
1086
+ * Tries to extract an ID from various common locations
1087
+ */
1088
+ getUniversalTreeId() {
1089
+ const sourceType = this.getSourceType();
1090
+ const prefix = sourceType ? sourceType.toLowerCase() : "tree";
1091
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1092
+ if (fileName) {
1093
+ const idMatch = fileName.match(/_(\d+)/);
1094
+ if (idMatch) {
1095
+ return `${prefix}_${idMatch[1]}`;
1096
+ }
1097
+ }
1098
+ return `${prefix}_${this._gedcom?.refcount || "unknown"}`;
1099
+ }
1100
+ /**
1101
+ * Universal tree name getter for unknown/unrecognized GEDCOM sources
1102
+ * Tries to extract a name from various common locations
1103
+ */
1104
+ getUniversalTreeName() {
1105
+ const sourceType = this.getSourceType();
1106
+ const prefix = sourceType ? `${sourceType}-` : "";
1107
+ const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1108
+ if (fileName) {
1109
+ const cleanName = fileName.replace(/\.ged$/i, "").replace(/_/g, " ");
1110
+ return `${prefix}${cleanName}`;
1111
+ }
1112
+ const sourName = get(this, "HEAD.SOUR.NAME.value") || get(this.getGedcom(), "HEAD.SOUR.NAME.value");
1113
+ if (sourName) {
1114
+ return `${prefix}${sourName}`;
1115
+ }
1116
+ const sourValue = get(this, "HEAD.SOUR.value") || get(this.getGedcom(), "HEAD.SOUR.value");
1117
+ if (sourValue) {
1118
+ return `${prefix}${sourValue}`;
1119
+ }
1120
+ return `${prefix}Unknown Tree`;
1121
+ }
897
1122
  getTreeName() {
898
1123
  if (this?.isAncestry()) {
899
- return this.getAncestryTreeName();
1124
+ const name = this.getAncestryTreeName();
1125
+ if (name) return name;
900
1126
  }
901
1127
  if (this?.isMyHeritage()) {
902
- return this.getMyHeritageTreeName();
1128
+ const name = this.getMyHeritageTreeName();
1129
+ if (name) return name;
1130
+ }
1131
+ if (this?.isFamilySearch()) {
1132
+ const name = this.getFamilySearchTreeName();
1133
+ if (name) return name;
1134
+ }
1135
+ if (this?.isGNO2GED()) {
1136
+ const name = this.getGNO2GEDTreeName();
1137
+ if (name) return name;
903
1138
  }
1139
+ if (this?.isAhnenblatt()) {
1140
+ const name = this.getAhnenblattTreeName();
1141
+ if (name) return name;
1142
+ }
1143
+ if (this?.isGeni()) {
1144
+ const name = this.getGeniTreeName();
1145
+ if (name) return name;
1146
+ }
1147
+ if (this?.isGenoPro()) {
1148
+ const name = this.getGenoProTreeName();
1149
+ if (name) return name;
1150
+ }
1151
+ return this.getUniversalTreeName();
904
1152
  }
905
1153
  };
906
1154
  var createProxy = (target) => {
@@ -2739,7 +2987,7 @@ var Indi = class extends Common {
2739
2987
  }
2740
2988
  async ancestryMedia(namespace) {
2741
2989
  const list = {};
2742
- const objeList = this.get("OBJE")?.toList();
2990
+ const objeList = this.get("OBJE")?.toList().copy();
2743
2991
  const www = this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
2744
2992
  const tree = this.getAncestryTreeId();
2745
2993
  if (objeList) {
@@ -2813,11 +3061,12 @@ var Indi = class extends Common {
2813
3061
  if (!tree) {
2814
3062
  return;
2815
3063
  }
2816
- const objeList = this.get("OBJE")?.toList();
2817
- const birthObj = this.get("BIRT.OBJE")?.toList();
2818
- const deathObj = this.get("DEAT.OBJE")?.toList();
3064
+ const objeList = this.get("OBJE")?.toList().copy();
3065
+ const birthObj = this.get("BIRT.OBJE")?.toList().copy();
3066
+ const deathObj = this.get("DEAT.OBJE")?.toList().copy();
3067
+ objeList?.merge(birthObj).merge(deathObj);
2819
3068
  (this.get("FAMS")?.toValueList().values() ?? []).concat(this.get("FAMC")?.toValueList().values() ?? []).forEach((fam) => {
2820
- objeList?.merge(birthObj).merge(deathObj).merge(fam?.get("MARR.OBJE"));
3069
+ objeList.merge(fam?.get("MARR.OBJE"));
2821
3070
  });
2822
3071
  objeList?.forEach((o, index) => {
2823
3072
  if (!o) {
@@ -2935,6 +3184,88 @@ var Indi = class extends Common {
2935
3184
  };
2936
3185
  });
2937
3186
  }
3187
+ geniMedia() {
3188
+ const list = {};
3189
+ const objeList = this.get("OBJE")?.toList().copy();
3190
+ const sourList = this.get("SOUR")?.toList().copy();
3191
+ sourList?.forEach((sour) => {
3192
+ const sourObje = sour?.get("OBJE")?.toList();
3193
+ objeList.merge(sourObje);
3194
+ });
3195
+ if (!objeList || objeList.length === 0) {
3196
+ return void 0;
3197
+ }
3198
+ const rfn = this.get("RFN")?.toValue();
3199
+ const geniId = rfn?.replace(/^geni:/, "") || "unknown";
3200
+ objeList.forEach((obje, index) => {
3201
+ if (!obje) {
3202
+ return;
3203
+ }
3204
+ const key = `@O${index}@`;
3205
+ const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
3206
+ const url = obje?.get("FILE")?.toValue();
3207
+ const title = obje?.get("TITL")?.toValue() ?? "";
3208
+ const type = obje?.get("FORM")?.toValue() ?? "raw";
3209
+ if (url) {
3210
+ const urlMatch = url.match(/\/([^/]+)\?hash=/);
3211
+ const imgId = urlMatch?.[1] || `img-${index}-${Date.now().toString(36)}`;
3212
+ const id = `geni-${geniId}-${imgId}`;
3213
+ list[id] = {
3214
+ isPrimary,
3215
+ key,
3216
+ id,
3217
+ tree: geniId,
3218
+ imgId,
3219
+ person: this.id,
3220
+ title,
3221
+ url,
3222
+ contentType: type,
3223
+ downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
3224
+ };
3225
+ }
3226
+ });
3227
+ return list;
3228
+ }
3229
+ universalMedia() {
3230
+ const list = {};
3231
+ if (!this.id) {
3232
+ return list;
3233
+ }
3234
+ const objeList = this.get("OBJE")?.toList().copy();
3235
+ if (!objeList || objeList.length === 0) {
3236
+ return list;
3237
+ }
3238
+ const rfn = this.get("RFN")?.toValue();
3239
+ const treeId = rfn || "universal";
3240
+ objeList.forEach((obje, index) => {
3241
+ if (!obje) {
3242
+ return;
3243
+ }
3244
+ const key = `@O${index}@`;
3245
+ obje.standardizeMedia();
3246
+ const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
3247
+ const url = obje?.get("FILE")?.toValue();
3248
+ const title = obje?.get("TITL")?.toValue() ?? "";
3249
+ const type = obje?.get("FORM")?.toValue() ?? "raw";
3250
+ if (url) {
3251
+ const imgId = `media-${index}-${url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
3252
+ const id = `${treeId}-${this.id}-${imgId}`;
3253
+ list[id] = {
3254
+ isPrimary,
3255
+ key,
3256
+ id,
3257
+ tree: treeId,
3258
+ imgId,
3259
+ person: this.id,
3260
+ title,
3261
+ url,
3262
+ contentType: type,
3263
+ downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`
3264
+ };
3265
+ }
3266
+ });
3267
+ return list;
3268
+ }
2938
3269
  async multimedia(namespace) {
2939
3270
  if (this?.isAncestry()) {
2940
3271
  return await this.ancestryMedia(namespace);
@@ -2942,11 +3273,30 @@ var Indi = class extends Common {
2942
3273
  if (this?.isMyHeritage()) {
2943
3274
  return this.myheritageMedia();
2944
3275
  }
2945
- return void 0;
3276
+ if (this?.isGeni()) {
3277
+ return this.geniMedia();
3278
+ }
3279
+ return this.universalMedia();
2946
3280
  }
2947
3281
  async getProfilePicture(namespace, onlyPrimary = true) {
3282
+ if (!this.id) {
3283
+ return void 0;
3284
+ }
3285
+ const cacheKey = this.id;
3286
+ const cached = profilePictureCache(
3287
+ this._gedcom,
3288
+ cacheKey
3289
+ );
3290
+ if (cached !== void 0) {
3291
+ return cached;
3292
+ }
2948
3293
  const mediaList = await this.multimedia(namespace);
2949
3294
  if (!mediaList) {
3295
+ profilePictureCache(
3296
+ this._gedcom,
3297
+ cacheKey,
3298
+ void 0
3299
+ );
2950
3300
  return void 0;
2951
3301
  }
2952
3302
  const mediaArray = Object.values(mediaList);
@@ -2954,27 +3304,41 @@ var Indi = class extends Common {
2954
3304
  (media) => media.isPrimary && isImageFormat(media.contentType || getFileExtension(media.url))
2955
3305
  );
2956
3306
  if (primaryMedia) {
2957
- return {
3307
+ const result = {
2958
3308
  file: primaryMedia.url,
2959
3309
  form: primaryMedia.contentType,
2960
3310
  title: primaryMedia.title,
2961
3311
  isPrimary: true
2962
3312
  };
2963
- }
2964
- if (!onlyPrimary) {
3313
+ profilePictureCache(this._gedcom, cacheKey, result);
3314
+ return result;
3315
+ }
3316
+ if (onlyPrimary) {
3317
+ profilePictureCache(
3318
+ this._gedcom,
3319
+ cacheKey,
3320
+ void 0
3321
+ );
2965
3322
  return void 0;
2966
3323
  }
2967
3324
  const secondaryMedia = mediaArray.find(
2968
3325
  (media) => isImageFormat(media.contentType || getFileExtension(media.url))
2969
3326
  );
2970
3327
  if (secondaryMedia) {
2971
- return {
3328
+ const result = {
2972
3329
  file: secondaryMedia.url,
2973
3330
  form: secondaryMedia.contentType,
2974
3331
  title: secondaryMedia.title,
2975
3332
  isPrimary: false
2976
3333
  };
3334
+ profilePictureCache(this._gedcom, cacheKey, result);
3335
+ return result;
2977
3336
  }
3337
+ profilePictureCache(
3338
+ this._gedcom,
3339
+ cacheKey,
3340
+ void 0
3341
+ );
2978
3342
  return void 0;
2979
3343
  }
2980
3344
  link(poolId) {
@@ -3342,7 +3706,7 @@ var Indi = class extends Common {
3342
3706
  return;
3343
3707
  }
3344
3708
  const cacheKey = `${this.id}|${usedIndi.id}`;
3345
- const cache = pathCache(cacheKey);
3709
+ const cache = pathCache(this._gedcom, cacheKey);
3346
3710
  if (cache) {
3347
3711
  return cache;
3348
3712
  }
@@ -3387,7 +3751,7 @@ var Indi = class extends Common {
3387
3751
  if (breakOnNext) {
3388
3752
  return void 0;
3389
3753
  }
3390
- pathCache(cacheKey, path2);
3754
+ pathCache(this._gedcom, cacheKey, path2);
3391
3755
  return path2;
3392
3756
  }
3393
3757
  visited.append(indi);
@@ -3557,7 +3921,7 @@ var Indi = class extends Common {
3557
3921
  }
3558
3922
  getRelativesOnDegree(degree = 0) {
3559
3923
  this.id = this.id || `@I${Math.random()}@`;
3560
- const cache = relativesOnDegreeCache(this.id, degree);
3924
+ const cache = relativesOnDegreeCache(this._gedcom, this.id, degree);
3561
3925
  if (cache) {
3562
3926
  return cache;
3563
3927
  }
@@ -3565,6 +3929,7 @@ var Indi = class extends Common {
3565
3929
  const excludes = persons;
3566
3930
  if (!Math.abs(degree)) {
3567
3931
  return relativesOnDegreeCache(
3932
+ this._gedcom,
3568
3933
  this.id,
3569
3934
  degree,
3570
3935
  persons.except(this)
@@ -3575,11 +3940,11 @@ var Indi = class extends Common {
3575
3940
  excludes.merge(persons);
3576
3941
  persons = this.getRelativesOnLevel(validDegree).getRelativesOnDegree(-validDegree).copy().exclude(excludes);
3577
3942
  }
3578
- return relativesOnDegreeCache(this.id, degree, persons);
3943
+ return relativesOnDegreeCache(this._gedcom, this.id, degree, persons);
3579
3944
  }
3580
3945
  getRelativesOnLevel(level = 0, filter) {
3581
3946
  this.id = this.id || `@I${Math.random()}@`;
3582
- const cache = relativesOnLevelCache(this.id, level);
3947
+ const cache = relativesOnLevelCache(this._gedcom, this.id, level);
3583
3948
  if (cache) {
3584
3949
  return cache;
3585
3950
  }
@@ -3590,7 +3955,7 @@ var Indi = class extends Common {
3590
3955
  };
3591
3956
  let families = this.get(config.key)?.toValueList();
3592
3957
  if (!families) {
3593
- return relativesOnLevelCache(this.id, level, persons);
3958
+ return relativesOnLevelCache(this._gedcom, this.id, level, persons);
3594
3959
  }
3595
3960
  if (filter) {
3596
3961
  families = families.filter(filter);
@@ -3601,7 +3966,12 @@ var Indi = class extends Common {
3601
3966
  persons = this.toFamilies(families).getParents();
3602
3967
  }
3603
3968
  if (level >= -1 && level <= 1) {
3604
- return relativesOnLevelCache(this.id, level, persons.except(this));
3969
+ return relativesOnLevelCache(
3970
+ this._gedcom,
3971
+ this.id,
3972
+ level,
3973
+ persons.except(this)
3974
+ );
3605
3975
  }
3606
3976
  for (let i = 1; i < Math.abs(level); i++) {
3607
3977
  if (config.isAscendant) {
@@ -3610,7 +3980,12 @@ var Indi = class extends Common {
3610
3980
  persons = persons.getParents();
3611
3981
  }
3612
3982
  }
3613
- return relativesOnLevelCache(this.id, level, persons.except(this));
3983
+ return relativesOnLevelCache(
3984
+ this._gedcom,
3985
+ this.id,
3986
+ level,
3987
+ persons.except(this)
3988
+ );
3614
3989
  }
3615
3990
  getAscendants(level = 0, filter) {
3616
3991
  if (!level) {
@@ -3649,7 +4024,12 @@ var Indi = class extends Common {
3649
4024
  }
3650
4025
  currentGen++;
3651
4026
  generations[currentGen] = descentants;
3652
- relativesOnLevelCache(this.id, -currentGen, descentants);
4027
+ relativesOnLevelCache(
4028
+ this._gedcom,
4029
+ this.id,
4030
+ -currentGen,
4031
+ descentants
4032
+ );
3653
4033
  descentants && relatives.merge(descentants);
3654
4034
  }
3655
4035
  return { relatives, generations };
@@ -3682,7 +4062,7 @@ var Indi = class extends Common {
3682
4062
  }
3683
4063
  currentGen++;
3684
4064
  generations[currentGen] = parents;
3685
- relativesOnLevelCache(this.id, currentGen, parents);
4065
+ relativesOnLevelCache(this._gedcom, this.id, currentGen, parents);
3686
4066
  parents && relatives.merge(parents);
3687
4067
  }
3688
4068
  return { relatives, generations };
@@ -6110,7 +6490,7 @@ var isCommonDate = (value) => {
6110
6490
  // package.json
6111
6491
  var package_default = {
6112
6492
  name: "@treeviz/gedcom-parser",
6113
- version: "1.0.23"};
6493
+ version: "2.0.0"};
6114
6494
 
6115
6495
  // src/utils/get-product-details.ts
6116
6496
  var isDevelopment = () => {
@@ -6874,7 +7254,7 @@ var GedcomTree = {
6874
7254
  return this.parseHierarchy(content, options);
6875
7255
  },
6876
7256
  parseHierarchy: function(content, options) {
6877
- const { settings } = options ?? {};
7257
+ const { settings, filename = "" } = options ?? {};
6878
7258
  const { linkedPersons = "skip", linkingKey } = settings ?? {};
6879
7259
  const gedcom = createGedCom();
6880
7260
  gedcom.removeValue();
@@ -6909,6 +7289,25 @@ var GedcomTree = {
6909
7289
  if (lineMatch) {
6910
7290
  const lineIndent = Number(lineMatch?.groups?.indent ?? 0);
6911
7291
  const lineValue = lineMatch?.groups?.value ?? "";
7292
+ const lineType = lineMatch?.groups?.type ?? "";
7293
+ const linesAcc = acc;
7294
+ if (lineIndent === 0 && lineType === "HEAD") {
7295
+ acc.push(line);
7296
+ linesAcc._inHead = true;
7297
+ linesAcc._hasFile = false;
7298
+ return acc;
7299
+ }
7300
+ if (lineIndent === 0 && linesAcc._inHead) {
7301
+ if (filename && !linesAcc._hasFile) {
7302
+ acc.push(`1 FILE ${filename}`);
7303
+ }
7304
+ linesAcc._inHead = false;
7305
+ acc.push(line);
7306
+ return acc;
7307
+ }
7308
+ if (linesAcc._inHead && lineIndent === 1 && lineType === "FILE") {
7309
+ linesAcc._hasFile = true;
7310
+ }
6912
7311
  if (lineIndent > 0 && lineIndent > prevLineIndent && lineValue && isId(lineValue)) {
6913
7312
  const refLines = lineValue.split(/,\s*/).map((id) => line.replace(lineValue, id));
6914
7313
  if (refLines.length > 1) {
@@ -7091,4 +7490,4 @@ if (isDev) {
7091
7490
  }
7092
7491
  var parser_default = GedcomTree;
7093
7492
 
7094
- export { ACCEPTED_DATE_FORMATS, ACCEPTED_DATE_FORMATS_REGEX, parser_default as GedcomTree, PlaceType, commonDateFormatter, create, dateFormatter, extractSeparationYears, extractSplitPoints, findMatchingRangeForSplitRange, fromTuple, generateSplitRanges, getAllProp, getFamilyWith, getFileExtension, getName, getPlaceParts, getPlaces, getRawSize, getVersion, hungarianOrdinalize, implemented, inRange, isDevelopment, isImageFormat, isIntersectedRange, isRangeContained, marriageDateFormatter, nameFormatter, notImplemented, noteDateFormatter, ordinalize, parseRangeBounds, pathCache, placeTranslator, relativesCache, resetRelativesCache, setNestedGroup, splitOverlappingRanges, splitRange };
7493
+ export { ACCEPTED_DATE_FORMATS, ACCEPTED_DATE_FORMATS_REGEX, parser_default as GedcomTree, PlaceType, commonDateFormatter, create, dateFormatter, extractSeparationYears, extractSplitPoints, findMatchingRangeForSplitRange, fromTuple, generateSplitRanges, getAllProp, getFamilyWith, getFileExtension, getName, getPlaceParts, getPlaces, getRawSize, getVersion, hungarianOrdinalize, implemented, inRange, initializeCache, isDevelopment, isImageFormat, isIntersectedRange, isRangeContained, marriageDateFormatter, nameFormatter, notImplemented, noteDateFormatter, ordinalize, parseRangeBounds, pathCache, placeTranslator, profilePictureCache, relativesCache, resetRelativesCache, setNestedGroup, splitOverlappingRanges, splitRange };