@treeviz/gedcom-parser 2.1.17 → 2.1.18
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/classes/common.d.ts +19 -1
- package/dist/classes/common.d.ts.map +1 -1
- package/dist/classes/index.js +178 -56
- package/dist/classes/indi.d.ts.map +1 -1
- package/dist/classes/obje.d.ts +1 -1
- package/dist/classes/obje.d.ts.map +1 -1
- package/dist/cli/index.js +178 -56
- package/dist/constants/index.js +157 -37
- package/dist/factories/index.js +157 -37
- package/dist/index.js +180 -58
- package/dist/kinship-translator/index.js +157 -37
- package/dist/utils/index.js +180 -58
- package/dist/utils/media-utils.d.ts +10 -0
- package/dist/utils/media-utils.d.ts.map +1 -1
- package/dist/utils/multimedia.d.ts +5 -0
- package/dist/utils/multimedia.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/factories/index.js
CHANGED
|
@@ -165,6 +165,30 @@ var mediaIdValue = (obje, path) => {
|
|
|
165
165
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
166
166
|
};
|
|
167
167
|
var resolveObjeMediaId = (obje) => mediaIdValue(obje, "RIN") || mediaIdValue(obje, "_CLON._OID") || mediaIdValue(obje, "_MSER._LKID") || mediaIdValue(obje, "_OID") || mediaIdValue(obje, "_LKID");
|
|
168
|
+
var ANCESTRY_TREE_MEDIA_NAMESPACE = 1093;
|
|
169
|
+
var ANCESTRY_NAMESPACE_IN_URL = /\/namespaces\/(\d+)\/media\//i;
|
|
170
|
+
var parseAncestryNamespaceFromUrl = (url) => {
|
|
171
|
+
if (!url) {
|
|
172
|
+
return void 0;
|
|
173
|
+
}
|
|
174
|
+
const match = url.match(ANCESTRY_NAMESPACE_IN_URL);
|
|
175
|
+
const namespace = match?.[1] ? Number(match[1]) : NaN;
|
|
176
|
+
return Number.isFinite(namespace) ? namespace : void 0;
|
|
177
|
+
};
|
|
178
|
+
var isAncestryOriginObje = (obje) => {
|
|
179
|
+
if (!obje) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
const orig = mediaIdValue(obje, "_ORIG");
|
|
183
|
+
if (orig?.toLowerCase() === "acom") {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
const file = mediaIdValue(obje, "FILE") ?? "";
|
|
187
|
+
if (parseAncestryNamespaceFromUrl(file)) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
return Boolean(resolveObjeMediaId(obje) && !file.trim());
|
|
191
|
+
};
|
|
168
192
|
var ANCESTRY_MEDIA_RETRIEVAL_PREFIX = "https://www.ancestry.com/api/media/retrieval/v2/image";
|
|
169
193
|
var ANCESTRY_MEDIA_QUERY = "client=trees-mediaservice&imageQuality=hq";
|
|
170
194
|
var ancestryMediaPath = (namespace, imgId) => `/namespaces/${namespace}/media/${imgId}?${ANCESTRY_MEDIA_QUERY}`;
|
|
@@ -540,8 +564,25 @@ var Common = class _Common {
|
|
|
540
564
|
getHeadRecord() {
|
|
541
565
|
return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
|
|
542
566
|
}
|
|
567
|
+
unwrapHeadRecord(node) {
|
|
568
|
+
if (!node) {
|
|
569
|
+
return void 0;
|
|
570
|
+
}
|
|
571
|
+
const common = node instanceof List ? node.index(0) : node;
|
|
572
|
+
if (!common || typeof common.get !== "function") {
|
|
573
|
+
return void 0;
|
|
574
|
+
}
|
|
575
|
+
const nested = common.get("HEAD");
|
|
576
|
+
if (nested instanceof List) {
|
|
577
|
+
return nested.index(0) ?? common;
|
|
578
|
+
}
|
|
579
|
+
if (nested instanceof _Common) {
|
|
580
|
+
return nested;
|
|
581
|
+
}
|
|
582
|
+
return common;
|
|
583
|
+
}
|
|
543
584
|
getOriginalHeadRecord() {
|
|
544
|
-
return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
|
|
585
|
+
return this.unwrapHeadRecord(get(this, ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getGedcom(), ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getHeadRecord(), ORIG_HEAD_TAG));
|
|
545
586
|
}
|
|
546
587
|
getSourceHeads() {
|
|
547
588
|
const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
|
|
@@ -549,9 +590,23 @@ var Common = class _Common {
|
|
|
549
590
|
return Boolean(head && heads.indexOf(head) === index);
|
|
550
591
|
});
|
|
551
592
|
}
|
|
593
|
+
sourceHeadField(head, path) {
|
|
594
|
+
const normalized = path.endsWith(".value") ? path.slice(0, -".value".length) : path;
|
|
595
|
+
const node = head.get(normalized);
|
|
596
|
+
if (!node) {
|
|
597
|
+
return void 0;
|
|
598
|
+
}
|
|
599
|
+
if (node instanceof List) {
|
|
600
|
+
return node.index(0)?.toValue();
|
|
601
|
+
}
|
|
602
|
+
if (typeof node.toValue === "function") {
|
|
603
|
+
return node.toValue();
|
|
604
|
+
}
|
|
605
|
+
return void 0;
|
|
606
|
+
}
|
|
552
607
|
getFromSourceHeads(path) {
|
|
553
608
|
for (const head of this.getSourceHeads()) {
|
|
554
|
-
const value =
|
|
609
|
+
const value = this.sourceHeadField(head, path);
|
|
555
610
|
if (value !== void 0 && value !== null && value !== "") {
|
|
556
611
|
return value;
|
|
557
612
|
}
|
|
@@ -560,8 +615,8 @@ var Common = class _Common {
|
|
|
560
615
|
}
|
|
561
616
|
sourStartsWith(prefix) {
|
|
562
617
|
return this.getSourceHeads().some((head) => {
|
|
563
|
-
const sour =
|
|
564
|
-
return
|
|
618
|
+
const sour = this.sourceHeadField(head, "SOUR");
|
|
619
|
+
return typeof sour === "string" && sour.toLowerCase().startsWith(prefix);
|
|
565
620
|
});
|
|
566
621
|
}
|
|
567
622
|
isGenoPro() {
|
|
@@ -579,6 +634,51 @@ var Common = class _Common {
|
|
|
579
634
|
isMyHeritage() {
|
|
580
635
|
return this.sourStartsWith("myheritage");
|
|
581
636
|
}
|
|
637
|
+
/**
|
|
638
|
+
* GEDCOM root for Ancestry media helpers.
|
|
639
|
+
* `this._gedcom` when called on a child record; `this` when called on the file root.
|
|
640
|
+
*
|
|
641
|
+
* Cannot use `instanceof GedCom`: `GedComType` is a type alias (erased at runtime),
|
|
642
|
+
* and importing the `GedCom` class here would cycle (`GedCom extends Common`).
|
|
643
|
+
* The root is the only Common with an `objes()` method.
|
|
644
|
+
*/
|
|
645
|
+
hostGedcom() {
|
|
646
|
+
const linked = this.getGedcom();
|
|
647
|
+
if (linked) {
|
|
648
|
+
return linked;
|
|
649
|
+
}
|
|
650
|
+
if ("objes" in this && typeof this.objes === "function") {
|
|
651
|
+
return this;
|
|
652
|
+
}
|
|
653
|
+
return void 0;
|
|
654
|
+
}
|
|
655
|
+
/** True when the file still has Ancestry tree media (`_ORIG acom`, `_OID`, retrieval URL). */
|
|
656
|
+
hasAncestryOriginMedia() {
|
|
657
|
+
const objes = this.hostGedcom()?.objes?.();
|
|
658
|
+
return objes?.values().some((obje) => isAncestryOriginObje(obje)) ?? false;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Namespace for Ancestry tree photos. Prefer a `namespaces/{id}` FILE URL
|
|
662
|
+
* (TreeViz GEDCOM 7 / GEDZIP export), otherwise 1093 for member-tree media.
|
|
663
|
+
*/
|
|
664
|
+
getAncestryMediaNamespace() {
|
|
665
|
+
const objes = this.hostGedcom()?.objes?.();
|
|
666
|
+
if (objes) {
|
|
667
|
+
for (const obje of objes.values()) {
|
|
668
|
+
const file = obje?.get("FILE")?.toValue();
|
|
669
|
+
const fromUrl = parseAncestryNamespaceFromUrl(
|
|
670
|
+
typeof file === "string" ? file : void 0
|
|
671
|
+
);
|
|
672
|
+
if (fromUrl) {
|
|
673
|
+
return fromUrl;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (this.isAncestry() || this.hasAncestryOriginMedia()) {
|
|
678
|
+
return ANCESTRY_TREE_MEDIA_NAMESPACE;
|
|
679
|
+
}
|
|
680
|
+
return void 0;
|
|
681
|
+
}
|
|
582
682
|
/**
|
|
583
683
|
* Get the source type as a string (for prefixing tree IDs and names)
|
|
584
684
|
* Returns the detected source type or undefined if unknown
|
|
@@ -595,13 +695,13 @@ var Common = class _Common {
|
|
|
595
695
|
}
|
|
596
696
|
isFamilySearch() {
|
|
597
697
|
return this.getSourceHeads().some((head) => {
|
|
598
|
-
const sourName =
|
|
698
|
+
const sourName = this.sourceHeadField(head, "SOUR.NAME");
|
|
599
699
|
return sourName === "FamilySearch API";
|
|
600
700
|
});
|
|
601
701
|
}
|
|
602
702
|
isGNO2GED() {
|
|
603
703
|
return this.getSourceHeads().some((head) => {
|
|
604
|
-
const sour =
|
|
704
|
+
const sour = this.sourceHeadField(head, "SOUR");
|
|
605
705
|
return sour === "GNO2GED";
|
|
606
706
|
});
|
|
607
707
|
}
|
|
@@ -646,8 +746,7 @@ var Common = class _Common {
|
|
|
646
746
|
return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
|
|
647
747
|
}
|
|
648
748
|
getMyHeritageTreeName() {
|
|
649
|
-
const
|
|
650
|
-
const treeDetails = get(this, path) || get(this.getGedcom(), path);
|
|
749
|
+
const treeDetails = this.getFromSourceHeads("FILE.value") || (get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value"));
|
|
651
750
|
return treeDetails?.match(
|
|
652
751
|
/Exported by MyHeritage.com from (?<tree>.+) in.+$/
|
|
653
752
|
)?.groups?.tree;
|
|
@@ -664,7 +763,7 @@ var Common = class _Common {
|
|
|
664
763
|
if (treeName) {
|
|
665
764
|
return treeName;
|
|
666
765
|
}
|
|
667
|
-
const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
|
|
766
|
+
const fileName = this.getFromSourceHeads("FILE.value") || get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
|
|
668
767
|
return fileName || "FamilySearch Import";
|
|
669
768
|
}
|
|
670
769
|
getAhnenblattTreeId() {
|
|
@@ -2745,6 +2844,28 @@ var resolveLocalMediaUrl = async (path, context) => {
|
|
|
2745
2844
|
var implemented = (type, ...args) => {
|
|
2746
2845
|
};
|
|
2747
2846
|
|
|
2847
|
+
// src/utils/multimedia.ts
|
|
2848
|
+
var mergeMediaListsByObjeKey = (...lists) => {
|
|
2849
|
+
const merged = {};
|
|
2850
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2851
|
+
for (const list of lists) {
|
|
2852
|
+
if (!list) {
|
|
2853
|
+
continue;
|
|
2854
|
+
}
|
|
2855
|
+
for (const [id, item] of Object.entries(list)) {
|
|
2856
|
+
const objeKey = item.key ? String(item.key) : "";
|
|
2857
|
+
if (objeKey && seen.has(objeKey)) {
|
|
2858
|
+
continue;
|
|
2859
|
+
}
|
|
2860
|
+
merged[id] = item;
|
|
2861
|
+
if (objeKey) {
|
|
2862
|
+
seen.add(objeKey);
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
return merged;
|
|
2867
|
+
};
|
|
2868
|
+
|
|
2748
2869
|
// src/factories/place-parser-provider.ts
|
|
2749
2870
|
var placeParserProvider;
|
|
2750
2871
|
var setPlaceParserProvider = (parser) => {
|
|
@@ -4031,7 +4152,10 @@ var Indi = class extends Common {
|
|
|
4031
4152
|
return result;
|
|
4032
4153
|
}
|
|
4033
4154
|
ancestryLink() {
|
|
4034
|
-
|
|
4155
|
+
let www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
4156
|
+
if (!www || /treeviz/i.test(String(www))) {
|
|
4157
|
+
www = "www.ancestry.com";
|
|
4158
|
+
}
|
|
4035
4159
|
const tree = this.getAncestryTreeId();
|
|
4036
4160
|
if (this.id) {
|
|
4037
4161
|
return `https://${www}/family-tree/person/tree/${tree}/person/${this.id.replace(
|
|
@@ -4043,14 +4167,15 @@ var Indi = class extends Common {
|
|
|
4043
4167
|
async ancestryMedia(namespace) {
|
|
4044
4168
|
const list = {};
|
|
4045
4169
|
const objeList = this.get("OBJE")?.toList().copy();
|
|
4046
|
-
|
|
4170
|
+
this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
4047
4171
|
const tree = this.getAncestryTreeId();
|
|
4172
|
+
const usedNamespace = namespace || this.getAncestryMediaNamespace() || ANCESTRY_TREE_MEDIA_NAMESPACE;
|
|
4048
4173
|
if (objeList) {
|
|
4049
4174
|
await Promise.all(
|
|
4050
4175
|
objeList.map(async (objeRef) => {
|
|
4051
4176
|
const key = objeXrefKey(objeRef, 0);
|
|
4052
4177
|
const obje = objeRef?.standardizeMedia(
|
|
4053
|
-
|
|
4178
|
+
usedNamespace,
|
|
4054
4179
|
true,
|
|
4055
4180
|
ancestryMediaFileUrl
|
|
4056
4181
|
);
|
|
@@ -4062,27 +4187,9 @@ var Indi = class extends Common {
|
|
|
4062
4187
|
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
4063
4188
|
let imgId = media;
|
|
4064
4189
|
const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
|
|
4065
|
-
if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
|
|
4066
|
-
return;
|
|
4067
|
-
}
|
|
4068
4190
|
if (!this.id) {
|
|
4069
4191
|
return;
|
|
4070
4192
|
}
|
|
4071
|
-
if (!namespace && !url) {
|
|
4072
|
-
try {
|
|
4073
|
-
if (media) {
|
|
4074
|
-
const mediaDetailsResponse = await fetch(
|
|
4075
|
-
`https://www.ancestry.com/api/media/viewer/v2/trees/${tree}/media?id=${media}`
|
|
4076
|
-
);
|
|
4077
|
-
const mediaDetails = await mediaDetailsResponse.json();
|
|
4078
|
-
if (mediaDetails.url) {
|
|
4079
|
-
url = `${mediaDetails.url}&imageQuality=hq`;
|
|
4080
|
-
}
|
|
4081
|
-
}
|
|
4082
|
-
} catch (_e) {
|
|
4083
|
-
}
|
|
4084
|
-
url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
|
|
4085
|
-
}
|
|
4086
4193
|
if (!imgId && hasEmbeddedOrLocalFile && url) {
|
|
4087
4194
|
imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
|
|
4088
4195
|
}
|
|
@@ -4108,9 +4215,12 @@ var Indi = class extends Common {
|
|
|
4108
4215
|
return list;
|
|
4109
4216
|
}
|
|
4110
4217
|
myheritageLink(poolId = 0) {
|
|
4111
|
-
|
|
4218
|
+
let www = (this.getFromSourceHeads("SOUR.CORP.value") || this._gedcom?.HEAD?.SOUR?.CORP?.value)?.toLowerCase().replace(/^www\./gi, "");
|
|
4219
|
+
if (!www || /treeviz/i.test(www)) {
|
|
4220
|
+
www = "myheritage.com";
|
|
4221
|
+
}
|
|
4112
4222
|
const site = this.getMyHeritageTreeId();
|
|
4113
|
-
const file = this._gedcom?.HEAD?.get("FILE")?.toValue()?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
4223
|
+
const file = (this.getFromSourceHeads("FILE.value") || this._gedcom?.HEAD?.get("FILE")?.toValue())?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
4114
4224
|
const normalizedFile = file?.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
4115
4225
|
if (normalizedFile && this.id) {
|
|
4116
4226
|
const id = Number(this.id.replace(/@|I/g, "")) + poolId;
|
|
@@ -4331,16 +4441,26 @@ var Indi = class extends Common {
|
|
|
4331
4441
|
return list;
|
|
4332
4442
|
}
|
|
4333
4443
|
async multimedia(namespace) {
|
|
4334
|
-
|
|
4335
|
-
|
|
4444
|
+
const lists = [];
|
|
4445
|
+
const ownObjes = this.get("OBJE")?.toList()?.values() ?? [];
|
|
4446
|
+
const ownAncestryMedia = ownObjes.some(
|
|
4447
|
+
(obje) => !!obje && (isAncestryOriginObje(obje) || isAncestryOriginObje(obje.ref))
|
|
4448
|
+
);
|
|
4449
|
+
if (this.isAncestry() || ownAncestryMedia) {
|
|
4450
|
+
lists.push(
|
|
4451
|
+
await this.ancestryMedia(
|
|
4452
|
+
namespace || this.getAncestryMediaNamespace()
|
|
4453
|
+
)
|
|
4454
|
+
);
|
|
4336
4455
|
}
|
|
4337
4456
|
if (this?.isMyHeritage()) {
|
|
4338
|
-
|
|
4457
|
+
lists.push(this.myheritageMedia());
|
|
4339
4458
|
}
|
|
4340
4459
|
if (this?.isGeni()) {
|
|
4341
|
-
|
|
4460
|
+
lists.push(this.geniMedia());
|
|
4342
4461
|
}
|
|
4343
|
-
|
|
4462
|
+
lists.push(this.universalMedia());
|
|
4463
|
+
return mergeMediaListsByObjeKey(...lists);
|
|
4344
4464
|
}
|
|
4345
4465
|
async getProfilePicture(namespace, onlyPrimary = true) {
|
|
4346
4466
|
if (!this.id) {
|