@treeviz/familysearch-sdk 2.0.6 → 2.0.7
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.cjs +135 -50
- package/dist/index.js +135 -50
- package/dist/utils/index.cjs +135 -50
- package/dist/utils/index.js +135 -50
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6416,6 +6416,64 @@ function transformSourceUrl(url) {
|
|
|
6416
6416
|
}
|
|
6417
6417
|
return `${baseUrl}/${arkId}`;
|
|
6418
6418
|
}
|
|
6419
|
+
function sanitizeGedcomValue(value) {
|
|
6420
|
+
return value.replace(/[\r\n\t]+/g, " ").trim();
|
|
6421
|
+
}
|
|
6422
|
+
var GEDCOM_MONTHS = [
|
|
6423
|
+
"JAN",
|
|
6424
|
+
"FEB",
|
|
6425
|
+
"MAR",
|
|
6426
|
+
"APR",
|
|
6427
|
+
"MAY",
|
|
6428
|
+
"JUN",
|
|
6429
|
+
"JUL",
|
|
6430
|
+
"AUG",
|
|
6431
|
+
"SEP",
|
|
6432
|
+
"OCT",
|
|
6433
|
+
"NOV",
|
|
6434
|
+
"DEC"
|
|
6435
|
+
];
|
|
6436
|
+
function formatSimpleFormalDate(value) {
|
|
6437
|
+
const match = value.match(/^([+-])(\d{1,6})(?:-(\d{2}))?(?:-(\d{2}))?/);
|
|
6438
|
+
if (!match) return void 0;
|
|
6439
|
+
const [, sign, yearPart, monthPart, dayPart] = match;
|
|
6440
|
+
if (sign === "-") return void 0;
|
|
6441
|
+
const year = String(parseInt(yearPart, 10));
|
|
6442
|
+
if (!monthPart) return year;
|
|
6443
|
+
const month = GEDCOM_MONTHS[parseInt(monthPart, 10) - 1];
|
|
6444
|
+
if (!month) return void 0;
|
|
6445
|
+
if (!dayPart) return `${month} ${year}`;
|
|
6446
|
+
return `${parseInt(dayPart, 10)} ${month} ${year}`;
|
|
6447
|
+
}
|
|
6448
|
+
function convertFormalDateToGedcom(formal) {
|
|
6449
|
+
if (!formal) return void 0;
|
|
6450
|
+
let value = formal.trim();
|
|
6451
|
+
let approximate = false;
|
|
6452
|
+
if (value.startsWith("A")) {
|
|
6453
|
+
approximate = true;
|
|
6454
|
+
value = value.slice(1);
|
|
6455
|
+
}
|
|
6456
|
+
if (value.includes("/")) {
|
|
6457
|
+
const slashIndex = value.indexOf("/");
|
|
6458
|
+
const start = value.slice(0, slashIndex);
|
|
6459
|
+
const end = value.slice(slashIndex + 1);
|
|
6460
|
+
const startDate = start ? formatSimpleFormalDate(start) : void 0;
|
|
6461
|
+
const endDate = end ? formatSimpleFormalDate(end) : void 0;
|
|
6462
|
+
if (start && !startDate) return void 0;
|
|
6463
|
+
if (end && !endDate) return void 0;
|
|
6464
|
+
if (startDate && endDate) return `BET ${startDate} AND ${endDate}`;
|
|
6465
|
+
if (startDate) return `FROM ${startDate}`;
|
|
6466
|
+
if (endDate) return `TO ${endDate}`;
|
|
6467
|
+
return void 0;
|
|
6468
|
+
}
|
|
6469
|
+
const simple = formatSimpleFormalDate(value);
|
|
6470
|
+
if (!simple) return void 0;
|
|
6471
|
+
return approximate ? `ABT ${simple}` : simple;
|
|
6472
|
+
}
|
|
6473
|
+
function resolveFactDate(date) {
|
|
6474
|
+
if (!date) return void 0;
|
|
6475
|
+
return convertFormalDateToGedcom(date.formal) || date.original;
|
|
6476
|
+
}
|
|
6419
6477
|
function extractName(person) {
|
|
6420
6478
|
if (!person) return null;
|
|
6421
6479
|
if (person.names?.[0]?.nameForms?.[0]) {
|
|
@@ -6423,8 +6481,14 @@ function extractName(person) {
|
|
|
6423
6481
|
const parts = nameForm.parts || [];
|
|
6424
6482
|
const given = parts.find((p) => p.type?.includes("Given"))?.value || "";
|
|
6425
6483
|
const surname = parts.find((p) => p.type?.includes("Surname"))?.value || "";
|
|
6426
|
-
if (given
|
|
6427
|
-
return `${given} /${surname}
|
|
6484
|
+
if (given && surname) {
|
|
6485
|
+
return `${given} /${surname}/`;
|
|
6486
|
+
}
|
|
6487
|
+
if (surname) {
|
|
6488
|
+
return `/${surname}/`;
|
|
6489
|
+
}
|
|
6490
|
+
if (given) {
|
|
6491
|
+
return given;
|
|
6428
6492
|
}
|
|
6429
6493
|
if (nameForm.fullText) {
|
|
6430
6494
|
return nameForm.fullText;
|
|
@@ -6454,11 +6518,9 @@ function extractFact(person, factType) {
|
|
|
6454
6518
|
const factTypeUrl = `http://gedcomx.org/${factType === "BIRTH" ? "Birth" : "Death"}`;
|
|
6455
6519
|
const fact = person.facts?.find((f) => f.type === factTypeUrl);
|
|
6456
6520
|
if (fact) {
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
""
|
|
6461
|
-
);
|
|
6521
|
+
const resolvedDate = resolveFactDate(fact.date);
|
|
6522
|
+
if (resolvedDate) {
|
|
6523
|
+
result.date = resolvedDate;
|
|
6462
6524
|
}
|
|
6463
6525
|
if (fact.place?.original) {
|
|
6464
6526
|
result.place = fact.place.original;
|
|
@@ -6511,25 +6573,30 @@ function convertFactToGedcom(fact) {
|
|
|
6511
6573
|
};
|
|
6512
6574
|
const gedcomTag = typeMap[fact.type] || "EVEN";
|
|
6513
6575
|
if (gedcomTag === "OCCU" && fact.value) {
|
|
6514
|
-
lines.push(`1 OCCU ${fact.value}`);
|
|
6576
|
+
lines.push(`1 OCCU ${sanitizeGedcomValue(fact.value)}`);
|
|
6515
6577
|
} else {
|
|
6516
6578
|
lines.push(`1 ${gedcomTag}`);
|
|
6517
6579
|
}
|
|
6580
|
+
if (gedcomTag === "EVEN") {
|
|
6581
|
+
const typeName = fact.type.split("/").pop();
|
|
6582
|
+
if (typeName) {
|
|
6583
|
+
lines.push(`2 TYPE ${sanitizeGedcomValue(typeName)}`);
|
|
6584
|
+
}
|
|
6585
|
+
}
|
|
6518
6586
|
if (fact.links?.conclusion?.href) {
|
|
6519
6587
|
const webUrl = transformFamilySearchUrl(fact.links.conclusion.href);
|
|
6520
6588
|
lines.push(`2 WWW ${webUrl}`);
|
|
6521
6589
|
lines.push(`3 _IS_FS Y`);
|
|
6522
6590
|
}
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
);
|
|
6591
|
+
const resolvedDate = resolveFactDate(fact.date);
|
|
6592
|
+
if (resolvedDate) {
|
|
6593
|
+
lines.push(`2 DATE ${sanitizeGedcomValue(resolvedDate)}`);
|
|
6527
6594
|
}
|
|
6528
6595
|
if (fact.place?.original) {
|
|
6529
|
-
lines.push(`2 PLAC ${fact.place.original}`);
|
|
6596
|
+
lines.push(`2 PLAC ${sanitizeGedcomValue(fact.place.original)}`);
|
|
6530
6597
|
}
|
|
6531
6598
|
if (fact.value && gedcomTag !== "OCCU") {
|
|
6532
|
-
lines.push(`2 NOTE ${fact.value}`);
|
|
6599
|
+
lines.push(`2 NOTE ${sanitizeGedcomValue(fact.value)}`);
|
|
6533
6600
|
}
|
|
6534
6601
|
return lines;
|
|
6535
6602
|
}
|
|
@@ -6549,14 +6616,14 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6549
6616
|
lines.push("2 VERS 1.0");
|
|
6550
6617
|
lines.push("2 NAME FamilySearch API");
|
|
6551
6618
|
if (treeName) {
|
|
6552
|
-
lines.push(`2 _TREE ${treeName}`);
|
|
6619
|
+
lines.push(`2 _TREE ${sanitizeGedcomValue(treeName)}`);
|
|
6553
6620
|
const randomRIN = Math.floor(Math.random() * 1e8);
|
|
6554
6621
|
lines.push(`3 RIN ${randomRIN}`);
|
|
6555
6622
|
}
|
|
6556
6623
|
lines.push("1 DEST ANY");
|
|
6557
6624
|
lines.push("1 DATE " + formatDateForGedcom(/* @__PURE__ */ new Date()));
|
|
6558
6625
|
lines.push("1 SUBM @SUBM1@");
|
|
6559
|
-
lines.push("1 FILE " + treeName);
|
|
6626
|
+
lines.push("1 FILE " + sanitizeGedcomValue(treeName));
|
|
6560
6627
|
lines.push("1 GEDC");
|
|
6561
6628
|
lines.push("2 VERS 5.5");
|
|
6562
6629
|
lines.push("2 FORM LINEAGE-LINKED");
|
|
@@ -6578,20 +6645,22 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6578
6645
|
const sourceId = `@S${sourceCounter++}@`;
|
|
6579
6646
|
lines.push(`0 ${sourceId} SOUR`);
|
|
6580
6647
|
const title = source.titles?.[0]?.value || "FamilySearch Source";
|
|
6581
|
-
lines.push(`1 TITL ${title}`);
|
|
6648
|
+
lines.push(`1 TITL ${sanitizeGedcomValue(title)}`);
|
|
6582
6649
|
if (source.citations?.[0]?.value) {
|
|
6583
|
-
lines.push(`1 TEXT ${source.citations[0].value}`);
|
|
6650
|
+
lines.push(`1 TEXT ${sanitizeGedcomValue(source.citations[0].value)}`);
|
|
6584
6651
|
}
|
|
6585
6652
|
if (source.about) {
|
|
6586
6653
|
const webUrl = transformSourceUrl(source.about);
|
|
6587
6654
|
lines.push(`1 WWW ${webUrl}`);
|
|
6588
6655
|
}
|
|
6589
6656
|
if (source.resourceType) {
|
|
6590
|
-
lines.push(
|
|
6657
|
+
lines.push(
|
|
6658
|
+
`1 NOTE Resource Type: ${sanitizeGedcomValue(source.resourceType)}`
|
|
6659
|
+
);
|
|
6591
6660
|
}
|
|
6592
6661
|
});
|
|
6593
6662
|
const fsSourMap = /* @__PURE__ */ new Map();
|
|
6594
|
-
let fsSourCounter =
|
|
6663
|
+
let fsSourCounter = sourceCounter;
|
|
6595
6664
|
pedigreeData.persons.forEach((person) => {
|
|
6596
6665
|
if (person.sources?.persons?.[0]?.sources) {
|
|
6597
6666
|
const sourceDescMap = /* @__PURE__ */ new Map();
|
|
@@ -6641,20 +6710,22 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6641
6710
|
lines.push(`1 _IS_FS Y`);
|
|
6642
6711
|
lines.push(`1 _FS_ID ${id}`);
|
|
6643
6712
|
if (source.titles?.[0]?.value) {
|
|
6644
|
-
lines.push(`1 TITL ${source.titles[0].value}`);
|
|
6713
|
+
lines.push(`1 TITL ${sanitizeGedcomValue(source.titles[0].value)}`);
|
|
6645
6714
|
}
|
|
6646
6715
|
if (source.citations?.[0]?.value) {
|
|
6647
|
-
lines.push(`1 TEXT ${source.citations[0].value}`);
|
|
6716
|
+
lines.push(`1 TEXT ${sanitizeGedcomValue(source.citations[0].value)}`);
|
|
6648
6717
|
}
|
|
6649
6718
|
if (source.about) {
|
|
6650
6719
|
const webUrl = transformSourceUrl(source.about);
|
|
6651
6720
|
lines.push(`1 WWW ${webUrl}`);
|
|
6652
6721
|
}
|
|
6653
6722
|
if (source.resourceType) {
|
|
6654
|
-
lines.push(
|
|
6723
|
+
lines.push(
|
|
6724
|
+
`1 NOTE Resource Type: ${sanitizeGedcomValue(source.resourceType)}`
|
|
6725
|
+
);
|
|
6655
6726
|
}
|
|
6656
6727
|
notes.forEach((note) => {
|
|
6657
|
-
lines.push(`1 NOTE ${note}`);
|
|
6728
|
+
lines.push(`1 NOTE ${sanitizeGedcomValue(note)}`);
|
|
6658
6729
|
});
|
|
6659
6730
|
});
|
|
6660
6731
|
const fsMatchMap = /* @__PURE__ */ new Map();
|
|
@@ -6674,7 +6745,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6674
6745
|
lines.push(`1 _IS_FS Y`);
|
|
6675
6746
|
lines.push(`1 _FS_ID ${id}`);
|
|
6676
6747
|
if (entry.title) {
|
|
6677
|
-
lines.push(`1 TITL ${entry.title}`);
|
|
6748
|
+
lines.push(`1 TITL ${sanitizeGedcomValue(entry.title)}`);
|
|
6678
6749
|
}
|
|
6679
6750
|
if (entry.content?.score !== void 0) {
|
|
6680
6751
|
lines.push(`1 SCORE ${entry.content.score}`);
|
|
@@ -6695,7 +6766,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6695
6766
|
}
|
|
6696
6767
|
if (matchInfo.status) {
|
|
6697
6768
|
const statusName = matchInfo.status.includes("/") ? matchInfo.status.split("/").pop() : matchInfo.status;
|
|
6698
|
-
lines.push(`1 NOTE Status: ${statusName}`);
|
|
6769
|
+
lines.push(`1 NOTE Status: ${sanitizeGedcomValue(statusName || "")}`);
|
|
6699
6770
|
}
|
|
6700
6771
|
}
|
|
6701
6772
|
lines.push(`1 TYPE ${collectionType}`);
|
|
@@ -6707,42 +6778,52 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6707
6778
|
if (entry.content?.gedcomx?.persons && entry.content.gedcomx.persons.length > 0) {
|
|
6708
6779
|
const matchedPerson = entry.content.gedcomx.persons[0];
|
|
6709
6780
|
if (matchedPerson.display?.name) {
|
|
6710
|
-
lines.push(`1 TEXT ${matchedPerson.display.name}`);
|
|
6781
|
+
lines.push(`1 TEXT ${sanitizeGedcomValue(matchedPerson.display.name)}`);
|
|
6711
6782
|
}
|
|
6712
6783
|
if (matchedPerson.display?.lifespan) {
|
|
6713
6784
|
lines.push(
|
|
6714
|
-
`1 NOTE Lifespan: ${matchedPerson.display.lifespan}`
|
|
6785
|
+
`1 NOTE Lifespan: ${sanitizeGedcomValue(matchedPerson.display.lifespan)}`
|
|
6715
6786
|
);
|
|
6716
6787
|
}
|
|
6717
6788
|
if (matchedPerson.display?.birthDate || matchedPerson.display?.birthPlace) {
|
|
6718
|
-
const birthInfo =
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6789
|
+
const birthInfo = sanitizeGedcomValue(
|
|
6790
|
+
[
|
|
6791
|
+
matchedPerson.display.birthDate,
|
|
6792
|
+
matchedPerson.display.birthPlace
|
|
6793
|
+
].filter(Boolean).join(", ")
|
|
6794
|
+
);
|
|
6722
6795
|
if (birthInfo) {
|
|
6723
6796
|
lines.push(`1 NOTE Birth: ${birthInfo}`);
|
|
6724
6797
|
}
|
|
6725
6798
|
}
|
|
6726
6799
|
if (matchedPerson.display?.deathDate || matchedPerson.display?.deathPlace) {
|
|
6727
|
-
const deathInfo =
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6800
|
+
const deathInfo = sanitizeGedcomValue(
|
|
6801
|
+
[
|
|
6802
|
+
matchedPerson.display.deathDate,
|
|
6803
|
+
matchedPerson.display.deathPlace
|
|
6804
|
+
].filter(Boolean).join(", ")
|
|
6805
|
+
);
|
|
6731
6806
|
if (deathInfo) {
|
|
6732
6807
|
lines.push(`1 NOTE Death: ${deathInfo}`);
|
|
6733
6808
|
}
|
|
6734
6809
|
}
|
|
6735
6810
|
if (matchedPerson.display?.gender) {
|
|
6736
|
-
lines.push(
|
|
6811
|
+
lines.push(
|
|
6812
|
+
`1 NOTE Gender: ${sanitizeGedcomValue(matchedPerson.display.gender)}`
|
|
6813
|
+
);
|
|
6737
6814
|
}
|
|
6738
6815
|
}
|
|
6739
6816
|
if (entry.content?.sourceDescription) {
|
|
6740
6817
|
const sourceDesc = entry.content.sourceDescription;
|
|
6741
6818
|
if (sourceDesc.citations?.[0]?.value) {
|
|
6742
|
-
lines.push(
|
|
6819
|
+
lines.push(
|
|
6820
|
+
`1 NOTE Citation: ${sanitizeGedcomValue(sourceDesc.citations[0].value)}`
|
|
6821
|
+
);
|
|
6743
6822
|
}
|
|
6744
6823
|
if (sourceDesc.resourceType) {
|
|
6745
|
-
lines.push(
|
|
6824
|
+
lines.push(
|
|
6825
|
+
`1 NOTE Resource Type: ${sanitizeGedcomValue(sourceDesc.resourceType)}`
|
|
6826
|
+
);
|
|
6746
6827
|
}
|
|
6747
6828
|
if (sourceDesc.about) {
|
|
6748
6829
|
const webUrl = transformSourceUrl(sourceDesc.about);
|
|
@@ -6985,7 +7066,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6985
7066
|
const personData = person.fullDetails?.persons?.[0] || person;
|
|
6986
7067
|
const name = extractName(personData);
|
|
6987
7068
|
if (name) {
|
|
6988
|
-
lines.push(`1 NAME ${name}`);
|
|
7069
|
+
lines.push(`1 NAME ${sanitizeGedcomValue(name)}`);
|
|
6989
7070
|
}
|
|
6990
7071
|
const gender = extractGender(personData);
|
|
6991
7072
|
if (gender) {
|
|
@@ -6995,20 +7076,20 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6995
7076
|
if (birth) {
|
|
6996
7077
|
lines.push("1 BIRT");
|
|
6997
7078
|
if (birth.date) {
|
|
6998
|
-
lines.push(`2 DATE ${birth.date}`);
|
|
7079
|
+
lines.push(`2 DATE ${sanitizeGedcomValue(birth.date)}`);
|
|
6999
7080
|
}
|
|
7000
7081
|
if (birth.place) {
|
|
7001
|
-
lines.push(`2 PLAC ${birth.place}`);
|
|
7082
|
+
lines.push(`2 PLAC ${sanitizeGedcomValue(birth.place)}`);
|
|
7002
7083
|
}
|
|
7003
7084
|
}
|
|
7004
7085
|
const death = extractFact(personData, "DEATH");
|
|
7005
7086
|
if (death) {
|
|
7006
7087
|
lines.push("1 DEAT");
|
|
7007
7088
|
if (death.date) {
|
|
7008
|
-
lines.push(`2 DATE ${death.date}`);
|
|
7089
|
+
lines.push(`2 DATE ${sanitizeGedcomValue(death.date)}`);
|
|
7009
7090
|
}
|
|
7010
7091
|
if (death.place) {
|
|
7011
|
-
lines.push(`2 PLAC ${death.place}`);
|
|
7092
|
+
lines.push(`2 PLAC ${sanitizeGedcomValue(death.place)}`);
|
|
7012
7093
|
}
|
|
7013
7094
|
}
|
|
7014
7095
|
personData.facts?.forEach((fact) => {
|
|
@@ -7020,8 +7101,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
7020
7101
|
if (includeNotes && person.notes?.persons?.[0]?.notes) {
|
|
7021
7102
|
person.notes.persons[0].notes.forEach((note) => {
|
|
7022
7103
|
if (note.text) {
|
|
7023
|
-
|
|
7024
|
-
lines.push(`1 NOTE ${noteText}`);
|
|
7104
|
+
lines.push(`1 NOTE ${sanitizeGedcomValue(note.text)}`);
|
|
7025
7105
|
}
|
|
7026
7106
|
});
|
|
7027
7107
|
}
|
|
@@ -7039,7 +7119,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
7039
7119
|
sourceRef.qualifiers.forEach((qualifier) => {
|
|
7040
7120
|
if (qualifier.name && qualifier.value) {
|
|
7041
7121
|
lines.push(
|
|
7042
|
-
`2 NOTE ${qualifier.name}: ${qualifier.value}`
|
|
7122
|
+
`2 NOTE ${sanitizeGedcomValue(`${qualifier.name}: ${qualifier.value}`)}`
|
|
7043
7123
|
);
|
|
7044
7124
|
}
|
|
7045
7125
|
});
|
|
@@ -7193,31 +7273,36 @@ function addMarriageFacts(lines, relationships, person1, person2) {
|
|
|
7193
7273
|
return [a, b].sort().join("-") === relKey;
|
|
7194
7274
|
});
|
|
7195
7275
|
if (!rel) return;
|
|
7276
|
+
const isMarriageEvent = (type) => !!type && (type.includes("Marriage") || type.includes("Divorce"));
|
|
7196
7277
|
const marriageFacts = [];
|
|
7197
7278
|
if (rel.facts && Array.isArray(rel.facts)) {
|
|
7198
7279
|
rel.facts.forEach((f) => {
|
|
7199
|
-
if (f.type
|
|
7280
|
+
if (isMarriageEvent(f.type)) {
|
|
7200
7281
|
marriageFacts.push(f);
|
|
7201
7282
|
}
|
|
7202
7283
|
});
|
|
7203
7284
|
}
|
|
7204
7285
|
if (rel.details?.facts && Array.isArray(rel.details.facts)) {
|
|
7205
7286
|
marriageFacts.push(
|
|
7206
|
-
...rel.details.facts.filter((f) => f.type
|
|
7287
|
+
...rel.details.facts.filter((f) => isMarriageEvent(f.type))
|
|
7207
7288
|
);
|
|
7208
7289
|
}
|
|
7209
7290
|
if (rel.details?.persons && Array.isArray(rel.details.persons)) {
|
|
7210
7291
|
rel.details.persons.forEach((p) => {
|
|
7211
7292
|
if (p.facts && Array.isArray(p.facts)) {
|
|
7212
7293
|
p.facts.forEach((f) => {
|
|
7213
|
-
if (f.type
|
|
7294
|
+
if (isMarriageEvent(f.type)) {
|
|
7214
7295
|
marriageFacts.push(f);
|
|
7215
7296
|
}
|
|
7216
7297
|
});
|
|
7217
7298
|
}
|
|
7218
7299
|
});
|
|
7219
7300
|
}
|
|
7301
|
+
const seenFacts = /* @__PURE__ */ new Set();
|
|
7220
7302
|
marriageFacts.forEach((mf) => {
|
|
7303
|
+
const key = `${mf.type}|${resolveFactDate(mf.date) || ""}|${mf.place?.original || ""}`;
|
|
7304
|
+
if (seenFacts.has(key)) return;
|
|
7305
|
+
seenFacts.add(key);
|
|
7221
7306
|
const factLines = convertFactToGedcom(mf);
|
|
7222
7307
|
factLines.forEach((line) => lines.push(line));
|
|
7223
7308
|
});
|