@treeviz/gedcom-parser 2.1.17 → 2.1.22

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.
package/dist/index.js CHANGED
@@ -88,6 +88,30 @@ var mediaIdValue = (obje, path) => {
88
88
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
89
89
  };
90
90
  var resolveObjeMediaId = (obje) => mediaIdValue(obje, "RIN") || mediaIdValue(obje, "_CLON._OID") || mediaIdValue(obje, "_MSER._LKID") || mediaIdValue(obje, "_OID") || mediaIdValue(obje, "_LKID");
91
+ var ANCESTRY_TREE_MEDIA_NAMESPACE = 1093;
92
+ var ANCESTRY_NAMESPACE_IN_URL = /\/namespaces\/(\d+)\/media\//i;
93
+ var parseAncestryNamespaceFromUrl = (url) => {
94
+ if (!url) {
95
+ return void 0;
96
+ }
97
+ const match = url.match(ANCESTRY_NAMESPACE_IN_URL);
98
+ const namespace = match?.[1] ? Number(match[1]) : NaN;
99
+ return Number.isFinite(namespace) ? namespace : void 0;
100
+ };
101
+ var isAncestryOriginObje = (obje) => {
102
+ if (!obje) {
103
+ return false;
104
+ }
105
+ const orig = mediaIdValue(obje, "_ORIG");
106
+ if (orig?.toLowerCase() === "acom") {
107
+ return true;
108
+ }
109
+ const file = mediaIdValue(obje, "FILE") ?? "";
110
+ if (parseAncestryNamespaceFromUrl(file)) {
111
+ return true;
112
+ }
113
+ return Boolean(resolveObjeMediaId(obje) && !file.trim());
114
+ };
91
115
  var ANCESTRY_MEDIA_RETRIEVAL_PREFIX = "https://www.ancestry.com/api/media/retrieval/v2/image";
92
116
  var ANCESTRY_MEDIA_QUERY = "client=trees-mediaservice&imageQuality=hq";
93
117
  var ancestryMediaPath = (namespace, imgId) => `/namespaces/${namespace}/media/${imgId}?${ANCESTRY_MEDIA_QUERY}`;
@@ -881,8 +905,25 @@ var Common = class _Common {
881
905
  getHeadRecord() {
882
906
  return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
883
907
  }
908
+ unwrapHeadRecord(node) {
909
+ if (!node) {
910
+ return void 0;
911
+ }
912
+ const common = node instanceof List ? node.index(0) : node;
913
+ if (!common || typeof common.get !== "function") {
914
+ return void 0;
915
+ }
916
+ const nested = common.get("HEAD");
917
+ if (nested instanceof List) {
918
+ return nested.index(0) ?? common;
919
+ }
920
+ if (nested instanceof _Common) {
921
+ return nested;
922
+ }
923
+ return common;
924
+ }
884
925
  getOriginalHeadRecord() {
885
- return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
926
+ return this.unwrapHeadRecord(get(this, ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getGedcom(), ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getHeadRecord(), ORIG_HEAD_TAG));
886
927
  }
887
928
  getSourceHeads() {
888
929
  const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
@@ -890,9 +931,23 @@ var Common = class _Common {
890
931
  return Boolean(head && heads.indexOf(head) === index);
891
932
  });
892
933
  }
