@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
|
@@ -2416,6 +2416,30 @@ var mediaIdValue = (obje, path) => {
|
|
|
2416
2416
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2417
2417
|
};
|
|
2418
2418
|
var resolveObjeMediaId = (obje) => mediaIdValue(obje, "RIN") || mediaIdValue(obje, "_CLON._OID") || mediaIdValue(obje, "_MSER._LKID") || mediaIdValue(obje, "_OID") || mediaIdValue(obje, "_LKID");
|
|
2419
|
+
var ANCESTRY_TREE_MEDIA_NAMESPACE = 1093;
|
|
2420
|
+
var ANCESTRY_NAMESPACE_IN_URL = /\/namespaces\/(\d+)\/media\//i;
|
|
2421
|
+
var parseAncestryNamespaceFromUrl = (url) => {
|
|
2422
|
+
if (!url) {
|
|
2423
|
+
return void 0;
|
|
2424
|
+
}
|
|
2425
|
+
const match = url.match(ANCESTRY_NAMESPACE_IN_URL);
|
|
2426
|
+
const namespace = match?.[1] ? Number(match[1]) : NaN;
|
|
2427
|
+
return Number.isFinite(namespace) ? namespace : void 0;
|
|
2428
|
+
};
|
|
2429
|
+
var isAncestryOriginObje = (obje) => {
|
|
2430
|
+
if (!obje) {
|
|
2431
|
+
return false;
|
|
2432
|
+
}
|
|
2433
|
+
const orig = mediaIdValue(obje, "_ORIG");
|
|
2434
|
+
if (orig?.toLowerCase() === "acom") {
|
|
2435
|
+
return true;
|
|
2436
|
+
}
|
|
2437
|
+
const file = mediaIdValue(obje, "FILE") ?? "";
|
|
2438
|
+
if (parseAncestryNamespaceFromUrl(file)) {
|
|
2439
|
+
return true;
|
|
2440
|
+
}
|
|
2441
|
+
return Boolean(resolveObjeMediaId(obje) && !file.trim());
|
|
2442
|
+
};
|
|
2419
2443
|
var ANCESTRY_MEDIA_RETRIEVAL_PREFIX = "https://www.ancestry.com/api/media/retrieval/v2/image";
|
|
2420
2444
|
var ANCESTRY_MEDIA_QUERY = "client=trees-mediaservice&imageQuality=hq";
|
|
2421
2445
|
var ancestryMediaPath = (namespace, imgId) => `/namespaces/${namespace}/media/${imgId}?${ANCESTRY_MEDIA_QUERY}`;
|
|
@@ -2791,8 +2815,25 @@ var Common = class _Common {
|
|
|
2791
2815
|
getHeadRecord() {
|
|
2792
2816
|
return get(this, "HEAD") || get(this.getGedcom(), "HEAD");
|
|
2793
2817
|
}
|
|
2818
|
+
unwrapHeadRecord(node) {
|
|
2819
|
+
if (!node) {
|
|
2820
|
+
return void 0;
|
|
2821
|
+
}
|
|
2822
|
+
const common = node instanceof List ? node.index(0) : node;
|
|
2823
|
+
if (!common || typeof common.get !== "function") {
|
|
2824
|
+
return void 0;
|
|
2825
|
+
}
|
|
2826
|
+
const nested = common.get("HEAD");
|
|
2827
|
+
if (nested instanceof List) {
|
|
2828
|
+
return nested.index(0) ?? common;
|
|
2829
|
+
}
|
|
2830
|
+
if (nested instanceof _Common) {
|
|
2831
|
+
return nested;
|
|
2832
|
+
}
|
|
2833
|
+
return common;
|
|
2834
|
+
}
|
|
2794
2835
|
getOriginalHeadRecord() {
|
|
2795
|
-
return get(this, ORIG_HEAD_TAG) || get(this.getGedcom(), ORIG_HEAD_TAG) || get(this.getHeadRecord(), ORIG_HEAD_TAG);
|
|
2836
|
+
return this.unwrapHeadRecord(get(this, ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getGedcom(), ORIG_HEAD_TAG)) || this.unwrapHeadRecord(get(this.getHeadRecord(), ORIG_HEAD_TAG));
|
|
2796
2837
|
}
|
|
2797
2838
|
getSourceHeads() {
|
|
2798
2839
|
const heads = [this.getOriginalHeadRecord(), this.getHeadRecord()];
|
|
@@ -2800,9 +2841,23 @@ var Common = class _Common {
|
|
|
2800
2841
|
return Boolean(head && heads.indexOf(head) === index);
|
|
2801
2842
|
});
|
|
2802
2843
|
}
|
|
2844
|
+
sourceHeadField(head, path) {
|
|
2845
|
+
const normalized = path.endsWith(".value") ? path.slice(0, -".value".length) : path;
|
|
2846
|
+
const node = head.get(normalized);
|
|
2847
|
+
if (!node) {
|
|
2848
|
+
return void 0;
|
|
2849
|
+
}
|
|
2850
|
+
if (node instanceof List) {
|
|
2851
|
+
return node.index(0)?.toValue();
|
|
2852
|
+
}
|
|
2853
|
+
if (typeof node.toValue === "function") {
|
|
2854
|
+
return node.toValue();
|
|
2855
|
+
}
|
|
2856
|
+
return void 0;
|
|
2857
|
+
}
|
|
2803
2858
|
getFromSourceHeads(path) {
|
|
2804
2859
|
for (const head of this.getSourceHeads()) {
|
|
2805
|
-
const value =
|
|
2860
|
+
const value = this.sourceHeadField(head, path);
|
|
2806
2861
|
if (value !== void 0 && value !== null && value !== "") {
|
|
2807
2862
|
return value;
|
|
2808
2863
|
}
|
|
@@ -2811,8 +2866,8 @@ var Common = class _Common {
|
|
|
2811
2866
|
}
|
|
2812
2867
|
sourStartsWith(prefix) {
|
|
2813
2868
|
return this.getSourceHeads().some((head) => {
|
|
2814
|
-
const sour =
|
|
2815
|
-
return
|
|
2869
|
+
const sour = this.sourceHeadField(head, "SOUR");
|
|
2870
|
+
return typeof sour === "string" && sour.toLowerCase().startsWith(prefix);
|
|
2816
2871
|
});
|
|
2817
2872
|
}
|
|
2818
2873
|
isGenoPro() {
|
|
@@ -2830,6 +2885,51 @@ var Common = class _Common {
|
|
|
2830
2885
|
isMyHeritage() {
|
|
2831
2886
|
return this.sourStartsWith("myheritage");
|
|
2832
2887
|
}
|
|
2888
|
+
/**
|
|
2889
|
+
* GEDCOM root for Ancestry media helpers.
|
|
2890
|
+
* `this._gedcom` when called on a child record; `this` when called on the file root.
|
|
2891
|
+
*
|
|
2892
|
+
* Cannot use `instanceof GedCom`: `GedComType` is a type alias (erased at runtime),
|
|
2893
|
+
* and importing the `GedCom` class here would cycle (`GedCom extends Common`).
|
|
2894
|
+
* The root is the only Common with an `objes()` method.
|
|
2895
|
+
*/
|
|
2896
|
+
hostGedcom() {
|
|
2897
|
+
const linked = this.getGedcom();
|
|
2898
|
+
if (linked) {
|
|
2899
|
+
return linked;
|
|
2900
|
+
}
|
|
2901
|
+
if ("objes" in this && typeof this.objes === "function") {
|
|
2902
|
+
return this;
|
|
2903
|
+
}
|
|
2904
|
+
return void 0;
|
|
2905
|
+
}
|
|
2906
|
+
/** True when the file still has Ancestry tree media (`_ORIG acom`, `_OID`, retrieval URL). */
|
|
2907
|
+
hasAncestryOriginMedia() {
|
|
2908
|
+
const objes = this.hostGedcom()?.objes?.();
|
|
2909
|
+
return objes?.values().some((obje) => isAncestryOriginObje(obje)) ?? false;
|
|
2910
|
+
}
|
|
2911
|
+
/**
|
|
2912
|
+
* Namespace for Ancestry tree photos. Prefer a `namespaces/{id}` FILE URL
|
|
2913
|
+
* (TreeViz GEDCOM 7 / GEDZIP export), otherwise 1093 for member-tree media.
|
|
2914
|
+
*/
|
|
2915
|
+
getAncestryMediaNamespace() {
|
|
2916
|
+
const objes = this.hostGedcom()?.objes?.();
|
|
2917
|
+
if (objes) {
|
|
2918
|
+
for (const obje of objes.values()) {
|
|
2919
|
+
const file = obje?.get("FILE")?.toValue();
|
|
2920
|
+
const fromUrl = parseAncestryNamespaceFromUrl(
|
|
2921
|
+
typeof file === "string" ? file : void 0
|
|
2922
|
+
);
|
|
2923
|
+
if (fromUrl) {
|
|
2924
|
+
return fromUrl;
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
if (this.isAncestry() || this.hasAncestryOriginMedia()) {
|
|
2929
|
+
return ANCESTRY_TREE_MEDIA_NAMESPACE;
|
|
2930
|
+
}
|
|
2931
|
+
return void 0;
|
|
2932
|
+
}
|
|
2833
2933
|
/**
|
|
2834
2934
|
* Get the source type as a string (for prefixing tree IDs and names)
|
|
2835
2935
|
* Returns the detected source type or undefined if unknown
|
|
@@ -2846,13 +2946,13 @@ var Common = class _Common {
|
|
|
2846
2946
|
}
|
|
2847
2947
|
isFamilySearch() {
|
|
2848
2948
|
return this.getSourceHeads().some((head) => {
|
|
2849
|
-
const sourName =
|
|
2949
|
+
const sourName = this.sourceHeadField(head, "SOUR.NAME");
|
|
2850
2950
|
return sourName === "FamilySearch API";
|
|
2851
2951
|
});
|
|
2852
2952
|
}
|
|
2853
2953
|
isGNO2GED() {
|
|
2854
2954
|
return this.getSourceHeads().some((head) => {
|
|
2855
|
-
const sour =
|
|
2955
|
+
const sour = this.sourceHeadField(head, "SOUR");
|
|
2856
2956
|
return sour === "GNO2GED";
|
|
2857
2957
|
});
|
|
2858
2958
|
}
|
|
@@ -2897,8 +2997,7 @@ var Common = class _Common {
|
|
|
2897
2997
|
return this.getFromSourceHeads("SOUR._TREE.value") || (get(this, "HEAD.SOUR._TREE.value") || get(this.getGedcom(), "HEAD.SOUR._TREE.value"));
|
|
2898
2998
|
}
|
|
2899
2999
|
getMyHeritageTreeName() {
|
|
2900
|
-
const
|
|
2901
|
-
const treeDetails = get(this, path) || get(this.getGedcom(), path);
|
|
3000
|
+
const treeDetails = this.getFromSourceHeads("FILE.value") || (get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value"));
|
|
2902
3001
|
return treeDetails?.match(
|
|
2903
3002
|
/Exported by MyHeritage.com from (?<tree>.+) in.+$/
|
|
2904
3003
|
)?.groups?.tree;
|
|
@@ -2915,7 +3014,7 @@ var Common = class _Common {
|
|
|
2915
3014
|
if (treeName) {
|
|
2916
3015
|
return treeName;
|
|
2917
3016
|
}
|
|
2918
|
-
const fileName = get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
|
|
3017
|
+
const fileName = this.getFromSourceHeads("FILE.value") || get(this, "HEAD.FILE.value") || get(this.getGedcom(), "HEAD.FILE.value");
|
|
2919
3018
|
return fileName || "FamilySearch Import";
|
|
2920
3019
|
}
|
|
2921
3020
|
getAhnenblattTreeId() {
|
|
@@ -4995,6 +5094,28 @@ var resolveLocalMediaUrl = async (path, context) => {
|
|
|
4995
5094
|
};
|
|
4996
5095
|
var implemented = (type, ...args) => {
|
|
4997
5096
|
};
|
|
5097
|
+
|
|
5098
|
+
// src/utils/multimedia.ts
|
|
5099
|
+
var mergeMediaListsByObjeKey = (...lists) => {
|
|
5100
|
+
const merged = {};
|
|
5101
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5102
|
+
for (const list of lists) {
|
|
5103
|
+
if (!list) {
|
|
5104
|
+
continue;
|
|
5105
|
+
}
|
|
5106
|
+
for (const [id, item] of Object.entries(list)) {
|
|
5107
|
+
const objeKey = item.key ? String(item.key) : "";
|
|
5108
|
+
if (objeKey && seen.has(objeKey)) {
|
|
5109
|
+
continue;
|
|
5110
|
+
}
|
|
5111
|
+
merged[id] = item;
|
|
5112
|
+
if (objeKey) {
|
|
5113
|
+
seen.add(objeKey);
|
|
5114
|
+
}
|
|
5115
|
+
}
|
|
5116
|
+
}
|
|
5117
|
+
return merged;
|
|
5118
|
+
};
|
|
4998
5119
|
var uniqueItemsCache = /* @__PURE__ */ new WeakMap();
|
|
4999
5120
|
var setNestedGroup = (obj, key, value, uniqueCounting = true) => {
|
|
5000
5121
|
const parts = Array.isArray(key) ? key : key.split(/,\s*/);
|
|
@@ -6254,7 +6375,10 @@ var Indi = class extends Common {
|
|
|
6254
6375
|
return result;
|
|
6255
6376
|
}
|
|
6256
6377
|
ancestryLink() {
|
|
6257
|
-
|
|
6378
|
+
let www = this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
6379
|
+
if (!www || /treeviz/i.test(String(www))) {
|
|
6380
|
+
www = "www.ancestry.com";
|
|
6381
|
+
}
|
|
6258
6382
|
const tree = this.getAncestryTreeId();
|
|
6259
6383
|
if (this.id) {
|
|
6260
6384
|
return `https://${www}/family-tree/person/tree/${tree}/person/${this.id.replace(
|
|
@@ -6266,14 +6390,15 @@ var Indi = class extends Common {
|
|
|
6266
6390
|
async ancestryMedia(namespace) {
|
|
6267
6391
|
const list = {};
|
|
6268
6392
|
const objeList = this.get("OBJE")?.toList().copy();
|
|
6269
|
-
|
|
6393
|
+
this.getFromSourceHeads("SOUR.CORP.WWW.value") || this._gedcom?.HEAD?.SOUR?.CORP?.WWW?.value;
|
|
6270
6394
|
const tree = this.getAncestryTreeId();
|
|
6395
|
+
const usedNamespace = namespace || this.getAncestryMediaNamespace() || ANCESTRY_TREE_MEDIA_NAMESPACE;
|
|
6271
6396
|
if (objeList) {
|
|
6272
6397
|
await Promise.all(
|
|
6273
6398
|
objeList.map(async (objeRef) => {
|
|
6274
6399
|
const key = objeXrefKey(objeRef, 0);
|
|
6275
6400
|
const obje = objeRef?.standardizeMedia(
|
|
6276
|
-
|
|
6401
|
+
usedNamespace,
|
|
6277
6402
|
true,
|
|
6278
6403
|
ancestryMediaFileUrl
|
|
6279
6404
|
);
|
|
@@ -6285,27 +6410,9 @@ var Indi = class extends Common {
|
|
|
6285
6410
|
const type = resolveObjeForm(obje) ?? (url ? getFileExtension(url) : void 0) ?? "raw";
|
|
6286
6411
|
let imgId = media;
|
|
6287
6412
|
const hasEmbeddedOrLocalFile = !!url && (url.startsWith("data:") || url.startsWith("blob:") || !/^https?:\/\//i.test(url));
|
|
6288
|
-
if (!hasEmbeddedOrLocalFile && (!www || !tree || !this.id)) {
|
|
6289
|
-
return;
|
|
6290
|
-
}
|
|
6291
6413
|
if (!this.id) {
|
|
6292
6414
|
return;
|
|
6293
6415
|
}
|
|
6294
|
-
if (!namespace && !url) {
|
|
6295
|
-
try {
|
|
6296
|
-
if (media) {
|
|
6297
|
-
const mediaDetailsResponse = await fetch(
|
|
6298
|
-
`https://www.ancestry.com/api/media/viewer/v2/trees/${tree}/media?id=${media}`
|
|
6299
|
-
);
|
|
6300
|
-
const mediaDetails = await mediaDetailsResponse.json();
|
|
6301
|
-
if (mediaDetails.url) {
|
|
6302
|
-
url = `${mediaDetails.url}&imageQuality=hq`;
|
|
6303
|
-
}
|
|
6304
|
-
}
|
|
6305
|
-
} catch (_e) {
|
|
6306
|
-
}
|
|
6307
|
-
url = url || `https://${www}/mediaui-viewer/tree/${tree}/media/${media}`;
|
|
6308
|
-
}
|
|
6309
6416
|
if (!imgId && hasEmbeddedOrLocalFile && url) {
|
|
6310
6417
|
imgId = typeof media === "string" && media || `local-${String(key).replace(/[@]/g, "")}-${getFileExtension(url) || "bin"}`;
|
|
6311
6418
|
}
|
|
@@ -6331,9 +6438,12 @@ var Indi = class extends Common {
|
|
|
6331
6438
|
return list;
|
|
6332
6439
|
}
|
|
6333
6440
|
myheritageLink(poolId = 0) {
|
|
6334
|
-
|
|
6441
|
+
let www = (this.getFromSourceHeads("SOUR.CORP.value") || this._gedcom?.HEAD?.SOUR?.CORP?.value)?.toLowerCase().replace(/^www\./gi, "");
|
|
6442
|
+
if (!www || /treeviz/i.test(www)) {
|
|
6443
|
+
www = "myheritage.com";
|
|
6444
|
+
}
|
|
6335
6445
|
const site = this.getMyHeritageTreeId();
|
|
6336
|
-
const file = this._gedcom?.HEAD?.get("FILE")?.toValue()?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
6446
|
+
const file = (this.getFromSourceHeads("FILE.value") || this._gedcom?.HEAD?.get("FILE")?.toValue())?.match(/Exported by MyHeritage.com from .+ in (?<site>.+) on .+$/)?.groups?.site;
|
|
6337
6447
|
const normalizedFile = file?.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
6338
6448
|
if (normalizedFile && this.id) {
|
|
6339
6449
|
const id = Number(this.id.replace(/@|I/g, "")) + poolId;
|
|
@@ -6554,16 +6664,26 @@ var Indi = class extends Common {
|
|
|
6554
6664
|
return list;
|
|
6555
6665
|
}
|
|
6556
6666
|
async multimedia(namespace) {
|
|
6557
|
-
|
|
6558
|
-
|
|
6667
|
+
const lists = [];
|
|
6668
|
+
const ownObjes = this.get("OBJE")?.toList()?.values() ?? [];
|
|
6669
|
+
const ownAncestryMedia = ownObjes.some(
|
|
6670
|
+
(obje) => !!obje && (isAncestryOriginObje(obje) || isAncestryOriginObje(obje.ref))
|
|
6671
|
+
);
|
|
6672
|
+
if (this.isAncestry() || ownAncestryMedia) {
|
|
6673
|
+
lists.push(
|
|
6674
|
+
await this.ancestryMedia(
|
|
6675
|
+
namespace || this.getAncestryMediaNamespace()
|
|
6676
|
+
)
|
|
6677
|
+
);
|
|
6559
6678
|
}
|
|
6560
6679
|
if (this?.isMyHeritage()) {
|
|
6561
|
-
|
|
6680
|
+
lists.push(this.myheritageMedia());
|
|
6562
6681
|
}
|
|
6563
6682
|
if (this?.isGeni()) {
|
|
6564
|
-
|
|
6683
|
+
lists.push(this.geniMedia());
|
|
6565
6684
|
}
|
|
6566
|
-
|
|
6685
|
+
lists.push(this.universalMedia());
|
|
6686
|
+
return mergeMediaListsByObjeKey(...lists);
|
|
6567
6687
|
}
|
|
6568
6688
|
async getProfilePicture(namespace, onlyPrimary = true) {
|
|
6569
6689
|
if (!this.id) {
|