@treeviz/familysearch-sdk 2.0.6 → 2.0.8
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-CcZ9bR5K.d.ts → index-BfeojAOm.d.cts} +1 -1
- package/dist/{index-BMAcJBZJ.d.cts → index-CgIsZu6a.d.ts} +1 -1
- package/dist/index.cjs +180 -53
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +177 -54
- package/dist/places/index.cjs +38 -0
- package/dist/places/index.d.cts +40 -1
- package/dist/places/index.d.ts +40 -1
- package/dist/places/index.js +35 -1
- package/dist/tree/index.cjs +6 -2
- package/dist/tree/index.d.cts +1 -1
- package/dist/tree/index.d.ts +1 -1
- package/dist/tree/index.js +6 -2
- package/dist/{index-CKi9wd-C.d.ts → tree-changes-CFwJtBcK.d.ts} +9 -0
- package/dist/{index-CLkFtjZD.d.cts → tree-changes-e0UMhVha.d.cts} +9 -0
- package/dist/utils/index.cjs +135 -50
- package/dist/utils/index.js +135 -50
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1666,6 +1666,10 @@ __export(tree_exports, {
|
|
|
1666
1666
|
});
|
|
1667
1667
|
|
|
1668
1668
|
// src/api/tree/persons.ts
|
|
1669
|
+
var PERSON_WRITE_HEADERS = {
|
|
1670
|
+
"Content-Type": "application/x-fs-v1+json",
|
|
1671
|
+
Accept: "application/x-fs-v1+json"
|
|
1672
|
+
};
|
|
1669
1673
|
async function readPerson(sdk, personId) {
|
|
1670
1674
|
try {
|
|
1671
1675
|
const response = await sdk.get(
|
|
@@ -1698,7 +1702,7 @@ async function readPersonWithDetails(sdk, personId, options = {}) {
|
|
|
1698
1702
|
}
|
|
1699
1703
|
async function createPerson(sdk, person, reason) {
|
|
1700
1704
|
try {
|
|
1701
|
-
const headers = {};
|
|
1705
|
+
const headers = { ...PERSON_WRITE_HEADERS };
|
|
1702
1706
|
if (reason) {
|
|
1703
1707
|
headers["X-Reason"] = reason;
|
|
1704
1708
|
}
|
|
@@ -1715,7 +1719,7 @@ async function createPerson(sdk, person, reason) {
|
|
|
1715
1719
|
}
|
|
1716
1720
|
async function updatePerson(sdk, personId, person, reason) {
|
|
1717
1721
|
try {
|
|
1718
|
-
const headers = {};
|
|
1722
|
+
const headers = { ...PERSON_WRITE_HEADERS };
|
|
1719
1723
|
if (reason) {
|
|
1720
1724
|
headers["X-Reason"] = reason;
|
|
1721
1725
|
}
|
|
@@ -6216,7 +6220,7 @@ var FamilySearchSDK = class {
|
|
|
6216
6220
|
});
|
|
6217
6221
|
let data;
|
|
6218
6222
|
const contentType = response.headers.get("content-type");
|
|
6219
|
-
if (contentType && contentType.includes("
|
|
6223
|
+
if (contentType && contentType.includes("json")) {
|
|
6220
6224
|
try {
|
|
6221
6225
|
data = await response.json();
|
|
6222
6226
|
} catch (error) {
|
|
@@ -6372,6 +6376,40 @@ function resetFamilySearchSDK() {
|
|
|
6372
6376
|
sdkInstance = null;
|
|
6373
6377
|
}
|
|
6374
6378
|
|
|
6379
|
+
// src/places/gazetteer-id.ts
|
|
6380
|
+
var numericPlaceIdFromRef = (ref) => {
|
|
6381
|
+
if (!ref) {
|
|
6382
|
+
return void 0;
|
|
6383
|
+
}
|
|
6384
|
+
if (ref.includes("/places/description/") || ref.includes("ark:/")) {
|
|
6385
|
+
return void 0;
|
|
6386
|
+
}
|
|
6387
|
+
const match = ref.match(/\/places\/(\d+)/);
|
|
6388
|
+
return match?.[1];
|
|
6389
|
+
};
|
|
6390
|
+
var extractGazetteerPlaceId = (place) => {
|
|
6391
|
+
const persistent = place.identifiers?.["http://gedcomx.org/Persistent"]?.[0];
|
|
6392
|
+
const fromPersistent = numericPlaceIdFromRef(persistent);
|
|
6393
|
+
if (fromPersistent) {
|
|
6394
|
+
return fromPersistent;
|
|
6395
|
+
}
|
|
6396
|
+
return numericPlaceIdFromRef(place.place?.description);
|
|
6397
|
+
};
|
|
6398
|
+
var familySearchResearchPlaceUrl = (placeId, baseUrl = "https://www.familysearch.org") => `${baseUrl}/en/research/places/?focusedId=${placeId}`;
|
|
6399
|
+
var pickBestPlaceSearchResult = (results, query) => {
|
|
6400
|
+
if (results.length === 0) {
|
|
6401
|
+
return void 0;
|
|
6402
|
+
}
|
|
6403
|
+
const town = query.split(",")[0]?.trim().toLowerCase();
|
|
6404
|
+
if (!town) {
|
|
6405
|
+
return results[0];
|
|
6406
|
+
}
|
|
6407
|
+
const label = (result) => (result.fullName || result.name || result.title || "").toLowerCase();
|
|
6408
|
+
return results.find(
|
|
6409
|
+
(result) => label(result) === town || label(result).startsWith(`${town},`)
|
|
6410
|
+
) || results.find((result) => label(result).includes(town)) || results[0];
|
|
6411
|
+
};
|
|
6412
|
+
|
|
6375
6413
|
// src/utils/gedcom-converter.ts
|
|
6376
6414
|
function transformFamilySearchUrl(url) {
|
|
6377
6415
|
if (url.includes("/platform/tree/persons/https://")) {
|
|
@@ -6416,6 +6454,64 @@ function transformSourceUrl(url) {
|
|
|
6416
6454
|
}
|
|
6417
6455
|
return `${baseUrl}/${arkId}`;
|
|
6418
6456
|
}
|
|
6457
|
+
function sanitizeGedcomValue(value) {
|
|
6458
|
+
return value.replace(/[\r\n\t]+/g, " ").trim();
|
|
6459
|
+
}
|
|
6460
|
+
var GEDCOM_MONTHS = [
|
|
6461
|
+
"JAN",
|
|
6462
|
+
"FEB",
|
|
6463
|
+
"MAR",
|
|
6464
|
+
"APR",
|
|
6465
|
+
"MAY",
|
|
6466
|
+
"JUN",
|
|
6467
|
+
"JUL",
|
|
6468
|
+
"AUG",
|
|
6469
|
+
"SEP",
|
|
6470
|
+
"OCT",
|
|
6471
|
+
"NOV",
|
|
6472
|
+
"DEC"
|
|
6473
|
+
];
|
|
6474
|
+
function formatSimpleFormalDate(value) {
|
|
6475
|
+
const match = value.match(/^([+-])(\d{1,6})(?:-(\d{2}))?(?:-(\d{2}))?/);
|
|
6476
|
+
if (!match) return void 0;
|
|
6477
|
+
const [, sign, yearPart, monthPart, dayPart] = match;
|
|
6478
|
+
if (sign === "-") return void 0;
|
|
6479
|
+
const year = String(parseInt(yearPart, 10));
|
|
6480
|
+
if (!monthPart) return year;
|
|
6481
|
+
const month = GEDCOM_MONTHS[parseInt(monthPart, 10) - 1];
|
|
6482
|
+
if (!month) return void 0;
|
|
6483
|
+
if (!dayPart) return `${month} ${year}`;
|
|
6484
|
+
return `${parseInt(dayPart, 10)} ${month} ${year}`;
|
|
6485
|
+
}
|
|
6486
|
+
function convertFormalDateToGedcom(formal) {
|
|
6487
|
+
if (!formal) return void 0;
|
|
6488
|
+
let value = formal.trim();
|
|
6489
|
+
let approximate = false;
|
|
6490
|
+
if (value.startsWith("A")) {
|
|
6491
|
+
approximate = true;
|
|
6492
|
+
value = value.slice(1);
|
|
6493
|
+
}
|
|
6494
|
+
if (value.includes("/")) {
|
|
6495
|
+
const slashIndex = value.indexOf("/");
|
|
6496
|
+
const start = value.slice(0, slashIndex);
|
|
6497
|
+
const end = value.slice(slashIndex + 1);
|
|
6498
|
+
const startDate = start ? formatSimpleFormalDate(start) : void 0;
|
|
6499
|
+
const endDate = end ? formatSimpleFormalDate(end) : void 0;
|
|
6500
|
+
if (start && !startDate) return void 0;
|
|
6501
|
+
if (end && !endDate) return void 0;
|
|
6502
|
+
if (startDate && endDate) return `BET ${startDate} AND ${endDate}`;
|
|
6503
|
+
if (startDate) return `FROM ${startDate}`;
|
|
6504
|
+
if (endDate) return `TO ${endDate}`;
|
|
6505
|
+
return void 0;
|
|
6506
|
+
}
|
|
6507
|
+
const simple = formatSimpleFormalDate(value);
|
|
6508
|
+
if (!simple) return void 0;
|
|
6509
|
+
return approximate ? `ABT ${simple}` : simple;
|
|
6510
|
+
}
|
|
6511
|
+
function resolveFactDate(date) {
|
|
6512
|
+
if (!date) return void 0;
|
|
6513
|
+
return convertFormalDateToGedcom(date.formal) || date.original;
|
|
6514
|
+
}
|
|
6419
6515
|
function extractName(person) {
|
|
6420
6516
|
if (!person) return null;
|
|
6421
6517
|
if (person.names?.[0]?.nameForms?.[0]) {
|
|
@@ -6423,8 +6519,14 @@ function extractName(person) {
|
|
|
6423
6519
|
const parts = nameForm.parts || [];
|
|
6424
6520
|
const given = parts.find((p) => p.type?.includes("Given"))?.value || "";
|
|
6425
6521
|
const surname = parts.find((p) => p.type?.includes("Surname"))?.value || "";
|
|
6426
|
-
if (given
|
|
6427
|
-
return `${given} /${surname}
|
|
6522
|
+
if (given && surname) {
|
|
6523
|
+
return `${given} /${surname}/`;
|
|
6524
|
+
}
|
|
6525
|
+
if (surname) {
|
|
6526
|
+
return `/${surname}/`;
|
|
6527
|
+
}
|
|
6528
|
+
if (given) {
|
|
6529
|
+
return given;
|
|
6428
6530
|
}
|
|
6429
6531
|
if (nameForm.fullText) {
|
|
6430
6532
|
return nameForm.fullText;
|
|
@@ -6454,11 +6556,9 @@ function extractFact(person, factType) {
|
|
|
6454
6556
|
const factTypeUrl = `http://gedcomx.org/${factType === "BIRTH" ? "Birth" : "Death"}`;
|
|
6455
6557
|
const fact = person.facts?.find((f) => f.type === factTypeUrl);
|
|
6456
6558
|
if (fact) {
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
""
|
|
6461
|
-
);
|
|
6559
|
+
const resolvedDate = resolveFactDate(fact.date);
|
|
6560
|
+
if (resolvedDate) {
|
|
6561
|
+
result.date = resolvedDate;
|
|
6462
6562
|
}
|
|
6463
6563
|
if (fact.place?.original) {
|
|
6464
6564
|
result.place = fact.place.original;
|
|
@@ -6511,25 +6611,30 @@ function convertFactToGedcom(fact) {
|
|
|
6511
6611
|
};
|
|
6512
6612
|
const gedcomTag = typeMap[fact.type] || "EVEN";
|
|
6513
6613
|
if (gedcomTag === "OCCU" && fact.value) {
|
|
6514
|
-
lines.push(`1 OCCU ${fact.value}`);
|
|
6614
|
+
lines.push(`1 OCCU ${sanitizeGedcomValue(fact.value)}`);
|
|
6515
6615
|
} else {
|
|
6516
6616
|
lines.push(`1 ${gedcomTag}`);
|
|
6517
6617
|
}
|
|
6618
|
+
if (gedcomTag === "EVEN") {
|
|
6619
|
+
const typeName = fact.type.split("/").pop();
|
|
6620
|
+
if (typeName) {
|
|
6621
|
+
lines.push(`2 TYPE ${sanitizeGedcomValue(typeName)}`);
|
|
6622
|
+
}
|
|
6623
|
+
}
|
|
6518
6624
|
if (fact.links?.conclusion?.href) {
|
|
6519
6625
|
const webUrl = transformFamilySearchUrl(fact.links.conclusion.href);
|
|
6520
6626
|
lines.push(`2 WWW ${webUrl}`);
|
|
6521
6627
|
lines.push(`3 _IS_FS Y`);
|
|
6522
6628
|
}
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
);
|
|
6629
|
+
const resolvedDate = resolveFactDate(fact.date);
|
|
6630
|
+
if (resolvedDate) {
|
|
6631
|
+
lines.push(`2 DATE ${sanitizeGedcomValue(resolvedDate)}`);
|
|
6527
6632
|
}
|
|
6528
6633
|
if (fact.place?.original) {
|
|
6529
|
-
lines.push(`2 PLAC ${fact.place.original}`);
|
|
6634
|
+
lines.push(`2 PLAC ${sanitizeGedcomValue(fact.place.original)}`);
|
|
6530
6635
|
}
|
|
6531
6636
|
if (fact.value && gedcomTag !== "OCCU") {
|
|
6532
|
-
lines.push(`2 NOTE ${fact.value}`);
|
|
6637
|
+
lines.push(`2 NOTE ${sanitizeGedcomValue(fact.value)}`);
|
|
6533
6638
|
}
|
|
6534
6639
|
return lines;
|
|
6535
6640
|
}
|
|
@@ -6549,14 +6654,14 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6549
6654
|
lines.push("2 VERS 1.0");
|
|
6550
6655
|
lines.push("2 NAME FamilySearch API");
|
|
6551
6656
|
if (treeName) {
|
|
6552
|
-
lines.push(`2 _TREE ${treeName}`);
|
|
6657
|
+
lines.push(`2 _TREE ${sanitizeGedcomValue(treeName)}`);
|
|
6553
6658
|
const randomRIN = Math.floor(Math.random() * 1e8);
|
|
6554
6659
|
lines.push(`3 RIN ${randomRIN}`);
|
|
6555
6660
|
}
|
|
6556
6661
|
lines.push("1 DEST ANY");
|
|
6557
6662
|
lines.push("1 DATE " + formatDateForGedcom(/* @__PURE__ */ new Date()));
|
|
6558
6663
|
lines.push("1 SUBM @SUBM1@");
|
|
6559
|
-
lines.push("1 FILE " + treeName);
|
|
6664
|
+
lines.push("1 FILE " + sanitizeGedcomValue(treeName));
|
|
6560
6665
|
lines.push("1 GEDC");
|
|
6561
6666
|
lines.push("2 VERS 5.5");
|
|
6562
6667
|
lines.push("2 FORM LINEAGE-LINKED");
|
|
@@ -6578,20 +6683,22 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6578
6683
|
const sourceId = `@S${sourceCounter++}@`;
|
|
6579
6684
|
lines.push(`0 ${sourceId} SOUR`);
|
|
6580
6685
|
const title = source.titles?.[0]?.value || "FamilySearch Source";
|
|
6581
|
-
lines.push(`1 TITL ${title}`);
|
|
6686
|
+
lines.push(`1 TITL ${sanitizeGedcomValue(title)}`);
|
|
6582
6687
|
if (source.citations?.[0]?.value) {
|
|
6583
|
-
lines.push(`1 TEXT ${source.citations[0].value}`);
|
|
6688
|
+
lines.push(`1 TEXT ${sanitizeGedcomValue(source.citations[0].value)}`);
|
|
6584
6689
|
}
|
|
6585
6690
|
if (source.about) {
|
|
6586
6691
|
const webUrl = transformSourceUrl(source.about);
|
|
6587
6692
|
lines.push(`1 WWW ${webUrl}`);
|
|
6588
6693
|
}
|
|
6589
6694
|
if (source.resourceType) {
|
|
6590
|
-
lines.push(
|
|
6695
|
+
lines.push(
|
|
6696
|
+
`1 NOTE Resource Type: ${sanitizeGedcomValue(source.resourceType)}`
|
|
6697
|
+
);
|
|
6591
6698
|
}
|
|
6592
6699
|
});
|
|
6593
6700
|
const fsSourMap = /* @__PURE__ */ new Map();
|
|
6594
|
-
let fsSourCounter =
|
|
6701
|
+
let fsSourCounter = sourceCounter;
|
|
6595
6702
|
pedigreeData.persons.forEach((person) => {
|
|
6596
6703
|
if (person.sources?.persons?.[0]?.sources) {
|
|
6597
6704
|
const sourceDescMap = /* @__PURE__ */ new Map();
|
|
@@ -6641,20 +6748,22 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6641
6748
|
lines.push(`1 _IS_FS Y`);
|
|
6642
6749
|
lines.push(`1 _FS_ID ${id}`);
|
|
6643
6750
|
if (source.titles?.[0]?.value) {
|
|
6644
|
-
lines.push(`1 TITL ${source.titles[0].value}`);
|
|
6751
|
+
lines.push(`1 TITL ${sanitizeGedcomValue(source.titles[0].value)}`);
|
|
6645
6752
|
}
|
|
6646
6753
|
if (source.citations?.[0]?.value) {
|
|
6647
|
-
lines.push(`1 TEXT ${source.citations[0].value}`);
|
|
6754
|
+
lines.push(`1 TEXT ${sanitizeGedcomValue(source.citations[0].value)}`);
|
|
6648
6755
|
}
|
|
6649
6756
|
if (source.about) {
|
|
6650
6757
|
const webUrl = transformSourceUrl(source.about);
|
|
6651
6758
|
lines.push(`1 WWW ${webUrl}`);
|
|
6652
6759
|
}
|
|
6653
6760
|
if (source.resourceType) {
|
|
6654
|
-
lines.push(
|
|
6761
|
+
lines.push(
|
|
6762
|
+
`1 NOTE Resource Type: ${sanitizeGedcomValue(source.resourceType)}`
|
|
6763
|
+
);
|
|
6655
6764
|
}
|
|
6656
6765
|
notes.forEach((note) => {
|
|
6657
|
-
lines.push(`1 NOTE ${note}`);
|
|
6766
|
+
lines.push(`1 NOTE ${sanitizeGedcomValue(note)}`);
|
|
6658
6767
|
});
|
|
6659
6768
|
});
|
|
6660
6769
|
const fsMatchMap = /* @__PURE__ */ new Map();
|
|
@@ -6674,7 +6783,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6674
6783
|
lines.push(`1 _IS_FS Y`);
|
|
6675
6784
|
lines.push(`1 _FS_ID ${id}`);
|
|
6676
6785
|
if (entry.title) {
|
|
6677
|
-
lines.push(`1 TITL ${entry.title}`);
|
|
6786
|
+
lines.push(`1 TITL ${sanitizeGedcomValue(entry.title)}`);
|
|
6678
6787
|
}
|
|
6679
6788
|
if (entry.content?.score !== void 0) {
|
|
6680
6789
|
lines.push(`1 SCORE ${entry.content.score}`);
|
|
@@ -6695,7 +6804,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6695
6804
|
}
|
|
6696
6805
|
if (matchInfo.status) {
|
|
6697
6806
|
const statusName = matchInfo.status.includes("/") ? matchInfo.status.split("/").pop() : matchInfo.status;
|
|
6698
|
-
lines.push(`1 NOTE Status: ${statusName}`);
|
|
6807
|
+
lines.push(`1 NOTE Status: ${sanitizeGedcomValue(statusName || "")}`);
|
|
6699
6808
|
}
|
|
6700
6809
|
}
|
|
6701
6810
|
lines.push(`1 TYPE ${collectionType}`);
|
|
@@ -6707,42 +6816,52 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6707
6816
|
if (entry.content?.gedcomx?.persons && entry.content.gedcomx.persons.length > 0) {
|
|
6708
6817
|
const matchedPerson = entry.content.gedcomx.persons[0];
|
|
6709
6818
|
if (matchedPerson.display?.name) {
|
|
6710
|
-
lines.push(`1 TEXT ${matchedPerson.display.name}`);
|
|
6819
|
+
lines.push(`1 TEXT ${sanitizeGedcomValue(matchedPerson.display.name)}`);
|
|
6711
6820
|
}
|
|
6712
6821
|
if (matchedPerson.display?.lifespan) {
|
|
6713
6822
|
lines.push(
|
|
6714
|
-
`1 NOTE Lifespan: ${matchedPerson.display.lifespan}`
|
|
6823
|
+
`1 NOTE Lifespan: ${sanitizeGedcomValue(matchedPerson.display.lifespan)}`
|
|
6715
6824
|
);
|
|
6716
6825
|
}
|
|
6717
6826
|
if (matchedPerson.display?.birthDate || matchedPerson.display?.birthPlace) {
|
|
6718
|
-
const birthInfo =
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6827
|
+
const birthInfo = sanitizeGedcomValue(
|
|
6828
|
+
[
|
|
6829
|
+
matchedPerson.display.birthDate,
|
|
6830
|
+
matchedPerson.display.birthPlace
|
|
6831
|
+
].filter(Boolean).join(", ")
|
|
6832
|
+
);
|
|
6722
6833
|
if (birthInfo) {
|
|
6723
6834
|
lines.push(`1 NOTE Birth: ${birthInfo}`);
|
|
6724
6835
|
}
|
|
6725
6836
|
}
|
|
6726
6837
|
if (matchedPerson.display?.deathDate || matchedPerson.display?.deathPlace) {
|
|
6727
|
-
const deathInfo =
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6838
|
+
const deathInfo = sanitizeGedcomValue(
|
|
6839
|
+
[
|
|
6840
|
+
matchedPerson.display.deathDate,
|
|
6841
|
+
matchedPerson.display.deathPlace
|
|
6842
|
+
].filter(Boolean).join(", ")
|
|
6843
|
+
);
|
|
6731
6844
|
if (deathInfo) {
|
|
6732
6845
|
lines.push(`1 NOTE Death: ${deathInfo}`);
|
|
6733
6846
|
}
|
|
6734
6847
|
}
|
|
6735
6848
|
if (matchedPerson.display?.gender) {
|
|
6736
|
-
lines.push(
|
|
6849
|
+
lines.push(
|
|
6850
|
+
`1 NOTE Gender: ${sanitizeGedcomValue(matchedPerson.display.gender)}`
|
|
6851
|
+
);
|
|
6737
6852
|
}
|
|
6738
6853
|
}
|
|
6739
6854
|
if (entry.content?.sourceDescription) {
|
|
6740
6855
|
const sourceDesc = entry.content.sourceDescription;
|
|
6741
6856
|
if (sourceDesc.citations?.[0]?.value) {
|
|
6742
|
-
lines.push(
|
|
6857
|
+
lines.push(
|
|
6858
|
+
`1 NOTE Citation: ${sanitizeGedcomValue(sourceDesc.citations[0].value)}`
|
|
6859
|
+
);
|
|
6743
6860
|
}
|
|
6744
6861
|
if (sourceDesc.resourceType) {
|
|
6745
|
-
lines.push(
|
|
6862
|
+
lines.push(
|
|
6863
|
+
`1 NOTE Resource Type: ${sanitizeGedcomValue(sourceDesc.resourceType)}`
|
|
6864
|
+
);
|
|
6746
6865
|
}
|
|
6747
6866
|
if (sourceDesc.about) {
|
|
6748
6867
|
const webUrl = transformSourceUrl(sourceDesc.about);
|
|
@@ -6985,7 +7104,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6985
7104
|
const personData = person.fullDetails?.persons?.[0] || person;
|
|
6986
7105
|
const name = extractName(personData);
|
|
6987
7106
|
if (name) {
|
|
6988
|
-
lines.push(`1 NAME ${name}`);
|
|
7107
|
+
lines.push(`1 NAME ${sanitizeGedcomValue(name)}`);
|
|
6989
7108
|
}
|
|
6990
7109
|
const gender = extractGender(personData);
|
|
6991
7110
|
if (gender) {
|
|
@@ -6995,20 +7114,20 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
6995
7114
|
if (birth) {
|
|
6996
7115
|
lines.push("1 BIRT");
|
|
6997
7116
|
if (birth.date) {
|
|
6998
|
-
lines.push(`2 DATE ${birth.date}`);
|
|
7117
|
+
lines.push(`2 DATE ${sanitizeGedcomValue(birth.date)}`);
|
|
6999
7118
|
}
|
|
7000
7119
|
if (birth.place) {
|
|
7001
|
-
lines.push(`2 PLAC ${birth.place}`);
|
|
7120
|
+
lines.push(`2 PLAC ${sanitizeGedcomValue(birth.place)}`);
|
|
7002
7121
|
}
|
|
7003
7122
|
}
|
|
7004
7123
|
const death = extractFact(personData, "DEATH");
|
|
7005
7124
|
if (death) {
|
|
7006
7125
|
lines.push("1 DEAT");
|
|
7007
7126
|
if (death.date) {
|
|
7008
|
-
lines.push(`2 DATE ${death.date}`);
|
|
7127
|
+
lines.push(`2 DATE ${sanitizeGedcomValue(death.date)}`);
|
|
7009
7128
|
}
|
|
7010
7129
|
if (death.place) {
|
|
7011
|
-
lines.push(`2 PLAC ${death.place}`);
|
|
7130
|
+
lines.push(`2 PLAC ${sanitizeGedcomValue(death.place)}`);
|
|
7012
7131
|
}
|
|
7013
7132
|
}
|
|
7014
7133
|
personData.facts?.forEach((fact) => {
|
|
@@ -7020,8 +7139,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
7020
7139
|
if (includeNotes && person.notes?.persons?.[0]?.notes) {
|
|
7021
7140
|
person.notes.persons[0].notes.forEach((note) => {
|
|
7022
7141
|
if (note.text) {
|
|
7023
|
-
|
|
7024
|
-
lines.push(`1 NOTE ${noteText}`);
|
|
7142
|
+
lines.push(`1 NOTE ${sanitizeGedcomValue(note.text)}`);
|
|
7025
7143
|
}
|
|
7026
7144
|
});
|
|
7027
7145
|
}
|
|
@@ -7039,7 +7157,7 @@ function convertToGedcom(pedigreeData, options = {}) {
|
|
|
7039
7157
|
sourceRef.qualifiers.forEach((qualifier) => {
|
|
7040
7158
|
if (qualifier.name && qualifier.value) {
|
|
7041
7159
|
lines.push(
|
|
7042
|
-
`2 NOTE ${qualifier.name}: ${qualifier.value}`
|
|
7160
|
+
`2 NOTE ${sanitizeGedcomValue(`${qualifier.name}: ${qualifier.value}`)}`
|
|
7043
7161
|
);
|
|
7044
7162
|
}
|
|
7045
7163
|
});
|
|
@@ -7193,35 +7311,40 @@ function addMarriageFacts(lines, relationships, person1, person2) {
|
|
|
7193
7311
|
return [a, b].sort().join("-") === relKey;
|
|
7194
7312
|
});
|
|
7195
7313
|
if (!rel) return;
|
|
7314
|
+
const isMarriageEvent = (type) => !!type && (type.includes("Marriage") || type.includes("Divorce"));
|
|
7196
7315
|
const marriageFacts = [];
|
|
7197
7316
|
if (rel.facts && Array.isArray(rel.facts)) {
|
|
7198
7317
|
rel.facts.forEach((f) => {
|
|
7199
|
-
if (f.type
|
|
7318
|
+
if (isMarriageEvent(f.type)) {
|
|
7200
7319
|
marriageFacts.push(f);
|
|
7201
7320
|
}
|
|
7202
7321
|
});
|
|
7203
7322
|
}
|
|
7204
7323
|
if (rel.details?.facts && Array.isArray(rel.details.facts)) {
|
|
7205
7324
|
marriageFacts.push(
|
|
7206
|
-
...rel.details.facts.filter((f) => f.type
|
|
7325
|
+
...rel.details.facts.filter((f) => isMarriageEvent(f.type))
|
|
7207
7326
|
);
|
|
7208
7327
|
}
|
|
7209
7328
|
if (rel.details?.persons && Array.isArray(rel.details.persons)) {
|
|
7210
7329
|
rel.details.persons.forEach((p) => {
|
|
7211
7330
|
if (p.facts && Array.isArray(p.facts)) {
|
|
7212
7331
|
p.facts.forEach((f) => {
|
|
7213
|
-
if (f.type
|
|
7332
|
+
if (isMarriageEvent(f.type)) {
|
|
7214
7333
|
marriageFacts.push(f);
|
|
7215
7334
|
}
|
|
7216
7335
|
});
|
|
7217
7336
|
}
|
|
7218
7337
|
});
|
|
7219
7338
|
}
|
|
7339
|
+
const seenFacts = /* @__PURE__ */ new Set();
|
|
7220
7340
|
marriageFacts.forEach((mf) => {
|
|
7341
|
+
const key = `${mf.type}|${resolveFactDate(mf.date) || ""}|${mf.place?.original || ""}`;
|
|
7342
|
+
if (seenFacts.has(key)) return;
|
|
7343
|
+
seenFacts.add(key);
|
|
7221
7344
|
const factLines = convertFactToGedcom(mf);
|
|
7222
7345
|
factLines.forEach((line) => lines.push(line));
|
|
7223
7346
|
});
|
|
7224
7347
|
}
|
|
7225
7348
|
var convertFamilySearchToGedcom = convertToGedcom;
|
|
7226
7349
|
|
|
7227
|
-
export { AuthenticationError, ENVIRONMENT_CONFIGS, FamilySearchError, FamilySearchSDK, genealogies_exports as GenealogiesAPI, memories_exports as MemoriesAPI, NetworkError, NotFoundError, OAUTH_ENDPOINTS, OAUTH_STORAGE_KEYS, OAuthAPI, PedigreeAPI, PlacesAPI, RateLimitError, ServerError, standards_exports as StandardsAPI, tree_exports as TreeAPI, user_exports as UserAPI, ValidationError, vocab_exports as VocabAPI, buildAuthorizationUrl, checkPlaceIsChild, clearAllTokens, clearStoredTokens, convertFamilySearchToGedcom, convertToGedcom, createErrorFromResponse, createFamilySearchSDK, createNetworkError, exchangeCodeForToken, fetchMultiplePersons, fetchPedigree, generateOAuthState, getFamilySearchSDK, getOAuthEndpoints, getStoredAccessToken, getStoredRefreshToken, getTokenStorageKey, getUserInfo, initFamilySearchSDK, isRetryableError, openOAuthPopup, parseCallbackParams, readCurrentUser2 as readCurrentUser, readPlaceAttributes, readPlaceChildren, readPlaceDescription, readPlaceDescriptionWithRelated, readPlaceDescriptions, readPlaceDescriptionsGroup, readPlaceDetails, readPlaceType, readPlaceTypeGroup, readPlaceTypeGroups, readPlaceTypes, refreshAccessToken, resetFamilySearchSDK, searchParentPlaces, searchPlaces, storeOAuthState, storeTokens, transformFamilySearchUrl, validateAccessToken, validateOAuthState };
|
|
7350
|
+
export { AuthenticationError, ENVIRONMENT_CONFIGS, FamilySearchError, FamilySearchSDK, genealogies_exports as GenealogiesAPI, memories_exports as MemoriesAPI, NetworkError, NotFoundError, OAUTH_ENDPOINTS, OAUTH_STORAGE_KEYS, OAuthAPI, PedigreeAPI, PlacesAPI, RateLimitError, ServerError, standards_exports as StandardsAPI, tree_exports as TreeAPI, user_exports as UserAPI, ValidationError, vocab_exports as VocabAPI, buildAuthorizationUrl, checkPlaceIsChild, clearAllTokens, clearStoredTokens, convertFamilySearchToGedcom, convertToGedcom, createErrorFromResponse, createFamilySearchSDK, createNetworkError, exchangeCodeForToken, extractGazetteerPlaceId, familySearchResearchPlaceUrl, fetchMultiplePersons, fetchPedigree, generateOAuthState, getFamilySearchSDK, getOAuthEndpoints, getStoredAccessToken, getStoredRefreshToken, getTokenStorageKey, getUserInfo, initFamilySearchSDK, isRetryableError, numericPlaceIdFromRef, openOAuthPopup, parseCallbackParams, pickBestPlaceSearchResult, readCurrentUser2 as readCurrentUser, readPlaceAttributes, readPlaceChildren, readPlaceDescription, readPlaceDescriptionWithRelated, readPlaceDescriptions, readPlaceDescriptionsGroup, readPlaceDetails, readPlaceType, readPlaceTypeGroup, readPlaceTypeGroups, readPlaceTypes, refreshAccessToken, resetFamilySearchSDK, searchParentPlaces, searchPlaces, storeOAuthState, storeTokens, transformFamilySearchUrl, validateAccessToken, validateOAuthState };
|
package/dist/places/index.cjs
CHANGED
|
@@ -298,8 +298,46 @@ var PlacesAPI = class {
|
|
|
298
298
|
}
|
|
299
299
|
};
|
|
300
300
|
|
|
301
|
+
// src/places/gazetteer-id.ts
|
|
302
|
+
var numericPlaceIdFromRef = (ref) => {
|
|
303
|
+
if (!ref) {
|
|
304
|
+
return void 0;
|
|
305
|
+
}
|
|
306
|
+
if (ref.includes("/places/description/") || ref.includes("ark:/")) {
|
|
307
|
+
return void 0;
|
|
308
|
+
}
|
|
309
|
+
const match = ref.match(/\/places\/(\d+)/);
|
|
310
|
+
return match?.[1];
|
|
311
|
+
};
|
|
312
|
+
var extractGazetteerPlaceId = (place) => {
|
|
313
|
+
const persistent = place.identifiers?.["http://gedcomx.org/Persistent"]?.[0];
|
|
314
|
+
const fromPersistent = numericPlaceIdFromRef(persistent);
|
|
315
|
+
if (fromPersistent) {
|
|
316
|
+
return fromPersistent;
|
|
317
|
+
}
|
|
318
|
+
return numericPlaceIdFromRef(place.place?.description);
|
|
319
|
+
};
|
|
320
|
+
var familySearchResearchPlaceUrl = (placeId, baseUrl = "https://www.familysearch.org") => `${baseUrl}/en/research/places/?focusedId=${placeId}`;
|
|
321
|
+
var pickBestPlaceSearchResult = (results, query) => {
|
|
322
|
+
if (results.length === 0) {
|
|
323
|
+
return void 0;
|
|
324
|
+
}
|
|
325
|
+
const town = query.split(",")[0]?.trim().toLowerCase();
|
|
326
|
+
if (!town) {
|
|
327
|
+
return results[0];
|
|
328
|
+
}
|
|
329
|
+
const label = (result) => (result.fullName || result.name || result.title || "").toLowerCase();
|
|
330
|
+
return results.find(
|
|
331
|
+
(result) => label(result) === town || label(result).startsWith(`${town},`)
|
|
332
|
+
) || results.find((result) => label(result).includes(town)) || results[0];
|
|
333
|
+
};
|
|
334
|
+
|
|
301
335
|
exports.PlacesAPI = PlacesAPI;
|
|
302
336
|
exports.checkPlaceIsChild = checkPlaceIsChild;
|
|
337
|
+
exports.extractGazetteerPlaceId = extractGazetteerPlaceId;
|
|
338
|
+
exports.familySearchResearchPlaceUrl = familySearchResearchPlaceUrl;
|
|
339
|
+
exports.numericPlaceIdFromRef = numericPlaceIdFromRef;
|
|
340
|
+
exports.pickBestPlaceSearchResult = pickBestPlaceSearchResult;
|
|
303
341
|
exports.readPlaceAttributes = readPlaceAttributes;
|
|
304
342
|
exports.readPlaceChildren = readPlaceChildren;
|
|
305
343
|
exports.readPlaceDescription = readPlaceDescription;
|
package/dist/places/index.d.cts
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
export { bW as PlacesAPI, bY as checkPlaceIsChild, b$ as readPlaceAttributes, c0 as readPlaceChildren, c1 as readPlaceDescription, c2 as readPlaceDescriptionWithRelated, c3 as readPlaceDescriptions, c4 as readPlaceDescriptionsGroup, c5 as readPlaceDetails, c6 as readPlaceType, c7 as readPlaceTypeGroup, c8 as readPlaceTypeGroups, c9 as readPlaceTypes, cd as searchParentPlaces, ce as searchPlaces } from '../
|
|
1
|
+
export { bW as PlacesAPI, bY as checkPlaceIsChild, b$ as readPlaceAttributes, c0 as readPlaceChildren, c1 as readPlaceDescription, c2 as readPlaceDescriptionWithRelated, c3 as readPlaceDescriptions, c4 as readPlaceDescriptionsGroup, c5 as readPlaceDetails, c6 as readPlaceType, c7 as readPlaceTypeGroup, c8 as readPlaceTypeGroups, c9 as readPlaceTypes, cd as searchParentPlaces, ce as searchPlaces } from '../tree-changes-e0UMhVha.cjs';
|
|
2
2
|
import '../tree-D7X-beAQ.cjs';
|
|
3
3
|
import '../index-0PpnEPuZ.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* FamilySearch Places search returns Place Descriptions.
|
|
7
|
+
* `place.id` is a Description ID. The Places web UI `focusedId` is a
|
|
8
|
+
* gazetteer Place ID (different namespace). The Place ID lives on
|
|
9
|
+
* `identifiers["http://gedcomx.org/Persistent"]` or `place.place`.
|
|
10
|
+
*
|
|
11
|
+
* @see https://developers.familysearch.org/main/docs/places
|
|
12
|
+
*/
|
|
13
|
+
type FamilySearchPlacePayload = {
|
|
14
|
+
id?: string;
|
|
15
|
+
identifiers?: Record<string, string[]>;
|
|
16
|
+
place?: {
|
|
17
|
+
original?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
};
|
|
20
|
+
display?: {
|
|
21
|
+
name?: string;
|
|
22
|
+
fullName?: string;
|
|
23
|
+
type?: string;
|
|
24
|
+
};
|
|
25
|
+
names?: Array<{
|
|
26
|
+
value?: string;
|
|
27
|
+
}>;
|
|
28
|
+
type?: string;
|
|
29
|
+
latitude?: number;
|
|
30
|
+
longitude?: number;
|
|
31
|
+
};
|
|
32
|
+
/** Numeric ID from a Place authority URL, never from /places/description/. */
|
|
33
|
+
declare const numericPlaceIdFromRef: (ref?: string) => string | undefined;
|
|
34
|
+
declare const extractGazetteerPlaceId: (place: FamilySearchPlacePayload) => string | undefined;
|
|
35
|
+
declare const familySearchResearchPlaceUrl: (placeId: string, baseUrl?: string) => string;
|
|
36
|
+
declare const pickBestPlaceSearchResult: <T extends {
|
|
37
|
+
name?: string;
|
|
38
|
+
fullName?: string;
|
|
39
|
+
title?: string;
|
|
40
|
+
}>(results: T[], query: string) => T | undefined;
|
|
41
|
+
|
|
42
|
+
export { type FamilySearchPlacePayload, extractGazetteerPlaceId, familySearchResearchPlaceUrl, numericPlaceIdFromRef, pickBestPlaceSearchResult };
|
package/dist/places/index.d.ts
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
-
export { bW as PlacesAPI, bY as checkPlaceIsChild, b$ as readPlaceAttributes, c0 as readPlaceChildren, c1 as readPlaceDescription, c2 as readPlaceDescriptionWithRelated, c3 as readPlaceDescriptions, c4 as readPlaceDescriptionsGroup, c5 as readPlaceDetails, c6 as readPlaceType, c7 as readPlaceTypeGroup, c8 as readPlaceTypeGroups, c9 as readPlaceTypes, cd as searchParentPlaces, ce as searchPlaces } from '../
|
|
1
|
+
export { bW as PlacesAPI, bY as checkPlaceIsChild, b$ as readPlaceAttributes, c0 as readPlaceChildren, c1 as readPlaceDescription, c2 as readPlaceDescriptionWithRelated, c3 as readPlaceDescriptions, c4 as readPlaceDescriptionsGroup, c5 as readPlaceDetails, c6 as readPlaceType, c7 as readPlaceTypeGroup, c8 as readPlaceTypeGroups, c9 as readPlaceTypes, cd as searchParentPlaces, ce as searchPlaces } from '../tree-changes-CFwJtBcK.js';
|
|
2
2
|
import '../tree-D7X-beAQ.js';
|
|
3
3
|
import '../index-0PpnEPuZ.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* FamilySearch Places search returns Place Descriptions.
|
|
7
|
+
* `place.id` is a Description ID. The Places web UI `focusedId` is a
|
|
8
|
+
* gazetteer Place ID (different namespace). The Place ID lives on
|
|
9
|
+
* `identifiers["http://gedcomx.org/Persistent"]` or `place.place`.
|
|
10
|
+
*
|
|
11
|
+
* @see https://developers.familysearch.org/main/docs/places
|
|
12
|
+
*/
|
|
13
|
+
type FamilySearchPlacePayload = {
|
|
14
|
+
id?: string;
|
|
15
|
+
identifiers?: Record<string, string[]>;
|
|
16
|
+
place?: {
|
|
17
|
+
original?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
};
|
|
20
|
+
display?: {
|
|
21
|
+
name?: string;
|
|
22
|
+
fullName?: string;
|
|
23
|
+
type?: string;
|
|
24
|
+
};
|
|
25
|
+
names?: Array<{
|
|
26
|
+
value?: string;
|
|
27
|
+
}>;
|
|
28
|
+
type?: string;
|
|
29
|
+
latitude?: number;
|
|
30
|
+
longitude?: number;
|
|
31
|
+
};
|
|
32
|
+
/** Numeric ID from a Place authority URL, never from /places/description/. */
|
|
33
|
+
declare const numericPlaceIdFromRef: (ref?: string) => string | undefined;
|
|
34
|
+
declare const extractGazetteerPlaceId: (place: FamilySearchPlacePayload) => string | undefined;
|
|
35
|
+
declare const familySearchResearchPlaceUrl: (placeId: string, baseUrl?: string) => string;
|
|
36
|
+
declare const pickBestPlaceSearchResult: <T extends {
|
|
37
|
+
name?: string;
|
|
38
|
+
fullName?: string;
|
|
39
|
+
title?: string;
|
|
40
|
+
}>(results: T[], query: string) => T | undefined;
|
|
41
|
+
|
|
42
|
+
export { type FamilySearchPlacePayload, extractGazetteerPlaceId, familySearchResearchPlaceUrl, numericPlaceIdFromRef, pickBestPlaceSearchResult };
|
package/dist/places/index.js
CHANGED
|
@@ -296,4 +296,38 @@ var PlacesAPI = class {
|
|
|
296
296
|
}
|
|
297
297
|
};
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
// src/places/gazetteer-id.ts
|
|
300
|
+
var numericPlaceIdFromRef = (ref) => {
|
|
301
|
+
if (!ref) {
|
|
302
|
+
return void 0;
|
|
303
|
+
}
|
|
304
|
+
if (ref.includes("/places/description/") || ref.includes("ark:/")) {
|
|
305
|
+
return void 0;
|
|
306
|
+
}
|
|
307
|
+
const match = ref.match(/\/places\/(\d+)/);
|
|
308
|
+
return match?.[1];
|
|
309
|
+
};
|
|
310
|
+
var extractGazetteerPlaceId = (place) => {
|
|
311
|
+
const persistent = place.identifiers?.["http://gedcomx.org/Persistent"]?.[0];
|
|
312
|
+
const fromPersistent = numericPlaceIdFromRef(persistent);
|
|
313
|
+
if (fromPersistent) {
|
|
314
|
+
return fromPersistent;
|
|
315
|
+
}
|
|
316
|
+
return numericPlaceIdFromRef(place.place?.description);
|
|
317
|
+
};
|
|
318
|
+
var familySearchResearchPlaceUrl = (placeId, baseUrl = "https://www.familysearch.org") => `${baseUrl}/en/research/places/?focusedId=${placeId}`;
|
|
319
|
+
var pickBestPlaceSearchResult = (results, query) => {
|
|
320
|
+
if (results.length === 0) {
|
|
321
|
+
return void 0;
|
|
322
|
+
}
|
|
323
|
+
const town = query.split(",")[0]?.trim().toLowerCase();
|
|
324
|
+
if (!town) {
|
|
325
|
+
return results[0];
|
|
326
|
+
}
|
|
327
|
+
const label = (result) => (result.fullName || result.name || result.title || "").toLowerCase();
|
|
328
|
+
return results.find(
|
|
329
|
+
(result) => label(result) === town || label(result).startsWith(`${town},`)
|
|
330
|
+
) || results.find((result) => label(result).includes(town)) || results[0];
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
export { PlacesAPI, checkPlaceIsChild, extractGazetteerPlaceId, familySearchResearchPlaceUrl, numericPlaceIdFromRef, pickBestPlaceSearchResult, readPlaceAttributes, readPlaceChildren, readPlaceDescription, readPlaceDescriptionWithRelated, readPlaceDescriptions, readPlaceDescriptionsGroup, readPlaceDetails, readPlaceType, readPlaceTypeGroup, readPlaceTypeGroups, readPlaceTypes, searchParentPlaces, searchPlaces };
|
package/dist/tree/index.cjs
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/api/tree/persons.ts
|
|
4
|
+
var PERSON_WRITE_HEADERS = {
|
|
5
|
+
"Content-Type": "application/x-fs-v1+json",
|
|
6
|
+
Accept: "application/x-fs-v1+json"
|
|
7
|
+
};
|
|
4
8
|
async function readPerson(sdk, personId) {
|
|
5
9
|
try {
|
|
6
10
|
const response = await sdk.get(
|
|
@@ -33,7 +37,7 @@ async function readPersonWithDetails(sdk, personId, options = {}) {
|
|
|
33
37
|
}
|
|
34
38
|
async function createPerson(sdk, person, reason) {
|
|
35
39
|
try {
|
|
36
|
-
const headers = {};
|
|
40
|
+
const headers = { ...PERSON_WRITE_HEADERS };
|
|
37
41
|
if (reason) {
|
|
38
42
|
headers["X-Reason"] = reason;
|
|
39
43
|
}
|
|
@@ -50,7 +54,7 @@ async function createPerson(sdk, person, reason) {
|
|
|
50
54
|
}
|
|
51
55
|
async function updatePerson(sdk, personId, person, reason) {
|
|
52
56
|
try {
|
|
53
|
-
const headers = {};
|
|
57
|
+
const headers = { ...PERSON_WRITE_HEADERS };
|
|
54
58
|
if (reason) {
|
|
55
59
|
headers["X-Reason"] = reason;
|
|
56
60
|
}
|