934
+ sourceHeadField(head, path) {
935
+ const normalized = path.endsWith(".value") ? path.slice(0, -".value".length) : path;
936
+ const node = head.get(normalized);
937
+ if (!node) {
938
+ return void 0;
939
+ }
940
+ if (node instanceof List) {
941
+ return node.index(0)?.toValue();
942
+ }
943
+ if (typeof node.toValue === "function") {
944
+ return node.toValue();
945
+ }
946
+ return void 0;
947
+ }
893
948
  getFromSourceHeads(path) {
894
949
  for (const head of this.getSourceHeads()) {
895
- const value = get(head, path);
950
+ const value = this.sourceHeadField(head, path);
896
951
  if (value !== void 0 && value !== null && value !== "") {
897
952
  return value;
898
953
  }
@@ -901,8 +956,8 @@ var Common = class _Common {
901
956
  }
902
957
  sourStartsWith(prefix) {
903
958
  return this.getSourceHeads().some((head) => {
904
- const sour = get(head, "SOUR.value");
905
- return !!sour?.toLowerCase()?.startsWith(prefix);
959
+ const sour = this.sourceHeadField(head, "SOUR");
960
+ return typeof sour === "string" && sour.toLowerCase().startsWith(prefix);
906
961
  });
907
962
  }
908
963
  isGenoPro() {
@@ -912,7 +967,7 @@ var Common = class _Common {
912
967
  return this.sourStartsWith("ahnenblatt");
913
968
  }
914
969
  isGeni() {
915
- return this.sourStartsWith("geni");
970
+ return this.sourStartsWith("geni.com");
916
971
  }
917
972
  isAncestry() {
918
973
  return this.sourStartsWith("ancestry");
@@ -920,6 +975,51 @@ var Common = class _Common {
920
975
  isMyHeritage() {
921
976
  return this.sourStartsWith("myheritage");
922
977
  }
978
+ /**
979
+ * GEDCOM root for Ancestry media helpers.
980
+ * `this._gedcom` when called on a child record; `this` when called on the file root.
981
+ *
982
+ * Cannot use `instanceof GedCom`: `GedComType` is a type alias (erased at runtime),
983
+ * and importing the `GedCom` class here would cycle (`GedCom extends Common`).
984
+ * The root is the only Common with an `objes()` method.
985
+ */
986
+ hostGedcom() {
987
+ const linked = this.getGedcom();
988
+ if (linked) {
989
+ return linked;
990
+ }
991
+ if ("objes" in this && typeof this.objes === "function") {
992
+ return this;
993
+ }
994
+ return void 0;
995
+ }
996
+ /** True when the file still has Ancestry tree media (`_ORIG acom`, `_OID`, retrieval URL). */
997
+ hasAncestryOriginMedia() {
998
+ const objes = this.hostGedcom()?.objes?.();
999
+ return objes?.values().some((obje) => isAncestryOriginObje(obje)) ?? false;
1000
+ }
1001
+ /**
1002
+ * Namespace for Ancestry tree photos. Prefer a `namespaces/{id}` FILE URL
1003
+ * (TreeViz GEDCOM 7 / GEDZIP export), otherwise 1093 for member-tree media.
1004
+ */
1005
+ getAncestryMediaNamespace() {
1006
+ const objes = this.hostGedcom()?.objes?.();
1007
+ if (objes) {
1008
+ for (const obje of objes.values()) {
1009
+ const file = obje?.get("FILE")?.toValue();
1010
+ const fromUrl = parseAncestryNamespaceFromUrl(
1011
+ typeof file === "string" ? file : void 0
1012
+ );
1013
+ if (fromUrl) {
1014
+ return fromUrl;
1015
+ }
1016
+ }
1017
+ }
1018
+ if (this.isAncestry() || this.hasAncestryOriginMedia()) {
1019
+ return ANCESTRY_TREE_MEDIA_NAMESPACE;
1020
+ }
1021
+ return void 0;
1022
+ }
923
1023
  /**
924
1024
  * Get the source type as a string (for prefixing tree IDs and names)
925
1025
  * Returns the detected source type or undefined if unknown
@@ -936,13 +1036,13 @@ var Common = class _Common {
936
1036
  }
937
1037
  isFamilySearch() {
938
1038
  return this.getSourceHeads().some((head) => {
939
- const sourName = get(head, "SOUR.NAME.value");
1039
+ const sourName = this.sourceHeadField(head, "SOUR.NAME");
940
1040
  return sourName === "FamilySearch API";
941
1041
  });
942
1042
  }
943
1043
  isGNO2GED() {
944
1044
  return this.getSourceHeads().some((head) => {
945
- const sour = get(head, "SOUR.value");
1045
+ const sour = this.sourceHeadField(head, "SOUR");
946
1046
  return sour === "GNO2GED";
947
1047
  });
948
1048
  }
@@ -987,8 +1087,7 @@ var Common = class _Common {
987
1087
  return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
988
1088
  }
989
1089
  getMyHeritageTreeName() {
990
- const path = "HEAD.FILE.value";
991
- const treeDetails = get(this, path) || get(this.getGedcom(), path);
1090
+ const treeDetails = this.getFromSourceHeads("FILE.value") || (get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value"));
992
1091
  return treeDetails?.match(
993
1092
  /Exported by MyHeritage.com from (?<tree>.+) in.+$/
994
1093
  )?.groups?.tree;
@@ -1005,7 +1104,7 @@ var Common = class _Common {
1005
1104
  if (treeName) {
1006
1105
  return treeName;
1007
1106
  }
1008
- const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1107
+ const fileName = this.getFromSourceHeads("FILE.value") || get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
1009
1108
  return fileName || "FamilySearch Import";
1010
1109
  }
1011
1110
  getAhnenblattTreeId() {
@@ -2819,6 +2918,45 @@ var notImplemented = (type, ...args) => {
2819
2918
  console.error(`[Not Implemented] ${type}`, ...args);
2820
2919
  };
2821
2920
 
2921
+ // src/utils/multimedia.ts
2922
+ var inferMediaForm = (file, fallback = "bin") => {
2923
+ const withoutQuery = file.split("?")[0] || file;
2924
+ const ext = getFileExtension(withoutQuery);
2925
+ if (ext) {
2926
+ return ext.toLowerCase() === "jpeg" ? "jpg" : ext.toLowerCase();
2927
+ }
2928
+ return fallback;
2929
+ };
2930
+ var mergeMediaLists = (...lists) => {
2931
+ const merged = {};
2932
+ for (const list of lists) {
2933
+ if (!list) continue;
2934
+ Object.assign(merged, list);
2935
+ }
2936
+ return merged;
2937
+ };
2938
+ var mergeMediaListsByObjeKey = (...lists) => {
2939
+ const merged = {};
2940
+ const seen = /* @__PURE__ */ new Set();
2941
+ for (const list of lists) {
2942
+ if (!list) {
2943
+ continue;
2944
+ }
2945
+ for (const [id, item] of Object.entries(list)) {
2946
+ const objeKey = item.key ? String(item.key) : "";
2947
+ if (objeKey && seen.has(objeKey)) {
2948
+ continue;
2949
+ }
2950
+ merged[id] = item;
2951
+ if (objeKey) {
2952
+ seen.add(objeKey);
2953
+ }
2954
+ }
2955
+ }
2956
+ return merged;
2957
+ };
2958
+ var isObjePointer = (value) => typeof value === "string" && /^@O\d+@$/.test(value);
2959
+
2822
2960
  // src/factories/place-parser-provider.ts
2823
2961
  var placeParserProvider;
2824
2962
  var setPlaceParserProvider = (parser) => {
@@ -3531,10 +3669,12 @@ var relativesOnLevelCache = relativesCache("relativesOnLevelCache");
3531
3669
  var relativesOnDegreeCache = relativesCache("relativesOnDegreeCache");
3532
3670
  var Indi = class extends Common {
3533
3671
  toName() {
3534
- return this.get("NAME")?.toValue();
3672
+ const name = this.get("NAME");
3673
+ const value = name?.index(0)?.toValue() ?? name?.toValue();
3674
+ return typeof value === "string" ? value : void 0;
3535
3675
  }
3536
3676
  toNaturalName() {
3537
- return this.get("NAME")?.toValue()?.replaceAll("/", "");
3677
+ return this.toName()?.replaceAll("/", "");
3538
3678
  }
3539
3679
  toList() {
3540
3680
  return new Individuals().concat(
@@ -4017,7 +4157,10 @@ var Indi = class extends Common {
4017
4157
  return result;
4018
4158
  }
4019
4159
  ancestryLink() {
4020
- const www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
4160
+ let www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
4161
+ if (!www || /treeviz/i.test(String(www))) {
4162
+ www = "www.ancestry.com";
4163
+ }
4021
4164
  const tree = this.getAncestryTreeId();
4022
4165
  if (this.id) {
4023
4166
  return `https://${www}/family-tree/person/tree/${tree}/person/${this.id.replace(
@@ -4029,14 +4172,15 @@ var Indi = class extends Common {
4029
4172
  async ancestryMedia(namespace) {
4030
4173
  const list = {};
4031
4174
  const objeList = this.get("OBJE")?.toList().copy();
4032
- const www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
4175
+ this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
4033
4176
  const tree = this.getAncestryTreeId();
4177
+ const usedNamespace = namespace || this.getAncestryMediaNamespace() || ANCESTRY_TREE_MEDIA_NAMESPACE;
4034
4178
  if (objeList) {
4035
4179
  await Promise.all(
4036
4180
  objeList.map(async (objeRef) => {
4037
4181
  const key = objeXrefKey(objeRef, 0);
4038
4182
  const obje = objeRef?.standardizeMedia(
4039
- namespace,
4183
+ usedNamespace,
4040
4184
  true,
4041
4185
  ancestryMediaFileUrl
4042
4186
  );
@@ -4048,27 +4192,9 @@ var Indi = class extends Common {
4048
4192
  const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
4049
4193
  let imgId = media;
4050
4194
  const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
4051
- if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
4052
- return;
4053
- }
4054
4195
  if (!this.id) {
4055
4196
  return;
4056
4197
  }
4057
- if (!namespace && !url) {
4058
- try {
4059
- if (media) {
4060
- const mediaDetailsResponse = await fetch(
4061
- `https://www.ancestry.com/api/media/viewer/v2/trees/${tree}/media?id=${media}`
4062
- );
4063
- const mediaDetails = await mediaDetailsResponse.json();
4064
- if (mediaDetails.url) {
4065
- url = `${mediaDetails.url}&imageQuality=hq`;
4066
- }
4067
- }
4068
- } catch (_e) {
4069
- }
4070
- url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
4071
- }
4072
4198
  if (!imgId && hasEmbeddedOrLocalFile && url) {
4073
4199
  imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
4074
4200
  }
@@ -4093,14 +4219,25 @@ var Indi = class extends Common {
4093
4219
  }
4094
4220
  return list;
4095
4221
  }
4096
- myheritageLink(poolId = 0) {
4097
- const www = (this.getFromSourceHeads("SOUR.CORP.value") || this._gedcom?.HEAD?.SOUR?.CORP?.value)?.toLowerCase().replace(/^www\./gi, "");
4222
+ myheritageLink(poolId = 0, treeToken) {
4223
+ let www = (this.getFromSourceHeads("SOUR.CORP.value") || this._gedcom?.HEAD?.SOUR?.CORP?.value)?.toLowerCase().replace(/^www\./gi, "");
4224
+ if (!www || /treeviz/i.test(www)) {
4225
+ www = "myheritage.com";
4226
+ }
4227
+ if (!this.id) {
4228
+ return;
4229
+ }
4230
+ const id = Number(this.id.replace(/@|I/g, "")) + poolId;
4231
+ if (!Number.isFinite(id)) {
4232
+ return;
4233
+ }
4234
+ const slug = this.toNaturalName()?.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || String(id);
4235
+ if (treeToken) {
4236
+ return `https://www.${www}/profile-${treeToken}-${id}/${slug}`;
4237
+ }
4098
4238
  const site = this.getMyHeritageTreeId();
4099
- const file = this._gedcom?.HEAD?.get("FILE")?.toValue()?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
4100
- const normalizedFile = file?.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
4101
- if (normalizedFile && this.id) {
4102
- const id = Number(this.id.replace(/@|I/g, "")) + poolId;
4103
- return `https://www.${www}/site-family-tree-${site}/${normalizedFile}#!profile-${id}-info`;
4239
+ if (site) {
4240
+ return `https://www.${www}/person-${id}_${site}_${site}/${slug}`;
4104
4241
  }
4105
4242
  }
4106
4243
  myheritageMedia() {
@@ -4149,6 +4286,14 @@ var Indi = class extends Common {
4149
4286
  });
4150
4287
  return list;
4151
4288
  }
4289
+ geniLink() {
4290
+ if (!this.id) {
4291
+ return;
4292
+ }
4293
+ const id = this.id.replace(/@|I/g, "");
4294
+ const given = this.toNaturalName()?.trim().split(/\s+/)[0] || id;
4295
+ return `https://www.geni.com/people/${given}/${id}`;
4296
+ }
4152
4297
  familySearchLink() {
4153
4298
  const wwwTags = this.get("WWW")?.toList();
4154
4299
  const wwwTag = wwwTags?.find((wwwTag2) => {
@@ -4317,16 +4462,26 @@ var Indi = class extends Common {
4317
4462
  return list;
4318
4463
  }
4319
4464
  async multimedia(namespace) {
4320
- if (this?.isAncestry()) {
4321
- return await this.ancestryMedia(namespace);
4465
+ const lists = [];
4466
+ const ownObjes = this.get("OBJE")?.toList()?.values() ?? [];
4467
+ const ownAncestryMedia = ownObjes.some(
4468
+ (obje) => !!obje && (isAncestryOriginObje(obje) || isAncestryOriginObje(obje.ref))
4469
+ );
4470
+ if (this.isAncestry() || ownAncestryMedia) {
4471
+ lists.push(
4472
+ await this.ancestryMedia(
4473
+ namespace || this.getAncestryMediaNamespace()
4474
+ )
4475
+ );
4322
4476
  }
4323
4477
  if (this?.isMyHeritage()) {
4324
- return this.myheritageMedia();
4478
+ lists.push(this.myheritageMedia());
4325
4479
  }
4326
4480
  if (this?.isGeni()) {
4327
- return this.geniMedia();
4481
+ lists.push(this.geniMedia());
4328
4482
  }
4329
- return this.universalMedia();
4483
+ lists.push(this.universalMedia());
4484
+ return mergeMediaListsByObjeKey(...lists);
4330
4485
  }
4331
4486
  async getProfilePicture(namespace, onlyPrimary = true) {
4332
4487
  if (!this.id) {
@@ -4419,12 +4574,15 @@ var Indi = class extends Common {
4419
4574
  );
4420
4575
  return void 0;
4421
4576
  }
4422
- link(poolId) {
4577
+ link(poolId, treeToken) {
4423
4578
  if (this?.isAncestry()) {
4424
4579
  return this.ancestryLink();
4425
4580
  }
4426
4581
  if (this?.isMyHeritage()) {
4427
- return this.myheritageLink(poolId);
4582
+ return this.myheritageLink(poolId, treeToken);
4583
+ }
4584
+ if (this?.isGeni()) {
4585
+ return this.geniLink();
4428
4586
  }
4429
4587
  if (this?.isFamilySearch()) {
4430
4588
  return this.familySearchLink();
@@ -6184,11 +6342,28 @@ var KinshipTranslatorBasic = class {
6184
6342
  // src/kinship-translator/patterns.hu.ts
6185
6343
  var parentRelationsHu = {
6186
6344
  step: "mostoha",
6187
- foster: "nevelt",
6345
+ foster: { ancestor: "nevel\u0151", other: "nevelt" },
6188
6346
  birth: "v\xE9rszerinti",
6189
6347
  biological: "v\xE9rszerinti",
6190
- adopted: "\xF6r\xF6kbefogadott"
6348
+ adopted: { ancestor: "\xF6r\xF6kbefogad\xF3", other: "\xF6r\xF6kbefogadott" }
6349
+ };
6350
+ var parentRelationPrefix = (relation, ancestor) => {
6351
+ const label = parentRelationsHu[relation];
6352
+ if (!label) {
6353
+ return;
6354
+ }
6355
+ if (typeof label === "string") {
6356
+ return label;
6357
+ }
6358
+ return ancestor ? label.ancestor : label.other;
6191
6359
  };
6360
+ var parentRelationModifiers = [
6361
+ ...new Set(
6362
+ Object.values(parentRelationsHu).flatMap(
6363
+ (label) => typeof label === "string" ? [label] : [label.ancestor, label.other]
6364
+ )
6365
+ )
6366
+ ].join("|");
6192
6367
  var nominativus = {
6193
6368
  apa: { nominativus: "apa", dativus: "apj\xE1nak", possessivus: "apja" },
6194
6369
  anya: { nominativus: "anya", dativus: "anyj\xE1nak", possessivus: "anyja" },
@@ -6266,15 +6441,9 @@ var casesHu = {
6266
6441
  var InLawsHu = {
6267
6442
  "gyermek feles\xE9ge": "meny",
6268
6443
  "gyermek f\xE9rje": "v\u0151",
6269
- [`(f\xE9rj|feles\xE9g) (?<mod1>(${Object.values(parentRelationsHu).join(
6270
- "|"
6271
- )}) )?anyja`]: "any\xF3s",
6272
- [`(f\xE9rj|feles\xE9g) (?<mod1>(${Object.values(parentRelationsHu).join(
6273
- "|"
6274
- )}) )?apja`]: "ap\xF3s",
6275
- [`(f\xE9rj|feles\xE9g) (?<mod1>(${Object.values(parentRelationsHu).join(
6276
- "|"
6277
- )}) )?(f\xE9l)?testv\xE9re`]: (indi) => {
6444
+ [`(f\xE9rj|feles\xE9g) (?<mod1>(${parentRelationModifiers}) )?anyja`]: "any\xF3s",
6445
+ [`(f\xE9rj|feles\xE9g) (?<mod1>(${parentRelationModifiers}) )?apja`]: "ap\xF3s",
6446
+ [`(f\xE9rj|feles\xE9g) (?<mod1>(${parentRelationModifiers}) )?(f\xE9l)?testv\xE9re`]: (indi) => {
6278
6447
  if (indi?.isMale()) {
6279
6448
  return "s\xF3gor";
6280
6449
  }
@@ -6551,7 +6720,12 @@ var KinshipTranslatorHU = class extends KinshipTranslatorBasic {
6551
6720
  if (!relation || !this.pathN?.relation) {
6552
6721
  return relation ?? "";
6553
6722
  }
6554
- return `${parentRelationsHu[this.pathN.relation]} ${relation}`;
6723
+ const isAncestor = (this.pathN.level ?? 0) > 0 && (this.pathN.degree ?? 0) === 0;
6724
+ const prefix = parentRelationPrefix(this.pathN.relation, isAncestor);
6725
+ if (!prefix) {
6726
+ return relation;
6727
+ }
6728
+ return `${prefix} ${relation}`;
6555
6729
  }
6556
6730
  };
6557
6731
 
@@ -6751,6 +6925,10 @@ var KinshipTranslatorEn = class extends KinshipTranslatorBasic {
6751
6925
  if (!relation || !this.pathN?.relation) {
6752
6926
  return relation ?? "";
6753
6927
  }
6928
+ if (this.pathN.relation === "adopted") {
6929
+ const isAncestor = (this.pathN.level ?? 0) > 0 && (this.pathN.degree ?? 0) === 0;
6930
+ return `${isAncestor ? "adoptive" : "adopted"} ${relation}`;
6931
+ }
6754
6932
  return `${this.pathN.relation} ${relation}`;
6755
6933
  }
6756
6934
  };
@@ -7909,6 +8087,39 @@ var lineal = (level, sex, kind) => {
7909
8087
  }
7910
8088
  return `${L - 1}\u4E16\u306E\u5B6B`;
7911
8089
  };
8090
+ var adoptedRelation = (relation) => {
8091
+ if (relation === "\u7236") {
8092
+ return "\u990A\u7236";
8093
+ }
8094
+ if (relation === "\u6BCD") {
8095
+ return "\u990A\u6BCD";
8096
+ }
8097
+ if (relation === "\u89AA") {
8098
+ return "\u990A\u89AA";
8099
+ }
8100
+ if (relation === "\u606F\u5B50" || relation === "\u5B50") {
8101
+ return "\u990A\u5B50";
8102
+ }
8103
+ if (relation === "\u5A18") {
8104
+ return "\u990A\u5973";
8105
+ }
8106
+ return `\u990A${relation}`;
8107
+ };
8108
+ var fosterRelation = (relation) => {
8109
+ if (relation === "\u7236") {
8110
+ return "\u91CC\u7236";
8111
+ }
8112
+ if (relation === "\u6BCD") {
8113
+ return "\u91CC\u6BCD";
8114
+ }
8115
+ if (relation === "\u89AA") {
8116
+ return "\u91CC\u89AA";
8117
+ }
8118
+ if (relation === "\u606F\u5B50" || relation === "\u5A18" || relation === "\u5B50") {
8119
+ return "\u91CC\u5B50";
8120
+ }
8121
+ return `\u91CC${relation}`;
8122
+ };
7912
8123
  var cousinPlain = (degree) => {
7913
8124
  if (degree <= 1) {
7914
8125
  return "\u3044\u3068\u3053";
@@ -8068,10 +8279,10 @@ var KinshipTranslatorJa = class extends KinshipTranslatorBasic {
8068
8279
  return `\u7D99${relation}`;
8069
8280
  }
8070
8281
  if (this.pathN.relation === "adopted") {
8071
- return `\u990A\u5B50\u306E${relation}`;
8282
+ return adoptedRelation(relation);
8072
8283
  }
8073
8284
  if (this.pathN.relation === "foster") {
8074
- return `\u91CC\u89AA\u306E${relation}`;
8285
+ return fosterRelation(relation);
8075
8286
  }
8076
8287
  return relation;
8077
8288
  }
@@ -9365,7 +9576,8 @@ var extractGedzip = async (data) => {
9365
9576
  if (!preferred) {
9366
9577
  throw new Error("No .ged file found in the archive.");
9367
9578
  }
9368
- const gedcomText = await preferred.async("string");
9579
+ const gedcomBytes = await preferred.async("uint8array");
9580
+ const gedcomText = new TextDecoder("utf-8").decode(gedcomBytes);
9369
9581
  const mediaEntries = [];
9370
9582
  for (const entry of entries) {
9371
9583
  const path = normalizeZipPath(entry.name);
@@ -9939,7 +10151,7 @@ var collectExtensionTagsFrom = (node, into = /* @__PURE__ */ new Set()) => {
9939
10151
  // package.json
9940
10152
  var package_default = {
9941
10153
  name: "@treeviz/gedcom-parser",
9942
- version: "2.1.17"};
10154
+ version: "2.1.22"};
9943
10155
 
9944
10156
  // src/utils/get-product-details.ts
9945
10157
  var isDevelopment = () => {
@@ -9948,25 +10160,6 @@ var isDevelopment = () => {
9948
10160
  var getVersion = () => package_default.version;
9949
10161
  var getName = () => package_default.name;
9950
10162
 
9951
- // src/utils/multimedia.ts
9952
- var inferMediaForm = (file, fallback = "bin") => {
9953
- const withoutQuery = file.split("?")[0] || file;
9954
- const ext = getFileExtension(withoutQuery);
9955
- if (ext) {
9956
- return ext.toLowerCase() === "jpeg" ? "jpg" : ext.toLowerCase();
9957
- }
9958
- return fallback;
9959
- };
9960
- var mergeMediaLists = (...lists) => {
9961
- const merged = {};
9962
- for (const list of lists) {
9963
- if (!list) continue;
9964
- Object.assign(merged, list);
9965
- }
9966
- return merged;
9967
- };
9968
- var isObjePointer = (value) => typeof value === "string" && /^@O\d+@$/.test(value);
9969
-
9970
10163
  // src/classes/note.ts
9971
10164
  var CommonNote = class extends Common {
9972
10165
  constructor(gedcom, id, main, parent) {
@@ -10117,6 +10310,10 @@ var Obje = class extends Common {
10117
10310
  if (lkidNode && !newObject.get("_LKID")) {
10118
10311
  newObject.set("_LKID", lkidNode);
10119
10312
  }
10313
+ const origNode = this.get("_ORIG");
10314
+ if (origNode && !newObject.get("_ORIG")) {
10315
+ newObject.set("_ORIG", origNode);
10316
+ }
10120
10317
  if (override) {
10121
10318
  this.remove("FILE");
10122
10319
  this.remove("FORM");
@@ -11367,6 +11564,7 @@ var GedcomTree = {
11367
11564
  return this.parseHierarchy(content, options);
11368
11565
  },
11369
11566
  parseHierarchy: function(content, options) {
11567
+ content = content.replace(/^\uFEFF+/, "");
11370
11568
  const { settings, filename = "" } = options ?? {};
11371
11569
  const { linkedPersons = "skip", linkingKey } = settings ?? {};
11372
11570
  const gedcom = createGedCom();
@@ -11631,4 +11829,4 @@ var createEmptyGedcom = (options) => {
11631
11829
  return gedcom;
11632
11830
  };
11633
11831
 
11634
- export { ACCEPTED_DATE_FORMATS, ACCEPTED_DATE_FORMATS_REGEX, ADOPTED, ANCESTRY_MEDIA_RETRIEVAL_PREFIX, APP_BRANDING, BIOLOGICAL, BIRTH, BIRTH_ASC, BIRTH_DESC, Common, CommonDate, CommonName, CommonNote, CustomTags, DATE_ASC, DATE_DESC, DEATH_ASC, DEATH_DESC, DEFAULT, DEFAULT_GEDCOM_EXPORT_VERSION, EVERY, Existed, FEMALE, FOSTER, FRIEND, Fam, Families, GEDCOM7_CALENDARS, GEDCOM7_PEDI_VALUES, GEDCOM7_RESN_VALUES, GEDCOM7_ROLE_VALUES, GEDCOM7_SEX_VALUES, GEDCOM_EXPORT_VERSIONS, GEDZIP_EXTENSION, GEDZIP_GEDCOM_ENTRY, GEDZIP_MIME, GedCom, parser_default as GedcomTree, ID_GETTER_REG, ID_REG, ID_SPLIT_REG, Indi, Individuals, KinshipTranslator, KinshipTranslatorBasic, KinshipTranslatorDe as KinshipTranslatorDE, KinshipTranslatorEn as KinshipTranslatorEN, KinshipTranslatorEs as KinshipTranslatorES, KinshipTranslatorFr as KinshipTranslatorFR, KinshipTranslatorHU, KinshipTranslatorJa as KinshipTranslatorJA, KinshipTranslatorRu as KinshipTranslatorRU, KinshipTranslatorZh as KinshipTranslatorZH, LINE_REG, List, MALE, MAX_FILE_SIZE_TO_SYNC, ORIG_HEAD_TAG, OTHER, Obje, Objects, PARTNER, PEDIGREE_VALUES, PartnerType, PlaceType, REF_LINE_REG, Range, RelationType, Repo, Repositories, SEALING, SINGLE, SPOUSE, STEP, Sour, Sources, Subm, Submitters, TREEVIZ_EXTENSION_BASE_URI, TREEVIZ_EXTENSION_URIS, UNKOWN, addFamilyFact, addIndividualFact, addNonEvent, ancestryMediaFileUrl, applyGedcom7DatePhrases, applyGedcom7Enumerations, applyGedcom7RecordMetadata, attachChildToFamily, attachSpouseToFamily, buildGedzip, buildGedzipBlob, bytesToDataUrl, cacheDiscoveredPath, canAttachAsSpouse, collectExtensionTagsFrom, commonDateFormatter, consolidateChildIntoFamily, coupleKeyForFam, create, createCommon, createCommonDate, createCommonName, createCommonNote, createEmptyGedcom, createFam, createGedCom, createGedcomUid, createIndi, createObje, createProxy, createRepo, createSour, createSubm, dateFormatter, parser_default as default, deleteIndividual, downloadGedzipMedia, ensureExtensionSchema, extractGedzip, extractGedzipGedcom, extractSeparationYears, extractSplitPoints, familyHasChild, familyHasParent, findDegenerateFamiliesForIndi, findDuplicateCoupleFamiliesForIndi, findMatchingRangeForSplitRange, findReusableParentChildFamily, firstPointerId, formatGedcom7Timestamp, fromTuple, generateSplitRanges, getAllProp, getBirthAsc, getCacheManagerFactory, getDateLocale, getExtensionSchema, getFamilyWith, getFileExtension, getI18n, getKinshipTranslatorClass, getListTag, getMarriageAsc, getMarriageAscAndBirth, getMarriageAscAndChildBirth, getName, getNameAsc, getNameAscAndBirth, getNameDesc, getPlaceParserProvider, getPlaceParts, getPlaceTranslatorProvider, getPlaces, getRawSize, getValidKey, getValidKeys, getValidTag, getVersion, hungarianOrdinalize, i18n, idGetter, implemented, inRange, inferMediaForm, initializeCache, isCommonDate, isDegenerateFamily, isDevelopment, isGedcom7, isGedcomString, isGedzipContainer, isId, isImageFormat, isIntersectedRange, isObjePointer, isOnlyMainProp, isRangeContained, isRemoteOrEmbeddedMediaUrl, isValidKey, makePointer, marriageDateFormatter, mergeDuplicateCoupleFamilies, mergeGedcoms, mergeMediaLists, nameFormatter, nextRecordId, normalizeGedcomVersion, notImplemented, noteDateFormatter, objeNoteValue, objeXrefKey, ordinalize, parseGedcom7CalendarPrefix, parseRangeBounds, pathCache, placeTranslator, pointerIds, profilePictureCache, pruneEmptyFamilies, pruneFamiliesByIds, registerExtensionTag, relativesCache, remountGedzipMediaAsDataUrls, removePointerByValue, resetCacheManagerFactory, resetDateLocaleProvider, resetI18nProvider, resetKinshipTranslatorClass, resetPlaceParserProvider, resetPlaceTranslatorProvider, resetRelativesCache, resolveLocalMediaUrl, resolveMediaContent, resolveObjeForm, resolveObjeMediaId, rewriteGedcomFilePaths, setCacheManagerFactory, setCauseOfDeath, setChildPedigree, setDateLocaleProvider, setDeceased, setFamilyMarriage, setI18nProvider, setKinshipTranslatorClass, setLocalMediaResolver, setMediaContentResolver, setNestedGroup, setPlaceParserProvider, setPlaceTranslatorProvider, splitOverlappingRanges, splitRange, spouseTagFor, toGedcomPedigree, translators_exports as translators, unlinkRelative, updateFactRecord, validateGedcomContent, withGedcom7Calendar };
11832
+ export { ACCEPTED_DATE_FORMATS, ACCEPTED_DATE_FORMATS_REGEX, ADOPTED, ANCESTRY_MEDIA_RETRIEVAL_PREFIX, ANCESTRY_TREE_MEDIA_NAMESPACE, APP_BRANDING, BIOLOGICAL, BIRTH, BIRTH_ASC, BIRTH_DESC, Common, CommonDate, CommonName, CommonNote, CustomTags, DATE_ASC, DATE_DESC, DEATH_ASC, DEATH_DESC, DEFAULT, DEFAULT_GEDCOM_EXPORT_VERSION, EVERY, Existed, FEMALE, FOSTER, FRIEND, Fam, Families, GEDCOM7_CALENDARS, GEDCOM7_PEDI_VALUES, GEDCOM7_RESN_VALUES, GEDCOM7_ROLE_VALUES, GEDCOM7_SEX_VALUES, GEDCOM_EXPORT_VERSIONS, GEDZIP_EXTENSION, GEDZIP_GEDCOM_ENTRY, GEDZIP_MIME, GedCom, parser_default as GedcomTree, ID_GETTER_REG, ID_REG, ID_SPLIT_REG, Indi, Individuals, KinshipTranslator, KinshipTranslatorBasic, KinshipTranslatorDe as KinshipTranslatorDE, KinshipTranslatorEn as KinshipTranslatorEN, KinshipTranslatorEs as KinshipTranslatorES, KinshipTranslatorFr as KinshipTranslatorFR, KinshipTranslatorHU, KinshipTranslatorJa as KinshipTranslatorJA, KinshipTranslatorRu as KinshipTranslatorRU, KinshipTranslatorZh as KinshipTranslatorZH, LINE_REG, List, MALE, MAX_FILE_SIZE_TO_SYNC, ORIG_HEAD_TAG, OTHER, Obje, Objects, PARTNER, PEDIGREE_VALUES, PartnerType, PlaceType, REF_LINE_REG, Range, RelationType, Repo, Repositories, SEALING, SINGLE, SPOUSE, STEP, Sour, Sources, Subm, Submitters, TREEVIZ_EXTENSION_BASE_URI, TREEVIZ_EXTENSION_URIS, UNKOWN, addFamilyFact, addIndividualFact, addNonEvent, ancestryMediaFileUrl, applyGedcom7DatePhrases, applyGedcom7Enumerations, applyGedcom7RecordMetadata, attachChildToFamily, attachSpouseToFamily, buildGedzip, buildGedzipBlob, bytesToDataUrl, cacheDiscoveredPath, canAttachAsSpouse, collectExtensionTagsFrom, commonDateFormatter, consolidateChildIntoFamily, coupleKeyForFam, create, createCommon, createCommonDate, createCommonName, createCommonNote, createEmptyGedcom, createFam, createGedCom, createGedcomUid, createIndi, createObje, createProxy, createRepo, createSour, createSubm, dateFormatter, parser_default as default, deleteIndividual, downloadGedzipMedia, ensureExtensionSchema, extractGedzip, extractGedzipGedcom, extractSeparationYears, extractSplitPoints, familyHasChild, familyHasParent, findDegenerateFamiliesForIndi, findDuplicateCoupleFamiliesForIndi, findMatchingRangeForSplitRange, findReusableParentChildFamily, firstPointerId, formatGedcom7Timestamp, fromTuple, generateSplitRanges, getAllProp, getBirthAsc, getCacheManagerFactory, getDateLocale, getExtensionSchema, getFamilyWith, getFileExtension, getI18n, getKinshipTranslatorClass, getListTag, getMarriageAsc, getMarriageAscAndBirth, getMarriageAscAndChildBirth, getName, getNameAsc, getNameAscAndBirth, getNameDesc, getPlaceParserProvider, getPlaceParts, getPlaceTranslatorProvider, getPlaces, getRawSize, getValidKey, getValidKeys, getValidTag, getVersion, hungarianOrdinalize, i18n, idGetter, implemented, inRange, inferMediaForm, initializeCache, isAncestryOriginObje, isCommonDate, isDegenerateFamily, isDevelopment, isGedcom7, isGedcomString, isGedzipContainer, isId, isImageFormat, isIntersectedRange, isObjePointer, isOnlyMainProp, isRangeContained, isRemoteOrEmbeddedMediaUrl, isValidKey, makePointer, marriageDateFormatter, mergeDuplicateCoupleFamilies, mergeGedcoms, mergeMediaLists, mergeMediaListsByObjeKey, nameFormatter, nextRecordId, normalizeGedcomVersion, notImplemented, noteDateFormatter, objeNoteValue, objeXrefKey, ordinalize, parseAncestryNamespaceFromUrl, parseGedcom7CalendarPrefix, parseRangeBounds, pathCache, placeTranslator, pointerIds, profilePictureCache, pruneEmptyFamilies, pruneFamiliesByIds, registerExtensionTag, relativesCache, remountGedzipMediaAsDataUrls, removePointerByValue, resetCacheManagerFactory, resetDateLocaleProvider, resetI18nProvider, resetKinshipTranslatorClass, resetPlaceParserProvider, resetPlaceTranslatorProvider, resetRelativesCache, resolveLocalMediaUrl, resolveMediaContent, resolveObjeForm, resolveObjeMediaId, rewriteGedcomFilePaths, setCacheManagerFactory, setCauseOfDeath, setChildPedigree, setDateLocaleProvider, setDeceased, setFamilyMarriage, setI18nProvider, setKinshipTranslatorClass, setLocalMediaResolver, setMediaContentResolver, setNestedGroup, setPlaceParserProvider, setPlaceTranslatorProvider, splitOverlappingRanges, splitRange, spouseTagFor, toGedcomPedigree, translators_exports as translators, unlinkRelative, updateFactRecord, validateGedcomContent, withGedcom7Calendar };