@treeviz/gedcom-parser 2.1.28 → 2.1.30
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/gedcom.d.ts +2 -0
- package/dist/classes/gedcom.d.ts.map +1 -1
- package/dist/classes/index.js +235 -7
- package/dist/classes/indi.d.ts.map +1 -1
- package/dist/cli/index.js +238 -7
- package/dist/constants/index.js +150 -4
- package/dist/factories/index.js +150 -4
- package/dist/index.js +239 -8
- package/dist/interfaces/indi.d.ts +2 -0
- package/dist/interfaces/indi.d.ts.map +1 -1
- package/dist/kinship-translator/index.js +150 -4
- package/dist/types/types.d.ts +1 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/utils/index.js +155 -6
- package/dist/utils/media-utils.d.ts +18 -0
- package/dist/utils/media-utils.d.ts.map +1 -1
- package/dist/utils/multimedia.d.ts.map +1 -1
- package/dist/utils/parser.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -140,6 +140,100 @@ var objeXrefKey = (obje, fallback = 0) => {
|
|
|
140
140
|
return `@O${fallback}@`;
|
|
141
141
|
};
|
|
142
142
|
var objeNoteValue = (obje) => mediaIdValue(obje, "FILE.NOTE") || mediaIdValue(obje, "NOTE") || "";
|
|
143
|
+
var FS_WEB_RE = /familysearch\.org/i;
|
|
144
|
+
var FS_ARK_ID_RE = /^(?:ark:\/[^/]+\/)?([123]:[12]:[A-Za-z0-9-]+)$/i;
|
|
145
|
+
var listItems = (list) => {
|
|
146
|
+
if (!list) {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
if (typeof list.values === "function") {
|
|
150
|
+
return list.values();
|
|
151
|
+
}
|
|
152
|
+
if (typeof list.forEach === "function") {
|
|
153
|
+
const items = [];
|
|
154
|
+
list.forEach((item) => items.push(item));
|
|
155
|
+
return items;
|
|
156
|
+
}
|
|
157
|
+
return [];
|
|
158
|
+
};
|
|
159
|
+
var toList = (node) => {
|
|
160
|
+
if (!node) {
|
|
161
|
+
return void 0;
|
|
162
|
+
}
|
|
163
|
+
const maybe = node;
|
|
164
|
+
if (typeof maybe.toList === "function") {
|
|
165
|
+
return maybe.toList();
|
|
166
|
+
}
|
|
167
|
+
if (typeof maybe.values === "function" || typeof maybe.forEach === "function") {
|
|
168
|
+
return maybe;
|
|
169
|
+
}
|
|
170
|
+
return void 0;
|
|
171
|
+
};
|
|
172
|
+
var normalizeFsWebUrl = (url) => {
|
|
173
|
+
const trimmed = url.trim();
|
|
174
|
+
if (!trimmed || !FS_WEB_RE.test(trimmed)) {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
if (/\/dist\.jpg|\/service\/records\/storage\/|\/platform\//i.test(trimmed)) {
|
|
178
|
+
return void 0;
|
|
179
|
+
}
|
|
180
|
+
return trimmed;
|
|
181
|
+
};
|
|
182
|
+
var familySearchMediaOriginUrl = (obje, indi) => {
|
|
183
|
+
if (!obje) {
|
|
184
|
+
return void 0;
|
|
185
|
+
}
|
|
186
|
+
const resolved = obje.ref && typeof obje.toValue?.() === "string" ? obje.ref : obje;
|
|
187
|
+
const directWww = mediaIdValue(resolved, "WWW") || mediaIdValue(obje, "WWW");
|
|
188
|
+
const fromWww = directWww ? normalizeFsWebUrl(directWww) : void 0;
|
|
189
|
+
if (fromWww) {
|
|
190
|
+
return fromWww;
|
|
191
|
+
}
|
|
192
|
+
const objeKey = objeXrefKey(obje);
|
|
193
|
+
const sourItems = listItems(toList(indi?.get?.("SOUR")));
|
|
194
|
+
for (const sour of sourItems) {
|
|
195
|
+
if (!sour) continue;
|
|
196
|
+
const sourWww = mediaIdValue(sour, "WWW");
|
|
197
|
+
const normalized = sourWww ? normalizeFsWebUrl(sourWww) : void 0;
|
|
198
|
+
if (!normalized) continue;
|
|
199
|
+
const sourIsFs = mediaIdValue(sour, "_IS_FS") === "Y" || FS_WEB_RE.test(normalized);
|
|
200
|
+
if (!sourIsFs) continue;
|
|
201
|
+
let linksThisObje = false;
|
|
202
|
+
for (const ref of listItems(toList(sour.get?.("OBJE")))) {
|
|
203
|
+
if (ref && objeXrefKey(ref) === objeKey) {
|
|
204
|
+
linksThisObje = true;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const sourFsId = mediaIdValue(sour, "_FS_ID");
|
|
209
|
+
const objeFsId = mediaIdValue(resolved, "_FS_ID") || mediaIdValue(obje, "_FS_ID");
|
|
210
|
+
if (linksThisObje || sourFsId && objeFsId && sourFsId === objeFsId) {
|
|
211
|
+
return normalized;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const isFs = mediaIdValue(resolved, "_IS_FS") === "Y" || mediaIdValue(obje, "_IS_FS") === "Y";
|
|
215
|
+
const fsId = mediaIdValue(resolved, "_FS_ID") || mediaIdValue(obje, "_FS_ID");
|
|
216
|
+
if (!isFs || !fsId) {
|
|
217
|
+
return void 0;
|
|
218
|
+
}
|
|
219
|
+
const arkMatch = fsId.match(FS_ARK_ID_RE);
|
|
220
|
+
if (arkMatch?.[1]) {
|
|
221
|
+
return `https://www.familysearch.org/ark:/61903/${arkMatch[1]}`;
|
|
222
|
+
}
|
|
223
|
+
if (/^\d+$/.test(fsId)) {
|
|
224
|
+
return `https://www.familysearch.org/photos/artifacts/${fsId}`;
|
|
225
|
+
}
|
|
226
|
+
for (const sour of sourItems) {
|
|
227
|
+
if (!sour) continue;
|
|
228
|
+
if (mediaIdValue(sour, "_FS_ID") !== fsId) continue;
|
|
229
|
+
const sourWww = mediaIdValue(sour, "WWW");
|
|
230
|
+
const normalized = sourWww ? normalizeFsWebUrl(sourWww) : void 0;
|
|
231
|
+
if (normalized) {
|
|
232
|
+
return normalized;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return void 0;
|
|
236
|
+
};
|
|
143
237
|
var List = class _List {
|
|
144
238
|
// length = 0;
|
|
145
239
|
constructor(items) {
|
|
@@ -2257,6 +2351,14 @@ var mergeMediaListsByObjeKey = (...lists) => {
|
|
|
2257
2351
|
for (const [id, item] of Object.entries(list)) {
|
|
2258
2352
|
const objeKey = item.key ? String(item.key) : "";
|
|
2259
2353
|
if (objeKey && seen.has(objeKey)) {
|
|
2354
|
+
if (item.originUrl) {
|
|
2355
|
+
const existing = Object.values(merged).find(
|
|
2356
|
+
(entry) => entry.key === objeKey
|
|
2357
|
+
);
|
|
2358
|
+
if (existing && !existing.originUrl) {
|
|
2359
|
+
existing.originUrl = item.originUrl;
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2260
2362
|
continue;
|
|
2261
2363
|
}
|
|
2262
2364
|
merged[id] = item;
|
|
@@ -3470,6 +3572,10 @@ var Indi = class extends Common {
|
|
|
3470
3572
|
}
|
|
3471
3573
|
if (url && imgId) {
|
|
3472
3574
|
const id = `${tree || "gedzip"}-${this.id}-${imgId}`;
|
|
3575
|
+
const originUrl = familySearchMediaOriginUrl(
|
|
3576
|
+
objeRef ?? obje,
|
|
3577
|
+
this
|
|
3578
|
+
);
|
|
3473
3579
|
list[id] = {
|
|
3474
3580
|
key,
|
|
3475
3581
|
isPrimary,
|
|
@@ -3481,7 +3587,8 @@ var Indi = class extends Common {
|
|
|
3481
3587
|
note,
|
|
3482
3588
|
url,
|
|
3483
3589
|
contentType: type,
|
|
3484
|
-
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}
|
|
3590
|
+
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`,
|
|
3591
|
+
...originUrl ? { originUrl } : {}
|
|
3485
3592
|
};
|
|
3486
3593
|
}
|
|
3487
3594
|
})
|
|
@@ -3701,18 +3808,39 @@ var Indi = class extends Common {
|
|
|
3701
3808
|
if (!this.id) {
|
|
3702
3809
|
return list;
|
|
3703
3810
|
}
|
|
3704
|
-
|
|
3811
|
+
let objeList = this.get("OBJE")?.toList().copy();
|
|
3812
|
+
const sourList = this.get("SOUR")?.toList();
|
|
3813
|
+
sourList?.forEach((sour) => {
|
|
3814
|
+
const sourObje = sour?.get("OBJE")?.toList();
|
|
3815
|
+
if (!sourObje?.length) {
|
|
3816
|
+
return;
|
|
3817
|
+
}
|
|
3818
|
+
if (!objeList) {
|
|
3819
|
+
objeList = sourObje.copy();
|
|
3820
|
+
} else {
|
|
3821
|
+
objeList.merge(sourObje);
|
|
3822
|
+
}
|
|
3823
|
+
});
|
|
3705
3824
|
if (!objeList || objeList.length === 0) {
|
|
3706
3825
|
return list;
|
|
3707
3826
|
}
|
|
3708
3827
|
const rfn = this.get("RFN")?.toValue();
|
|
3709
3828
|
const treeId = this.getUniversalTreeId() || rfn || "universal";
|
|
3829
|
+
const seenFsIds = /* @__PURE__ */ new Set();
|
|
3710
3830
|
objeList.forEach((obje, index) => {
|
|
3711
3831
|
if (!obje) {
|
|
3712
3832
|
return;
|
|
3713
3833
|
}
|
|
3714
3834
|
const key = objeXrefKey(obje, index);
|
|
3715
3835
|
obje.standardizeMedia();
|
|
3836
|
+
const fsId = obje?.get("_FS_ID")?.toValue?.();
|
|
3837
|
+
if (typeof fsId === "string" && fsId.trim()) {
|
|
3838
|
+
const normalized = fsId.trim();
|
|
3839
|
+
if (seenFsIds.has(normalized)) {
|
|
3840
|
+
return;
|
|
3841
|
+
}
|
|
3842
|
+
seenFsIds.add(normalized);
|
|
3843
|
+
}
|
|
3716
3844
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3717
3845
|
const url = obje?.get("FILE")?.toValue();
|
|
3718
3846
|
const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
|
|
@@ -3720,6 +3848,7 @@ var Indi = class extends Common {
|
|
|
3720
3848
|
if (url) {
|
|
3721
3849
|
const imgId = `media-${index}-${url.startsWith("data:") ? getFileExtension(url) || "bin" : url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
|
|
3722
3850
|
const id = `${treeId}-${this.id}-${imgId}`;
|
|
3851
|
+
const originUrl = familySearchMediaOriginUrl(obje, this);
|
|
3723
3852
|
list[id] = {
|
|
3724
3853
|
isPrimary,
|
|
3725
3854
|
key,
|
|
@@ -3731,7 +3860,8 @@ var Indi = class extends Common {
|
|
|
3731
3860
|
note: objeNoteValue(obje),
|
|
3732
3861
|
url,
|
|
3733
3862
|
contentType: type,
|
|
3734
|
-
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}
|
|
3863
|
+
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`,
|
|
3864
|
+
...originUrl ? { originUrl } : {}
|
|
3735
3865
|
};
|
|
3736
3866
|
}
|
|
3737
3867
|
});
|
|
@@ -3757,7 +3887,23 @@ var Indi = class extends Common {
|
|
|
3757
3887
|
lists.push(this.geniMedia());
|
|
3758
3888
|
}
|
|
3759
3889
|
lists.push(this.universalMedia());
|
|
3760
|
-
|
|
3890
|
+
const merged = mergeMediaListsByObjeKey(...lists);
|
|
3891
|
+
const seenFsIds = /* @__PURE__ */ new Set();
|
|
3892
|
+
const deduped = {};
|
|
3893
|
+
for (const [id, media] of Object.entries(merged ?? {})) {
|
|
3894
|
+
const xref = media.key ? String(media.key) : "";
|
|
3895
|
+
const top = xref && this._gedcom ? this._gedcom.obje(xref) : void 0;
|
|
3896
|
+
const fsId = top?.get("_FS_ID")?.toValue?.();
|
|
3897
|
+
if (typeof fsId === "string" && fsId.trim()) {
|
|
3898
|
+
const normalized = fsId.trim();
|
|
3899
|
+
if (seenFsIds.has(normalized)) {
|
|
3900
|
+
continue;
|
|
3901
|
+
}
|
|
3902
|
+
seenFsIds.add(normalized);
|
|
3903
|
+
}
|
|
3904
|
+
deduped[id] = media;
|
|
3905
|
+
}
|
|
3906
|
+
return deduped;
|
|
3761
3907
|
}
|
|
3762
3908
|
async getProfilePicture(namespace, onlyPrimary = true) {
|
|
3763
3909
|
if (!this.id) {
|
|
@@ -9279,7 +9425,7 @@ var ensureExtensionSchema = (gedcom, extraTags) => {
|
|
|
9279
9425
|
|
|
9280
9426
|
// package.json
|
|
9281
9427
|
var package_default = {
|
|
9282
|
-
version: "2.1.
|
|
9428
|
+
version: "2.1.30"};
|
|
9283
9429
|
|
|
9284
9430
|
// src/utils/get-product-details.ts
|
|
9285
9431
|
var isDevelopment = () => {
|
|
@@ -10319,26 +10465,47 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10319
10465
|
const mergedGedcom = targetGedcom;
|
|
10320
10466
|
const idMap = /* @__PURE__ */ new Map();
|
|
10321
10467
|
const matchMap = /* @__PURE__ */ new Map();
|
|
10468
|
+
const reusedTopLevelIds = /* @__PURE__ */ new Set();
|
|
10322
10469
|
const isXref = (value) => !!value && /^@[A-Za-z0-9_]+@$/.test(value.trim());
|
|
10470
|
+
const recordFsId = (item) => {
|
|
10471
|
+
const node = item;
|
|
10472
|
+
const value = node?.get?.("_FS_ID")?.toValue?.();
|
|
10473
|
+
return typeof value === "string" ? value.trim() : "";
|
|
10474
|
+
};
|
|
10323
10475
|
const allocateTopLevelIds = (sourceList, targetList, prefix) => {
|
|
10324
10476
|
const used = /* @__PURE__ */ new Set();
|
|
10325
|
-
|
|
10477
|
+
const byFsId = /* @__PURE__ */ new Map();
|
|
10478
|
+
targetList?.forEach((item, id) => {
|
|
10326
10479
|
used.add(String(id));
|
|
10480
|
+
const fsId = recordFsId(item);
|
|
10481
|
+
if (fsId && !byFsId.has(fsId)) {
|
|
10482
|
+
byFsId.set(fsId, String(id));
|
|
10483
|
+
}
|
|
10327
10484
|
});
|
|
10328
10485
|
idMap.forEach((mapped) => {
|
|
10329
10486
|
used.add(String(mapped));
|
|
10330
10487
|
});
|
|
10331
|
-
sourceList?.forEach((
|
|
10488
|
+
sourceList?.forEach((item, sourceId) => {
|
|
10332
10489
|
const sid = String(sourceId);
|
|
10333
10490
|
if (!sid || idMap.has(sid)) {
|
|
10334
10491
|
return;
|
|
10335
10492
|
}
|
|
10493
|
+
const fsId = recordFsId(item);
|
|
10494
|
+
if (fsId && byFsId.has(fsId)) {
|
|
10495
|
+
const existingId = byFsId.get(fsId);
|
|
10496
|
+
idMap.set(sid, existingId);
|
|
10497
|
+
reusedTopLevelIds.add(sid);
|
|
10498
|
+
return;
|
|
10499
|
+
}
|
|
10336
10500
|
let newId = sid;
|
|
10337
10501
|
if (used.has(sid)) {
|
|
10338
10502
|
newId = nextRecordId([...used], prefix);
|
|
10339
10503
|
}
|
|
10340
10504
|
used.add(newId);
|
|
10341
10505
|
idMap.set(sid, newId);
|
|
10506
|
+
if (fsId) {
|
|
10507
|
+
byFsId.set(fsId, newId);
|
|
10508
|
+
}
|
|
10342
10509
|
});
|
|
10343
10510
|
};
|
|
10344
10511
|
const remapIndiPointers = (clonedIndi, sourceIndi, tag) => {
|
|
@@ -10358,6 +10525,9 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10358
10525
|
}
|
|
10359
10526
|
const pointer = createCommon(mergedGedcom, void 0, clonedIndi);
|
|
10360
10527
|
pointer.value = newVal;
|
|
10528
|
+
if (tag === "OBJE" || tag === "SOUR") {
|
|
10529
|
+
pointer.refType = tag;
|
|
10530
|
+
}
|
|
10361
10531
|
clonedIndi.assign(tag, pointer, true);
|
|
10362
10532
|
});
|
|
10363
10533
|
};
|
|
@@ -10469,10 +10639,39 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10469
10639
|
clonedFam.setGedcom(mergedGedcom);
|
|
10470
10640
|
clonedFams.set(sourceFam.id, clonedFam);
|
|
10471
10641
|
});
|
|
10642
|
+
const fillMissingTag = (target, source, tag) => {
|
|
10643
|
+
const current = target.get(tag)?.toValue?.();
|
|
10644
|
+
if (current !== void 0 && current !== null && String(current).trim()) {
|
|
10645
|
+
return;
|
|
10646
|
+
}
|
|
10647
|
+
const next = source.get(tag)?.toValue?.();
|
|
10648
|
+
if (typeof next === "string" && next.trim()) {
|
|
10649
|
+
target.set(tag, next);
|
|
10650
|
+
}
|
|
10651
|
+
};
|
|
10652
|
+
const isBinaryMediaUrl = (url) => /\.(jpe?g|png|gif|webp|tif{1,2}|pdf)(\?|$)/i.test(url) || /dist\.jpg/i.test(url);
|
|
10472
10653
|
sourceGedcom.objes()?.forEach((sourceObje, sourceId) => {
|
|
10473
10654
|
if (!sourceObje || !sourceId) return;
|
|
10655
|
+
const sid = String(sourceId);
|
|
10474
10656
|
const newId = idMap.get(sourceId);
|
|
10475
10657
|
if (!newId) return;
|
|
10658
|
+
if (reusedTopLevelIds.has(sid)) {
|
|
10659
|
+
const existingObje = mergedGedcom.obje(newId);
|
|
10660
|
+
if (existingObje) {
|
|
10661
|
+
fillMissingTag(existingObje, sourceObje, "WWW");
|
|
10662
|
+
fillMissingTag(existingObje, sourceObje, "TITL");
|
|
10663
|
+
const curFile = String(
|
|
10664
|
+
existingObje.get("FILE")?.toValue?.() ?? ""
|
|
10665
|
+
).trim();
|
|
10666
|
+
const nextFile = String(
|
|
10667
|
+
sourceObje.get("FILE")?.toValue?.() ?? ""
|
|
10668
|
+
).trim();
|
|
10669
|
+
if (nextFile && (!curFile || isBinaryMediaUrl(nextFile) && !isBinaryMediaUrl(curFile))) {
|
|
10670
|
+
existingObje.set("FILE", nextFile);
|
|
10671
|
+
}
|
|
10672
|
+
}
|
|
10673
|
+
return;
|
|
10674
|
+
}
|
|
10476
10675
|
const cloned = sourceObje.clone(false);
|
|
10477
10676
|
cloned.id = newId;
|
|
10478
10677
|
cloned.setGedcom(mergedGedcom);
|
|
@@ -10485,11 +10684,35 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10485
10684
|
});
|
|
10486
10685
|
sourceGedcom.sours()?.forEach((sourceSour, sourceId) => {
|
|
10487
10686
|
if (!sourceSour || !sourceId) return;
|
|
10687
|
+
const sid = String(sourceId);
|
|
10488
10688
|
const newId = idMap.get(sourceId);
|
|
10489
10689
|
if (!newId) return;
|
|
10690
|
+
if (reusedTopLevelIds.has(sid)) {
|
|
10691
|
+
const existingSour = mergedGedcom.sour(newId);
|
|
10692
|
+
if (existingSour) {
|
|
10693
|
+
fillMissingTag(existingSour, sourceSour, "WWW");
|
|
10694
|
+
fillMissingTag(existingSour, sourceSour, "TITL");
|
|
10695
|
+
fillMissingTag(existingSour, sourceSour, "PAGE");
|
|
10696
|
+
}
|
|
10697
|
+
return;
|
|
10698
|
+
}
|
|
10490
10699
|
const cloned = sourceSour.clone(false);
|
|
10491
10700
|
cloned.id = newId;
|
|
10492
10701
|
cloned.setGedcom(mergedGedcom);
|
|
10702
|
+
const sourObjes = cloned.get("OBJE")?.toList();
|
|
10703
|
+
if (sourObjes?.length) {
|
|
10704
|
+
cloned.remove("OBJE");
|
|
10705
|
+
sourObjes.forEach((ref) => {
|
|
10706
|
+
const oldVal = String(ref?.toValue?.() ?? "").trim();
|
|
10707
|
+
if (!oldVal) return;
|
|
10708
|
+
const newVal = isXref(oldVal) ? idMap.get(oldVal) : oldVal;
|
|
10709
|
+
if (!newVal) return;
|
|
10710
|
+
const pointer = createCommon(mergedGedcom, void 0, cloned);
|
|
10711
|
+
pointer.value = newVal;
|
|
10712
|
+
pointer.refType = "OBJE";
|
|
10713
|
+
cloned.assign("OBJE", pointer, true);
|
|
10714
|
+
});
|
|
10715
|
+
}
|
|
10493
10716
|
const existing = mergedGedcom.sours();
|
|
10494
10717
|
const list = existing ?? new Sources();
|
|
10495
10718
|
if (!existing) {
|
|
@@ -10513,6 +10736,7 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10513
10736
|
clonedIndi
|
|
10514
10737
|
);
|
|
10515
10738
|
newFamRef.value = newFamId;
|
|
10739
|
+
newFamRef.refType = "FAM";
|
|
10516
10740
|
clonedIndi.assign("FAMS", newFamRef, true);
|
|
10517
10741
|
}
|
|
10518
10742
|
}
|
|
@@ -10530,6 +10754,7 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10530
10754
|
clonedIndi
|
|
10531
10755
|
);
|
|
10532
10756
|
newFamRef.value = newFamId;
|
|
10757
|
+
newFamRef.refType = "FAM";
|
|
10533
10758
|
clonedIndi.assign("FAMC", newFamRef, true);
|
|
10534
10759
|
}
|
|
10535
10760
|
}
|
|
@@ -10550,6 +10775,7 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10550
10775
|
clonedFam
|
|
10551
10776
|
);
|
|
10552
10777
|
newHusbRef.value = newHusbId;
|
|
10778
|
+
newHusbRef.refType = "INDI";
|
|
10553
10779
|
clonedFam.set("HUSB", newHusbRef);
|
|
10554
10780
|
}
|
|
10555
10781
|
}
|
|
@@ -10563,6 +10789,7 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10563
10789
|
clonedFam
|
|
10564
10790
|
);
|
|
10565
10791
|
newWifeRef.value = newWifeId;
|
|
10792
|
+
newWifeRef.refType = "INDI";
|
|
10566
10793
|
clonedFam.set("WIFE", newWifeRef);
|
|
10567
10794
|
}
|
|
10568
10795
|
}
|
|
@@ -10579,6 +10806,7 @@ var mergeGedcoms = (targetGedcom, sourceGedcom, strategy = "id") => {
|
|
|
10579
10806
|
clonedFam
|
|
10580
10807
|
);
|
|
10581
10808
|
newChildRef.value = newChildId;
|
|
10809
|
+
newChildRef.refType = "INDI";
|
|
10582
10810
|
clonedFam.assign("CHIL", newChildRef, true);
|
|
10583
10811
|
}
|
|
10584
10812
|
}
|
|
@@ -10840,6 +11068,9 @@ var GedcomTree = {
|
|
|
10840
11068
|
}, []);
|
|
10841
11069
|
let linesJoined = lines.join("\n");
|
|
10842
11070
|
if (purgeOversized && typeof maxFileSizeToPurge === "number" && !linesJoined.includes("1 _IS_PURGED true") && getRawSize(linesJoined) > maxFileSizeToPurge) {
|
|
11071
|
+
if (!linesJoined.endsWith("\n")) {
|
|
11072
|
+
linesJoined += "\n";
|
|
11073
|
+
}
|
|
10843
11074
|
linesJoined = linesJoined.replace(
|
|
10844
11075
|
/1\s(NOTE|OBJE|SOUR)([^\n]*\n)([23456789]\s.+\n)*/gm,
|
|
10845
11076
|
""
|
package/dist/constants/index.js
CHANGED
|
@@ -464,6 +464,100 @@ var objeXrefKey = (obje, fallback = 0) => {
|
|
|
464
464
|
return `@O${fallback}@`;
|
|
465
465
|
};
|
|
466
466
|
var objeNoteValue = (obje) => mediaIdValue(obje, "FILE.NOTE") || mediaIdValue(obje, "NOTE") || "";
|
|
467
|
+
var FS_WEB_RE = /familysearch\.org/i;
|
|
468
|
+
var FS_ARK_ID_RE = /^(?:ark:\/[^/]+\/)?([123]:[12]:[A-Za-z0-9-]+)$/i;
|
|
469
|
+
var listItems = (list) => {
|
|
470
|
+
if (!list) {
|
|
471
|
+
return [];
|
|
472
|
+
}
|
|
473
|
+
if (typeof list.values === "function") {
|
|
474
|
+
return list.values();
|
|
475
|
+
}
|
|
476
|
+
if (typeof list.forEach === "function") {
|
|
477
|
+
const items = [];
|
|
478
|
+
list.forEach((item) => items.push(item));
|
|
479
|
+
return items;
|
|
480
|
+
}
|
|
481
|
+
return [];
|
|
482
|
+
};
|
|
483
|
+
var toList = (node) => {
|
|
484
|
+
if (!node) {
|
|
485
|
+
return void 0;
|
|
486
|
+
}
|
|
487
|
+
const maybe = node;
|
|
488
|
+
if (typeof maybe.toList === "function") {
|
|
489
|
+
return maybe.toList();
|
|
490
|
+
}
|
|
491
|
+
if (typeof maybe.values === "function" || typeof maybe.forEach === "function") {
|
|
492
|
+
return maybe;
|
|
493
|
+
}
|
|
494
|
+
return void 0;
|
|
495
|
+
};
|
|
496
|
+
var normalizeFsWebUrl = (url) => {
|
|
497
|
+
const trimmed = url.trim();
|
|
498
|
+
if (!trimmed || !FS_WEB_RE.test(trimmed)) {
|
|
499
|
+
return void 0;
|
|
500
|
+
}
|
|
501
|
+
if (/\/dist\.jpg|\/service\/records\/storage\/|\/platform\//i.test(trimmed)) {
|
|
502
|
+
return void 0;
|
|
503
|
+
}
|
|
504
|
+
return trimmed;
|
|
505
|
+
};
|
|
506
|
+
var familySearchMediaOriginUrl = (obje, indi) => {
|
|
507
|
+
if (!obje) {
|
|
508
|
+
return void 0;
|
|
509
|
+
}
|
|
510
|
+
const resolved = obje.ref && typeof obje.toValue?.() === "string" ? obje.ref : obje;
|
|
511
|
+
const directWww = mediaIdValue(resolved, "WWW") || mediaIdValue(obje, "WWW");
|
|
512
|
+
const fromWww = directWww ? normalizeFsWebUrl(directWww) : void 0;
|
|
513
|
+
if (fromWww) {
|
|
514
|
+
return fromWww;
|
|
515
|
+
}
|
|
516
|
+
const objeKey = objeXrefKey(obje);
|
|
517
|
+
const sourItems = listItems(toList(indi?.get?.("SOUR")));
|
|
518
|
+
for (const sour of sourItems) {
|
|
519
|
+
if (!sour) continue;
|
|
520
|
+
const sourWww = mediaIdValue(sour, "WWW");
|
|
521
|
+
const normalized = sourWww ? normalizeFsWebUrl(sourWww) : void 0;
|
|
522
|
+
if (!normalized) continue;
|
|
523
|
+
const sourIsFs = mediaIdValue(sour, "_IS_FS") === "Y" || FS_WEB_RE.test(normalized);
|
|
524
|
+
if (!sourIsFs) continue;
|
|
525
|
+
let linksThisObje = false;
|
|
526
|
+
for (const ref of listItems(toList(sour.get?.("OBJE")))) {
|
|
527
|
+
if (ref && objeXrefKey(ref) === objeKey) {
|
|
528
|
+
linksThisObje = true;
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
const sourFsId = mediaIdValue(sour, "_FS_ID");
|
|
533
|
+
const objeFsId = mediaIdValue(resolved, "_FS_ID") || mediaIdValue(obje, "_FS_ID");
|
|
534
|
+
if (linksThisObje || sourFsId && objeFsId && sourFsId === objeFsId) {
|
|
535
|
+
return normalized;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
const isFs = mediaIdValue(resolved, "_IS_FS") === "Y" || mediaIdValue(obje, "_IS_FS") === "Y";
|
|
539
|
+
const fsId = mediaIdValue(resolved, "_FS_ID") || mediaIdValue(obje, "_FS_ID");
|
|
540
|
+
if (!isFs || !fsId) {
|
|
541
|
+
return void 0;
|
|
542
|
+
}
|
|
543
|
+
const arkMatch = fsId.match(FS_ARK_ID_RE);
|
|
544
|
+
if (arkMatch?.[1]) {
|
|
545
|
+
return `https://www.familysearch.org/ark:/61903/${arkMatch[1]}`;
|
|
546
|
+
}
|
|
547
|
+
if (/^\d+$/.test(fsId)) {
|
|
548
|
+
return `https://www.familysearch.org/photos/artifacts/${fsId}`;
|
|
549
|
+
}
|
|
550
|
+
for (const sour of sourItems) {
|
|
551
|
+
if (!sour) continue;
|
|
552
|
+
if (mediaIdValue(sour, "_FS_ID") !== fsId) continue;
|
|
553
|
+
const sourWww = mediaIdValue(sour, "WWW");
|
|
554
|
+
const normalized = sourWww ? normalizeFsWebUrl(sourWww) : void 0;
|
|
555
|
+
if (normalized) {
|
|
556
|
+
return normalized;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return void 0;
|
|
560
|
+
};
|
|
467
561
|
|
|
468
562
|
// src/classes/common.ts
|
|
469
563
|
var Common = class _Common {
|
|
@@ -2392,6 +2486,14 @@ var mergeMediaListsByObjeKey = (...lists) => {
|
|
|
2392
2486
|
for (const [id, item] of Object.entries(list)) {
|
|
2393
2487
|
const objeKey = item.key ? String(item.key) : "";
|
|
2394
2488
|
if (objeKey && seen.has(objeKey)) {
|
|
2489
|
+
if (item.originUrl) {
|
|
2490
|
+
const existing = Object.values(merged).find(
|
|
2491
|
+
(entry) => entry.key === objeKey
|
|
2492
|
+
);
|
|
2493
|
+
if (existing && !existing.originUrl) {
|
|
2494
|
+
existing.originUrl = item.originUrl;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2395
2497
|
continue;
|
|
2396
2498
|
}
|
|
2397
2499
|
merged[id] = item;
|
|
@@ -3706,6 +3808,10 @@ var Indi = class extends Common {
|
|
|
3706
3808
|
}
|
|
3707
3809
|
if (url && imgId) {
|
|
3708
3810
|
const id = `${tree || "gedzip"}-${this.id}-${imgId}`;
|
|
3811
|
+
const originUrl = familySearchMediaOriginUrl(
|
|
3812
|
+
objeRef ?? obje,
|
|
3813
|
+
this
|
|
3814
|
+
);
|
|
3709
3815
|
list[id] = {
|
|
3710
3816
|
key,
|
|
3711
3817
|
isPrimary,
|
|
@@ -3717,7 +3823,8 @@ var Indi = class extends Common {
|
|
|
3717
3823
|
note,
|
|
3718
3824
|
url,
|
|
3719
3825
|
contentType: type,
|
|
3720
|
-
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}
|
|
3826
|
+
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`,
|
|
3827
|
+
...originUrl ? { originUrl } : {}
|
|
3721
3828
|
};
|
|
3722
3829
|
}
|
|
3723
3830
|
})
|
|
@@ -3937,18 +4044,39 @@ var Indi = class extends Common {
|
|
|
3937
4044
|
if (!this.id) {
|
|
3938
4045
|
return list;
|
|
3939
4046
|
}
|
|
3940
|
-
|
|
4047
|
+
let objeList = this.get("OBJE")?.toList().copy();
|
|
4048
|
+
const sourList = this.get("SOUR")?.toList();
|
|
4049
|
+
sourList?.forEach((sour) => {
|
|
4050
|
+
const sourObje = sour?.get("OBJE")?.toList();
|
|
4051
|
+
if (!sourObje?.length) {
|
|
4052
|
+
return;
|
|
4053
|
+
}
|
|
4054
|
+
if (!objeList) {
|
|
4055
|
+
objeList = sourObje.copy();
|
|
4056
|
+
} else {
|
|
4057
|
+
objeList.merge(sourObje);
|
|
4058
|
+
}
|
|
4059
|
+
});
|
|
3941
4060
|
if (!objeList || objeList.length === 0) {
|
|
3942
4061
|
return list;
|
|
3943
4062
|
}
|
|
3944
4063
|
const rfn = this.get("RFN")?.toValue();
|
|
3945
4064
|
const treeId = this.getUniversalTreeId() || rfn || "universal";
|
|
4065
|
+
const seenFsIds = /* @__PURE__ */ new Set();
|
|
3946
4066
|
objeList.forEach((obje, index) => {
|
|
3947
4067
|
if (!obje) {
|
|
3948
4068
|
return;
|
|
3949
4069
|
}
|
|
3950
4070
|
const key = objeXrefKey(obje, index);
|
|
3951
4071
|
obje.standardizeMedia();
|
|
4072
|
+
const fsId = obje?.get("_FS_ID")?.toValue?.();
|
|
4073
|
+
if (typeof fsId === "string" && fsId.trim()) {
|
|
4074
|
+
const normalized = fsId.trim();
|
|
4075
|
+
if (seenFsIds.has(normalized)) {
|
|
4076
|
+
return;
|
|
4077
|
+
}
|
|
4078
|
+
seenFsIds.add(normalized);
|
|
4079
|
+
}
|
|
3952
4080
|
const isPrimary = obje?.get("_PRIM")?.toValue() === "Y";
|
|
3953
4081
|
const url = obje?.get("FILE")?.toValue();
|
|
3954
4082
|
const title = obje?.get("FILE.TITL")?.toValue() ?? obje?.get("TITL")?.toValue() ?? "";
|
|
@@ -3956,6 +4084,7 @@ var Indi = class extends Common {
|
|
|
3956
4084
|
if (url) {
|
|
3957
4085
|
const imgId = `media-${index}-${url.startsWith("data:") ? getFileExtension(url) || "bin" : url.split("/").pop()?.split("?")[0]?.substring(0, 20) || Date.now().toString(36)}`;
|
|
3958
4086
|
const id = `${treeId}-${this.id}-${imgId}`;
|
|
4087
|
+
const originUrl = familySearchMediaOriginUrl(obje, this);
|
|
3959
4088
|
list[id] = {
|
|
3960
4089
|
isPrimary,
|
|
3961
4090
|
key,
|
|
@@ -3967,7 +4096,8 @@ var Indi = class extends Common {
|
|
|
3967
4096
|
note: objeNoteValue(obje),
|
|
3968
4097
|
url,
|
|
3969
4098
|
contentType: type,
|
|
3970
|
-
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}
|
|
4099
|
+
downloadName: `${this.id.replaceAll("@", "")}_${this.toNaturalName()?.replaceAll(" ", "-") || ""}_${(title || key.replaceAll("@", "").toString()).replaceAll(" ", "-")}`,
|
|
4100
|
+
...originUrl ? { originUrl } : {}
|
|
3971
4101
|
};
|
|
3972
4102
|
}
|
|
3973
4103
|
});
|
|
@@ -3993,7 +4123,23 @@ var Indi = class extends Common {
|
|
|
3993
4123
|
lists.push(this.geniMedia());
|
|
3994
4124
|
}
|
|
3995
4125
|
lists.push(this.universalMedia());
|
|
3996
|
-
|
|
4126
|
+
const merged = mergeMediaListsByObjeKey(...lists);
|
|
4127
|
+
const seenFsIds = /* @__PURE__ */ new Set();
|
|
4128
|
+
const deduped = {};
|
|
4129
|
+
for (const [id, media] of Object.entries(merged ?? {})) {
|
|
4130
|
+
const xref = media.key ? String(media.key) : "";
|
|
4131
|
+
const top = xref && this._gedcom ? this._gedcom.obje(xref) : void 0;
|
|
4132
|
+
const fsId = top?.get("_FS_ID")?.toValue?.();
|
|
4133
|
+
if (typeof fsId === "string" && fsId.trim()) {
|
|
4134
|
+
const normalized = fsId.trim();
|
|
4135
|
+
if (seenFsIds.has(normalized)) {
|
|
4136
|
+
continue;
|
|
4137
|
+
}
|
|
4138
|
+
seenFsIds.add(normalized);
|
|
4139
|
+
}
|
|
4140
|
+
deduped[id] = media;
|
|
4141
|
+
}
|
|
4142
|
+
return deduped;
|
|
3997
4143
|
}
|
|
3998
4144
|
async getProfilePicture(namespace, onlyPrimary = true) {
|
|
3999
4145
|
if (!this.id) {
|