ochre-sdk 1.0.4 → 1.0.6
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/README.md +1 -1
- package/dist/index.mjs +118 -87
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ const result = await fetchItem("<item-uuid>", {
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
if (result.error != null) {
|
|
36
|
-
throw new Error(result.error);
|
|
36
|
+
throw new Error("Failed to fetch item", { cause: result.error });
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
console.log(result.item.identification.label.getText("eng"));
|
package/dist/index.mjs
CHANGED
|
@@ -1409,6 +1409,12 @@ function parseStringContent(value, options = FALLBACK_PARSER_OPTIONS) {
|
|
|
1409
1409
|
}
|
|
1410
1410
|
//#endregion
|
|
1411
1411
|
//#region src/parsers/index.ts
|
|
1412
|
+
function isXMLContextGroup(context) {
|
|
1413
|
+
return "context" in context;
|
|
1414
|
+
}
|
|
1415
|
+
function isXMLContextItem(context) {
|
|
1416
|
+
return "project" in context;
|
|
1417
|
+
}
|
|
1412
1418
|
const SET_ITEM_CATEGORIES = ["tree", ...[
|
|
1413
1419
|
"bibliography",
|
|
1414
1420
|
"concept",
|
|
@@ -1521,27 +1527,33 @@ function emptyContextItem() {
|
|
|
1521
1527
|
}
|
|
1522
1528
|
function parseContext(rawContext) {
|
|
1523
1529
|
const nodes = [];
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1530
|
+
let displayPath = "";
|
|
1531
|
+
for (const rawContextOuterItem of rawContext) {
|
|
1532
|
+
if (!isXMLContextGroup(rawContextOuterItem)) continue;
|
|
1533
|
+
displayPath = displayPath || rawContextOuterItem.displayPath;
|
|
1534
|
+
for (const rawContextItem of rawContextOuterItem.context) {
|
|
1535
|
+
if (!isXMLContextItem(rawContextItem)) continue;
|
|
1536
|
+
const node = {
|
|
1537
|
+
tree: rawContextItem.tree[0] == null ? emptyContextItem() : parseContextItem$1(rawContextItem.tree[0]),
|
|
1538
|
+
project: parseContextItem$1(rawContextItem.project),
|
|
1539
|
+
heading: []
|
|
1540
|
+
};
|
|
1541
|
+
const rawContextValues = rawContextItem;
|
|
1542
|
+
for (const heading of rawContextValues.heading ?? []) node.heading.push(parseContextItem$1(heading));
|
|
1543
|
+
for (const { raw, parsed } of CONTEXT_CATEGORY_MAPPINGS) {
|
|
1544
|
+
const contextValues = rawContextValues[raw] ?? [];
|
|
1545
|
+
for (const contextValue of contextValues) {
|
|
1546
|
+
const parsedItems = node[parsed] ?? [];
|
|
1547
|
+
parsedItems.push(parseContextItem$1(contextValue));
|
|
1548
|
+
node[parsed] = parsedItems;
|
|
1549
|
+
}
|
|
1538
1550
|
}
|
|
1551
|
+
nodes.push(node);
|
|
1539
1552
|
}
|
|
1540
|
-
nodes.push(node);
|
|
1541
1553
|
}
|
|
1542
1554
|
return {
|
|
1543
1555
|
nodes,
|
|
1544
|
-
displayPath
|
|
1556
|
+
displayPath
|
|
1545
1557
|
};
|
|
1546
1558
|
}
|
|
1547
1559
|
function parseEventReference(rawReference, options) {
|
|
@@ -1692,16 +1704,19 @@ function normalizeSetItemCategories(containedItemCategory) {
|
|
|
1692
1704
|
return uniqueCategories;
|
|
1693
1705
|
}
|
|
1694
1706
|
function normalizeTreeItemCategory(containedItemCategory) {
|
|
1695
|
-
if (containedItemCategory != null && typeof containedItemCategory !== "string") throw new Error("Tree containedItemCategory must be a single category");
|
|
1696
|
-
if (containedItemCategory === "tree") throw new Error("Tree containedItemCategory cannot be \"tree\"");
|
|
1707
|
+
if (containedItemCategory != null && typeof containedItemCategory !== "string") throw new Error("Tree containedItemCategory must be a single category", { cause: containedItemCategory });
|
|
1708
|
+
if (containedItemCategory === "tree") throw new Error("Tree containedItemCategory cannot be \"tree\"", { cause: containedItemCategory });
|
|
1697
1709
|
return containedItemCategory;
|
|
1698
1710
|
}
|
|
1699
1711
|
function resolveTreeItemCategory(rawTree, containedItemCategory) {
|
|
1700
1712
|
const inferredCategories = inferItemCategories(rawTree.items);
|
|
1701
|
-
if (inferredCategories.length > 1) throw new Error(`Expected Tree items to contain one category, received ${inferredCategories.join(", ")}
|
|
1713
|
+
if (inferredCategories.length > 1) throw new Error(`Expected Tree items to contain one category, received ${inferredCategories.join(", ")}`, { cause: inferredCategories });
|
|
1702
1714
|
const inferredCategory = inferredCategories[0] ?? null;
|
|
1703
|
-
if (inferredCategory === "tree") throw new Error("Tree items cannot contain category \"tree\"");
|
|
1704
|
-
if (containedItemCategory != null && inferredCategory != null && containedItemCategory !== inferredCategory) throw new Error(`Tree containedItemCategory "${containedItemCategory}" does not match XML items category "${inferredCategory}"
|
|
1715
|
+
if (inferredCategory === "tree") throw new Error("Tree items cannot contain category \"tree\"", { cause: inferredCategory });
|
|
1716
|
+
if (containedItemCategory != null && inferredCategory != null && containedItemCategory !== inferredCategory) throw new Error(`Tree containedItemCategory "${containedItemCategory}" does not match XML items category "${inferredCategory}"`, { cause: {
|
|
1717
|
+
containedItemCategory,
|
|
1718
|
+
inferredCategory
|
|
1719
|
+
} });
|
|
1705
1720
|
return containedItemCategory ?? inferredCategory;
|
|
1706
1721
|
}
|
|
1707
1722
|
function parseImage(rawImage, options) {
|
|
@@ -1849,12 +1864,13 @@ function parseNotes(rawNotes, options) {
|
|
|
1849
1864
|
}
|
|
1850
1865
|
function parsePropertyDataType(dataType) {
|
|
1851
1866
|
if (dataType == null || dataType === "") return "string";
|
|
1852
|
-
|
|
1853
|
-
|
|
1867
|
+
const normalizedDataType = dataType.startsWith("xs:") ? dataType.slice(3) : dataType;
|
|
1868
|
+
for (const propertyDataType of PROPERTY_DATA_TYPES) if (normalizedDataType === propertyDataType) return propertyDataType;
|
|
1869
|
+
throw new Error(`Invalid property value data type: ${dataType}`, { cause: dataType });
|
|
1854
1870
|
}
|
|
1855
1871
|
function parsePropertyValueContent(value, options) {
|
|
1856
1872
|
const dataType = parsePropertyDataType(value.dataType);
|
|
1857
|
-
const rawLabel = value.content
|
|
1873
|
+
const rawLabel = value.content != null ? parseRequiredContentLike(value, options) : value.payload != null && value.payload !== "" ? multilingualFromText(value.payload, options) : null;
|
|
1858
1874
|
const displayText = rawLabel?.getText() ?? value.payload ?? value.slug ?? "";
|
|
1859
1875
|
const contentText = value.rawValue ?? value.payload ?? displayText;
|
|
1860
1876
|
const common = {
|
|
@@ -2580,7 +2596,7 @@ function resolveLanguages(requestedLanguages, metadataLanguages) {
|
|
|
2580
2596
|
if (requestedLanguages.length === 0) return metadataLanguages;
|
|
2581
2597
|
const unsupportedLanguages = [];
|
|
2582
2598
|
for (const requestedLanguage of requestedLanguages) if (!metadataLanguages.some((metadataLanguage) => metadataLanguage.toLocaleLowerCase("en-US") === requestedLanguage.toLocaleLowerCase("en-US"))) unsupportedLanguages.push(requestedLanguage);
|
|
2583
|
-
if (unsupportedLanguages.length > 0) throw new Error(`The following language(s) are not supported by the dataset: ${unsupportedLanguages.toSorted((a, b) => a.localeCompare(b, "en-US")).join(", ")}. Available languages: ${metadataLanguages.toSorted((a, b) => a.localeCompare(b, "en-US")).join(", ")}
|
|
2599
|
+
if (unsupportedLanguages.length > 0) throw new Error(`The following language(s) are not supported by the dataset: ${unsupportedLanguages.toSorted((a, b) => a.localeCompare(b, "en-US")).join(", ")}. Available languages: ${metadataLanguages.toSorted((a, b) => a.localeCompare(b, "en-US")).join(", ")}`, { cause: unsupportedLanguages });
|
|
2584
2600
|
return requestedLanguages;
|
|
2585
2601
|
}
|
|
2586
2602
|
function resolveDefaultLanguage(rawOchre, languages) {
|
|
@@ -2590,7 +2606,7 @@ function resolveDefaultLanguage(rawOchre, languages) {
|
|
|
2590
2606
|
}
|
|
2591
2607
|
for (const language of languages) if (language === DEFAULT_LANGUAGES[0]) return language;
|
|
2592
2608
|
const firstLanguage = languages[0];
|
|
2593
|
-
if (firstLanguage == null) throw new Error("Default language not found");
|
|
2609
|
+
if (firstLanguage == null) throw new Error("Default language not found", { cause: languages });
|
|
2594
2610
|
return firstLanguage;
|
|
2595
2611
|
}
|
|
2596
2612
|
function parseMetadataPublisher(rawPublisher) {
|
|
@@ -2635,11 +2651,11 @@ function inferTopLevelCategory(rawOchre) {
|
|
|
2635
2651
|
for (const category of SET_ITEM_CATEGORIES) if (category in rawOchre) return category;
|
|
2636
2652
|
if ("variable" in rawOchre) return "propertyVariable";
|
|
2637
2653
|
if ("value" in rawOchre) return "propertyValue";
|
|
2638
|
-
throw new Error("Could not infer OCHRE item category");
|
|
2654
|
+
throw new Error("Could not infer OCHRE item category", { cause: rawOchre });
|
|
2639
2655
|
}
|
|
2640
2656
|
function getSingleTopLevelRawItem(items, category) {
|
|
2641
|
-
if (items == null || items.length === 0) throw new Error(`${category} not found
|
|
2642
|
-
if (items.length > 1) throw new Error(`Expected one ${category}, received ${items.length}
|
|
2657
|
+
if (items == null || items.length === 0) throw new Error(`${category} not found`, { cause: items });
|
|
2658
|
+
if (items.length > 1) throw new Error(`Expected one ${category}, received ${items.length}`, { cause: items });
|
|
2643
2659
|
return items[0];
|
|
2644
2660
|
}
|
|
2645
2661
|
function parseTopLevelItem(rawOchre, category, options) {
|
|
@@ -2826,10 +2842,12 @@ const XMLContextItem = v.objectWithRest({
|
|
|
2826
2842
|
tree: v.array(XMLContextValue),
|
|
2827
2843
|
displayPath: v.string("XMLContextItem: displayPath is string and required")
|
|
2828
2844
|
}, v.array(XMLContextValue), "XMLContextItem: Shape error");
|
|
2829
|
-
const
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2845
|
+
const XMLEmptyContext = v.object({ payload: v.string("XMLEmptyContext: payload is string and required") }, "XMLEmptyContext: Shape error");
|
|
2846
|
+
const XMLContextGroup = v.object({
|
|
2847
|
+
context: v.array(v.union([XMLContextItem, XMLEmptyContext]), "XMLContextGroup: context is array of XMLContextItem or XMLEmptyContext"),
|
|
2848
|
+
displayPath: v.string("XMLContextGroup: displayPath is string and required")
|
|
2849
|
+
}, "XMLContextGroup: Shape error");
|
|
2850
|
+
const XMLContext = v.array(v.union([XMLContextGroup, XMLEmptyContext], "XMLContext: item is XMLContextGroup or XMLEmptyContext"));
|
|
2833
2851
|
const XMLEvent = v.object({
|
|
2834
2852
|
dateTime: v.optional(customDateTime("XMLEvent: dateTime is not a valid datetime")),
|
|
2835
2853
|
endDateTime: v.optional(customDateTime("XMLEvent: endDateTime is not a valid datetime")),
|
|
@@ -3612,13 +3630,13 @@ async function fetchGallery(params, options) {
|
|
|
3612
3630
|
}),
|
|
3613
3631
|
headers: { "Content-Type": "application/xquery" }
|
|
3614
3632
|
});
|
|
3615
|
-
if (!response.ok) throw new Error("Error fetching gallery items, please try again later.");
|
|
3633
|
+
if (!response.ok) throw new Error("Error fetching gallery items, please try again later.", { cause: response.statusText });
|
|
3616
3634
|
const dataRaw = await response.text();
|
|
3617
3635
|
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
3618
3636
|
const { success, issues, output } = v.safeParse(XMLGalleryData, data);
|
|
3619
3637
|
if (!success) {
|
|
3620
3638
|
logIssues(issues);
|
|
3621
|
-
throw new Error("Failed to parse gallery XML");
|
|
3639
|
+
throw new Error("Failed to parse gallery XML", { cause: issues });
|
|
3622
3640
|
}
|
|
3623
3641
|
restoreXMLMetadata(output, data);
|
|
3624
3642
|
return {
|
|
@@ -3722,13 +3740,13 @@ async function fetchItemLinks(uuid, options) {
|
|
|
3722
3740
|
body: buildXQuery$2(parsedUuid),
|
|
3723
3741
|
headers: { "Content-Type": "application/xquery" }
|
|
3724
3742
|
});
|
|
3725
|
-
if (!response.ok) throw new Error("Failed to fetch OCHRE item links");
|
|
3743
|
+
if (!response.ok) throw new Error("Failed to fetch OCHRE item links", { cause: response.statusText });
|
|
3726
3744
|
const dataRaw = await response.text();
|
|
3727
3745
|
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
3728
3746
|
const { success, issues, output } = v.safeParse(XMLItemLinksData, data);
|
|
3729
3747
|
if (!success) {
|
|
3730
3748
|
logIssues(issues);
|
|
3731
|
-
throw new Error("Failed to parse OCHRE item links");
|
|
3749
|
+
throw new Error("Failed to parse OCHRE item links", { cause: issues });
|
|
3732
3750
|
}
|
|
3733
3751
|
restoreXMLMetadata(output, data);
|
|
3734
3752
|
const languages = resolveItemLinksLanguages(output, requestedLanguages);
|
|
@@ -3788,7 +3806,7 @@ function inferFetchItemCategory(rawOchre) {
|
|
|
3788
3806
|
if ("resource" in rawOchre) return "resource";
|
|
3789
3807
|
if ("text" in rawOchre) return "text";
|
|
3790
3808
|
if ("set" in rawOchre) return "set";
|
|
3791
|
-
throw new Error("Could not infer OCHRE item category");
|
|
3809
|
+
throw new Error("Could not infer OCHRE item category", { cause: rawOchre });
|
|
3792
3810
|
}
|
|
3793
3811
|
/**
|
|
3794
3812
|
* Validate language codes while preserving literal tuple inference.
|
|
@@ -3823,13 +3841,13 @@ async function fetchItem(uuid, options) {
|
|
|
3823
3841
|
assertItemCategoryAllowed(options?.category, options?.containedItemCategory);
|
|
3824
3842
|
const languages = options?.languages == null ? [] : parseLanguages$1(options.languages);
|
|
3825
3843
|
const response = await (options?.fetch ?? fetch)(`https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?uuid=${parsedUuid}&xsl=none&lang="*"`);
|
|
3826
|
-
if (!response.ok) throw new Error("Failed to fetch OCHRE data");
|
|
3844
|
+
if (!response.ok) throw new Error("Failed to fetch OCHRE data", { cause: response.statusText });
|
|
3827
3845
|
const dataRaw = await response.text();
|
|
3828
3846
|
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
3829
3847
|
const { success, issues, output } = v.safeParse(XMLData, data);
|
|
3830
3848
|
if (!success) {
|
|
3831
3849
|
logIssues(issues);
|
|
3832
|
-
throw new Error("Failed to parse OCHRE data");
|
|
3850
|
+
throw new Error("Failed to parse OCHRE data", { cause: issues });
|
|
3833
3851
|
}
|
|
3834
3852
|
restoreXMLMetadata(output, data);
|
|
3835
3853
|
const category = options?.category ?? inferFetchItemCategory(output.result.ochre);
|
|
@@ -4514,7 +4532,7 @@ function buildLeafQueryExpression(context, query) {
|
|
|
4514
4532
|
if (query.target === "property" && query.dataType !== "date" && query.dataType !== "dateTime" && !("value" in query) && query.propertyVariable != null) return buildPropertyPresenceQueryExpression({ propertyVariable: query.propertyVariable });
|
|
4515
4533
|
if (query.target === "property" && (query.dataType === "date" || query.dataType === "dateTime") && query.value == null) return buildPropertyDateRangeQueryExpression(query);
|
|
4516
4534
|
const searchValue = getLeafSearchValue(query);
|
|
4517
|
-
if (searchValue == null) throw new Error("Missing searchable value for query leaf");
|
|
4535
|
+
if (searchValue == null) throw new Error("Missing searchable value for query leaf", { cause: query });
|
|
4518
4536
|
const exactHelper = registerLeafHelper({
|
|
4519
4537
|
context,
|
|
4520
4538
|
query,
|
|
@@ -4589,9 +4607,9 @@ function getCompatibleIncludesGroupLeaves(query) {
|
|
|
4589
4607
|
}
|
|
4590
4608
|
function buildIncludesGroupQueryExpression(context, queries) {
|
|
4591
4609
|
const firstQuery = queries[0];
|
|
4592
|
-
if (firstQuery == null) throw new Error("Cannot build an includes group without queries");
|
|
4610
|
+
if (firstQuery == null) throw new Error("Cannot build an includes group without queries", { cause: queries });
|
|
4593
4611
|
const groupValue = getGroupableIncludesValue(firstQuery);
|
|
4594
|
-
if (groupValue == null) throw new Error("Cannot build an includes group without a search value");
|
|
4612
|
+
if (groupValue == null) throw new Error("Cannot build an includes group without a search value", { cause: firstQuery });
|
|
4595
4613
|
const terms = tokenizeIncludesSearchValue({
|
|
4596
4614
|
value: groupValue,
|
|
4597
4615
|
isCaseSensitive: firstQuery.isCaseSensitive
|
|
@@ -4897,18 +4915,18 @@ async function fetchSetItems(params, containedItemCategories, options) {
|
|
|
4897
4915
|
body: xquery,
|
|
4898
4916
|
headers: { "Content-Type": "application/xquery" }
|
|
4899
4917
|
});
|
|
4900
|
-
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}
|
|
4918
|
+
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`, { cause: response.statusText });
|
|
4901
4919
|
const dataRaw = await response.text();
|
|
4902
4920
|
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
4903
4921
|
const { success, issues, output } = v.safeParse(XMLSetItemsData, data);
|
|
4904
4922
|
if (!success) {
|
|
4905
4923
|
logIssues(issues);
|
|
4906
|
-
throw new Error("Failed to parse OCHRE Set items");
|
|
4924
|
+
throw new Error("Failed to parse OCHRE Set items", { cause: issues });
|
|
4907
4925
|
}
|
|
4908
4926
|
restoreXMLMetadata(output, data);
|
|
4909
4927
|
if (containedItemCategories != null) {
|
|
4910
4928
|
const missingCategories = containedItemCategories.filter((category) => !hasSetItemsCategory(output.result.ochre.items, category));
|
|
4911
|
-
if (missingCategories.length > 0) throw new Error(`No Set items found for item categories: ${missingCategories.join(", ")}
|
|
4929
|
+
if (missingCategories.length > 0) throw new Error(`No Set items found for item categories: ${missingCategories.join(", ")}`, { cause: missingCategories });
|
|
4912
4930
|
}
|
|
4913
4931
|
const languages = resolveSetItemsLanguages(output, requestedLanguages);
|
|
4914
4932
|
const items = parseSetItems(output.result.ochre.items, {
|
|
@@ -5374,13 +5392,13 @@ async function fetchSetPropertyValues(params, options) {
|
|
|
5374
5392
|
body: xquery,
|
|
5375
5393
|
headers: { "Content-Type": "application/xquery" }
|
|
5376
5394
|
});
|
|
5377
|
-
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}
|
|
5395
|
+
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`, { cause: response.statusText });
|
|
5378
5396
|
const dataRaw = await response.text();
|
|
5379
5397
|
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
5380
5398
|
const { success, issues, output } = v.safeParse(responseSchema, data);
|
|
5381
5399
|
if (!success) {
|
|
5382
5400
|
logIssues(issues);
|
|
5383
|
-
throw new Error("Failed to parse OCHRE Set property values");
|
|
5401
|
+
throw new Error("Failed to parse OCHRE Set property values", { cause: issues });
|
|
5384
5402
|
}
|
|
5385
5403
|
const parsedPropertyValues = [];
|
|
5386
5404
|
const parsedAttributeValues = [];
|
|
@@ -5794,7 +5812,7 @@ var WebsitePresentationReader = class WebsitePresentationReader {
|
|
|
5794
5812
|
}
|
|
5795
5813
|
requiredProperty(label, message) {
|
|
5796
5814
|
const property = this.property(label);
|
|
5797
|
-
if (property === null) throw new Error(message);
|
|
5815
|
+
if (property === null) throw new Error(message, { cause: this.sourceProperties });
|
|
5798
5816
|
return property;
|
|
5799
5817
|
}
|
|
5800
5818
|
propertyByValue(label, value) {
|
|
@@ -5941,10 +5959,23 @@ function parseResponsiveCssStyles(properties) {
|
|
|
5941
5959
|
* @returns Parsed bounds object
|
|
5942
5960
|
*/
|
|
5943
5961
|
function parseBounds(bounds) {
|
|
5944
|
-
const [southWest, northEast] = bounds.split(";").map((pair) => pair.split(",").map((coordinate) => Number.parseFloat(coordinate.trim())));
|
|
5945
|
-
if (southWest?.length !== 2 || northEast?.length !== 2 || southWest.some((coordinate) => Number.isNaN(coordinate)) || northEast.some((coordinate) => Number.isNaN(coordinate))) throw new Error(`Invalid bounds: ${bounds}
|
|
5962
|
+
const [southWest, northEast] = bounds.trim().startsWith("[") ? parseJsonBounds(bounds) : bounds.split(";").map((pair) => pair.split(",").map((coordinate) => Number.parseFloat(coordinate.trim())));
|
|
5963
|
+
if (southWest?.length !== 2 || northEast?.length !== 2 || southWest.some((coordinate) => Number.isNaN(coordinate)) || northEast.some((coordinate) => Number.isNaN(coordinate))) throw new Error(`Invalid bounds: ${bounds}`, { cause: bounds });
|
|
5946
5964
|
return [[southWest[0], southWest[1]], [northEast[0], northEast[1]]];
|
|
5947
5965
|
}
|
|
5966
|
+
function parseJsonBounds(bounds) {
|
|
5967
|
+
let parsed;
|
|
5968
|
+
try {
|
|
5969
|
+
parsed = JSON.parse(bounds);
|
|
5970
|
+
} catch {
|
|
5971
|
+
throw new Error(`Invalid bounds: ${bounds}`, { cause: bounds });
|
|
5972
|
+
}
|
|
5973
|
+
if (!isNumberPairArray(parsed)) throw new Error(`Invalid bounds: ${bounds}`, { cause: bounds });
|
|
5974
|
+
return parsed;
|
|
5975
|
+
}
|
|
5976
|
+
function isNumberPairArray(value) {
|
|
5977
|
+
return Array.isArray(value) && value.every((pair) => Array.isArray(pair) && pair.every((coordinate) => typeof coordinate === "number"));
|
|
5978
|
+
}
|
|
5948
5979
|
/**
|
|
5949
5980
|
* Parses all context option arrays from an options object.
|
|
5950
5981
|
*
|
|
@@ -6017,7 +6048,7 @@ function parseStylesheets(styles) {
|
|
|
6017
6048
|
mobile: []
|
|
6018
6049
|
};
|
|
6019
6050
|
if (style.category === "propertyValue" || style.valueUuid != null) {
|
|
6020
|
-
if (style.valueUuid == null) throw new Error(`Stylesheet property value "${style.variableUuid}" is missing a value UUID
|
|
6051
|
+
if (style.valueUuid == null) throw new Error(`Stylesheet property value "${style.variableUuid}" is missing a value UUID`, { cause: style });
|
|
6021
6052
|
parsedStyles.push({
|
|
6022
6053
|
uuid: style.valueUuid,
|
|
6023
6054
|
category: "propertyValue",
|
|
@@ -6053,7 +6084,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6053
6084
|
switch (componentName) {
|
|
6054
6085
|
case "3d-viewer": {
|
|
6055
6086
|
const resourceLink = findWebsiteLink(websiteLinks, "resource", (link) => link.fileFormat === "model/obj");
|
|
6056
|
-
if (resourceLink == null) throw new Error(formatComponentError("Resource link not found", componentName, elementResource));
|
|
6087
|
+
if (resourceLink == null) throw new Error(formatComponentError("Resource link not found", componentName, elementResource), { cause: componentProperty });
|
|
6057
6088
|
const isInteractive = componentReader.valueOr("is-interactive", true);
|
|
6058
6089
|
const isControlsDisplayed = componentReader.valueOr("controls-displayed", true);
|
|
6059
6090
|
properties = {
|
|
@@ -6068,7 +6099,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6068
6099
|
case "advanced-search": {
|
|
6069
6100
|
const boundElementPropertyUuid = componentReader.uuid("bound-element");
|
|
6070
6101
|
const href = componentReader.linkTarget("link-to", transformPermanentIdentificationUrlToItemLink);
|
|
6071
|
-
if (boundElementPropertyUuid == null && href == null) throw new Error(formatComponentError("Bound element or href not found", componentName, elementResource));
|
|
6102
|
+
if (boundElementPropertyUuid == null && href == null) throw new Error(formatComponentError("Bound element or href not found", componentName, elementResource), { cause: componentProperty });
|
|
6072
6103
|
properties = {
|
|
6073
6104
|
component: "advanced-search",
|
|
6074
6105
|
boundElementUuid: boundElementPropertyUuid,
|
|
@@ -6078,7 +6109,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6078
6109
|
}
|
|
6079
6110
|
case "annotated-document": {
|
|
6080
6111
|
const documentLink = findWebsiteLink(websiteLinks, "resource", (link) => link.type === "internalDocument");
|
|
6081
|
-
if (documentLink == null) throw new Error(formatComponentError("Document link not found", componentName, elementResource));
|
|
6112
|
+
if (documentLink == null) throw new Error(formatComponentError("Document link not found", componentName, elementResource), { cause: componentProperty });
|
|
6082
6113
|
properties = {
|
|
6083
6114
|
component: "annotated-document",
|
|
6084
6115
|
linkUuid: documentLink.uuid
|
|
@@ -6087,7 +6118,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6087
6118
|
}
|
|
6088
6119
|
case "annotated-image": {
|
|
6089
6120
|
const imageLinks = getWebsiteLinks(websiteLinks, "resource").filter((link) => link.type === "image" || link.type === "IIIF");
|
|
6090
|
-
if (imageLinks.length === 0) throw new Error(formatComponentError("Image link not found", componentName, elementResource));
|
|
6121
|
+
if (imageLinks.length === 0) throw new Error(formatComponentError("Image link not found", componentName, elementResource), { cause: componentProperty });
|
|
6091
6122
|
const isFilterInputDisplayed = componentReader.valueOr("filter-input-displayed", true);
|
|
6092
6123
|
const isOptionsDisplayed = componentReader.valueOr("options-displayed", true);
|
|
6093
6124
|
const isAnnotationHighlightsDisplayed = componentReader.valueOr("annotation-highlights-displayed", true);
|
|
@@ -6104,7 +6135,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6104
6135
|
}
|
|
6105
6136
|
case "audio-player": {
|
|
6106
6137
|
const audioLink = findWebsiteLink(websiteLinks, "resource", (link) => link.type === "audio");
|
|
6107
|
-
if (audioLink == null) throw new Error(formatComponentError("Audio link not found", componentName, elementResource));
|
|
6138
|
+
if (audioLink == null) throw new Error(formatComponentError("Audio link not found", componentName, elementResource), { cause: componentProperty });
|
|
6108
6139
|
const isSpeedControlsDisplayed = componentReader.valueOr("speed-controls-displayed", true);
|
|
6109
6140
|
const isVolumeControlsDisplayed = componentReader.valueOr("volume-controls-displayed", true);
|
|
6110
6141
|
const isSeekBarDisplayed = componentReader.valueOr("seek-bar-displayed", true);
|
|
@@ -6120,7 +6151,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6120
6151
|
case "bibliography": {
|
|
6121
6152
|
const itemLinks = websiteLinks.filter((link) => link.category !== "bibliography");
|
|
6122
6153
|
const bibliographies = parseBibliographyList(elementResource.bibliographies, options);
|
|
6123
|
-
if (itemLinks.length === 0 && bibliographies.length === 0) throw new Error(formatComponentError("No links found", componentName, elementResource));
|
|
6154
|
+
if (itemLinks.length === 0 && bibliographies.length === 0) throw new Error(formatComponentError("No links found", componentName, elementResource), { cause: componentProperty });
|
|
6124
6155
|
const layout = componentReader.valueOr("layout", "long");
|
|
6125
6156
|
const isSourceDocumentDisplayed = componentReader.valueOr("source-document-displayed", true);
|
|
6126
6157
|
properties = {
|
|
@@ -6138,7 +6169,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6138
6169
|
let href = componentReader.linkTarget("navigate-to", transformPermanentIdentificationUrlToItemLink);
|
|
6139
6170
|
if (href === null) {
|
|
6140
6171
|
href = componentReader.linkTarget("link-to", transformPermanentIdentificationUrlToItemLink);
|
|
6141
|
-
if (href === null) throw new Error(formatComponentError("Properties “navigate-to” or “link-to” not found", componentName, elementResource));
|
|
6172
|
+
if (href === null) throw new Error(formatComponentError("Properties “navigate-to” or “link-to” not found", componentName, elementResource), { cause: componentProperty });
|
|
6142
6173
|
else isExternal = true;
|
|
6143
6174
|
}
|
|
6144
6175
|
const startIcon = componentReader.value("start-icon");
|
|
@@ -6167,7 +6198,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6167
6198
|
}
|
|
6168
6199
|
case "collection": {
|
|
6169
6200
|
const setLinks = getWebsiteLinks(websiteLinks, "set");
|
|
6170
|
-
if (setLinks.length === 0) throw new Error(formatComponentError("Set links not found", componentName, elementResource));
|
|
6201
|
+
if (setLinks.length === 0) throw new Error(formatComponentError("Set links not found", componentName, elementResource), { cause: componentProperty });
|
|
6171
6202
|
const displayedProperties = componentReader.property("use-property");
|
|
6172
6203
|
const variant = componentReader.valueOr("variant", "slide");
|
|
6173
6204
|
const paginationVariant = componentReader.valueOr("pagination-variant", "default");
|
|
@@ -6216,7 +6247,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6216
6247
|
break;
|
|
6217
6248
|
case "entries": {
|
|
6218
6249
|
const entriesLink = findWebsiteLinkByCategories(websiteLinks, ["set", "tree"]);
|
|
6219
|
-
if (entriesLink == null) throw new Error(formatComponentError("Entries link not found", componentName, elementResource));
|
|
6250
|
+
if (entriesLink == null) throw new Error(formatComponentError("Entries link not found", componentName, elementResource), { cause: componentProperty });
|
|
6220
6251
|
const variant = componentReader.valueOr("variant", "entry");
|
|
6221
6252
|
const isFilterInputDisplayed = componentReader.valueOr("filter-input-displayed", false);
|
|
6222
6253
|
properties = {
|
|
@@ -6229,7 +6260,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6229
6260
|
}
|
|
6230
6261
|
case "iframe": {
|
|
6231
6262
|
const webpageLink = findWebsiteLink(websiteLinks, "resource", (link) => link.type === "webpage");
|
|
6232
|
-
if (webpageLink?.href == null) throw new Error(formatComponentError("URL not found", componentName, elementResource));
|
|
6263
|
+
if (webpageLink?.href == null) throw new Error(formatComponentError("URL not found", componentName, elementResource), { cause: componentProperty });
|
|
6233
6264
|
properties = {
|
|
6234
6265
|
component: "iframe",
|
|
6235
6266
|
href: transformPermanentIdentificationUrlToItemLink(webpageLink.href),
|
|
@@ -6240,7 +6271,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6240
6271
|
}
|
|
6241
6272
|
case "iiif-viewer": {
|
|
6242
6273
|
const manifestLink = findWebsiteLink(websiteLinks, "resource", (link) => link.type === "IIIF");
|
|
6243
|
-
if (manifestLink == null) throw new Error(formatComponentError("Manifest link not found", componentName, elementResource));
|
|
6274
|
+
if (manifestLink == null) throw new Error(formatComponentError("Manifest link not found", componentName, elementResource), { cause: componentProperty });
|
|
6244
6275
|
const variant = componentReader.valueOr("variant", "universal-viewer");
|
|
6245
6276
|
properties = {
|
|
6246
6277
|
component: "iiif-viewer",
|
|
@@ -6250,7 +6281,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6250
6281
|
break;
|
|
6251
6282
|
}
|
|
6252
6283
|
case "image": {
|
|
6253
|
-
if (websiteLinks.length === 0) throw new Error(formatComponentError("No links found", componentName, elementResource));
|
|
6284
|
+
if (websiteLinks.length === 0) throw new Error(formatComponentError("No links found", componentName, elementResource), { cause: componentProperty });
|
|
6254
6285
|
const imageQuality = componentReader.valueOr("image-quality", "high");
|
|
6255
6286
|
const images = [];
|
|
6256
6287
|
for (const link of websiteLinks) images.push({
|
|
@@ -6320,7 +6351,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6320
6351
|
}
|
|
6321
6352
|
case "image-gallery": {
|
|
6322
6353
|
const galleryLink = findWebsiteLinkByCategories(websiteLinks, ["set", "tree"]);
|
|
6323
|
-
if (galleryLink == null) throw new Error(formatComponentError("Image gallery link not found", componentName, elementResource));
|
|
6354
|
+
if (galleryLink == null) throw new Error(formatComponentError("Image gallery link not found", componentName, elementResource), { cause: componentProperty });
|
|
6324
6355
|
const isFilterInputDisplayed = componentReader.valueOr("filter-input-displayed", true);
|
|
6325
6356
|
properties = {
|
|
6326
6357
|
component: "image-gallery",
|
|
@@ -6331,7 +6362,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6331
6362
|
}
|
|
6332
6363
|
case "map": {
|
|
6333
6364
|
const mapLink = findWebsiteLinkByCategories(websiteLinks, ["set", "tree"]);
|
|
6334
|
-
if (mapLink == null) throw new Error(formatComponentError("Map link not found", componentName, elementResource));
|
|
6365
|
+
if (mapLink == null) throw new Error(formatComponentError("Map link not found", componentName, elementResource), { cause: componentProperty });
|
|
6335
6366
|
const isInteractive = componentReader.valueOr("is-interactive", true);
|
|
6336
6367
|
const isClustered = componentReader.valueOr("is-clustered", false);
|
|
6337
6368
|
const isUsingPins = componentReader.valueOr("is-using-pins", false);
|
|
@@ -6360,9 +6391,9 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6360
6391
|
}
|
|
6361
6392
|
case "query": {
|
|
6362
6393
|
const setLinks = getWebsiteLinks(websiteLinks, "set");
|
|
6363
|
-
if (setLinks.length === 0) throw new Error(formatComponentError("Set links not found", componentName, elementResource));
|
|
6394
|
+
if (setLinks.length === 0) throw new Error(formatComponentError("Set links not found", componentName, elementResource), { cause: componentProperty });
|
|
6364
6395
|
const items = [];
|
|
6365
|
-
if (componentProperty.properties.length === 0) throw new Error(formatComponentError("Query properties not found", componentName, elementResource));
|
|
6396
|
+
if (componentProperty.properties.length === 0) throw new Error(formatComponentError("Query properties not found", componentName, elementResource), { cause: componentProperty });
|
|
6366
6397
|
for (const queryItem of componentProperty.properties) {
|
|
6367
6398
|
const queryReader = websitePresentationReader(queryItem.properties);
|
|
6368
6399
|
const label = queryReader.multilingualValue("query-prompt", options);
|
|
@@ -6372,9 +6403,9 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6372
6403
|
if (queryLanguage == null) throw new Error(formatComponentError("Query language not found", componentName, elementResource));
|
|
6373
6404
|
const queries = [];
|
|
6374
6405
|
for (const propertyVariable of propertyVariables) {
|
|
6375
|
-
if (propertyVariable.uuid === null) throw new Error(formatComponentError("Property variable UUID not found", componentName, elementResource));
|
|
6406
|
+
if (propertyVariable.uuid === null) throw new Error(formatComponentError("Property variable UUID not found", componentName, elementResource), { cause: propertyVariable });
|
|
6376
6407
|
const dataType = propertyVariable.dataType;
|
|
6377
|
-
if (dataType === "coordinate") throw new Error(formatComponentError("Query prompts with data type \"coordinate\" are not supported", componentName, elementResource));
|
|
6408
|
+
if (dataType === "coordinate") throw new Error(formatComponentError("Query prompts with data type \"coordinate\" are not supported", componentName, elementResource), { cause: propertyVariable });
|
|
6378
6409
|
queries.push({
|
|
6379
6410
|
target: "property",
|
|
6380
6411
|
propertyVariable: propertyVariable.uuid,
|
|
@@ -6393,7 +6424,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6393
6424
|
endIcon
|
|
6394
6425
|
});
|
|
6395
6426
|
}
|
|
6396
|
-
if (items.length === 0) throw new Error(formatComponentError("No queries found", componentName, elementResource));
|
|
6427
|
+
if (items.length === 0) throw new Error(formatComponentError("No queries found", componentName, elementResource), { cause: componentProperty });
|
|
6397
6428
|
const componentOptions = parseWebsiteOptions(elementResource.options, options);
|
|
6398
6429
|
const displayedProperties = componentReader.property("use-property");
|
|
6399
6430
|
const variant = componentReader.valueOr("variant", "slide");
|
|
@@ -6420,7 +6451,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6420
6451
|
}
|
|
6421
6452
|
case "table": {
|
|
6422
6453
|
const tableLink = findWebsiteLink(websiteLinks, "set");
|
|
6423
|
-
if (tableLink == null) throw new Error(formatComponentError("Table link not found", componentName, elementResource));
|
|
6454
|
+
if (tableLink == null) throw new Error(formatComponentError("Table link not found", componentName, elementResource), { cause: componentProperty });
|
|
6424
6455
|
properties = {
|
|
6425
6456
|
component: "table",
|
|
6426
6457
|
linkUuid: tableLink.uuid
|
|
@@ -6431,7 +6462,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6431
6462
|
const queryVariant = componentReader.valueOr("query-variant", "submit");
|
|
6432
6463
|
const boundElementUuid = componentReader.uuid("bound-element");
|
|
6433
6464
|
const href = componentReader.linkTarget("link-to", transformPermanentIdentificationUrlToItemLink);
|
|
6434
|
-
if (!boundElementUuid && !href) throw new Error(formatComponentError("Bound element or href not found", componentName, elementResource));
|
|
6465
|
+
if (!boundElementUuid && !href) throw new Error(formatComponentError("Bound element or href not found", componentName, elementResource), { cause: componentProperty });
|
|
6435
6466
|
properties = {
|
|
6436
6467
|
component: "search-bar",
|
|
6437
6468
|
queryVariant,
|
|
@@ -6444,7 +6475,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6444
6475
|
}
|
|
6445
6476
|
case "text": {
|
|
6446
6477
|
const content = elementResource.document && "content" in elementResource.document ? parseXMLContent(elementResource.document, options) : null;
|
|
6447
|
-
if (content == null) throw new Error(formatComponentError("Content not found", componentName, elementResource));
|
|
6478
|
+
if (content == null) throw new Error(formatComponentError("Content not found", componentName, elementResource), { cause: componentProperty });
|
|
6448
6479
|
let variantName = "block";
|
|
6449
6480
|
let variant;
|
|
6450
6481
|
const variantProperty = componentReader.property("variant");
|
|
@@ -6490,7 +6521,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6490
6521
|
}
|
|
6491
6522
|
case "timeline": {
|
|
6492
6523
|
const timelineLink = findWebsiteLink(websiteLinks, "tree");
|
|
6493
|
-
if (timelineLink == null) throw new Error(formatComponentError("Timeline link not found", componentName, elementResource));
|
|
6524
|
+
if (timelineLink == null) throw new Error(formatComponentError("Timeline link not found", componentName, elementResource), { cause: componentProperty });
|
|
6494
6525
|
properties = {
|
|
6495
6526
|
component: "timeline",
|
|
6496
6527
|
linkUuid: timelineLink.uuid
|
|
@@ -6499,7 +6530,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6499
6530
|
}
|
|
6500
6531
|
case "video": {
|
|
6501
6532
|
const videoLink = findWebsiteLink(websiteLinks, "resource", (link) => link.type === "video");
|
|
6502
|
-
if (videoLink == null) throw new Error(formatComponentError("Video link not found", componentName, elementResource));
|
|
6533
|
+
if (videoLink == null) throw new Error(formatComponentError("Video link not found", componentName, elementResource), { cause: componentProperty });
|
|
6503
6534
|
const isChaptersDisplayed = componentReader.valueOr("chapters-displayed", true);
|
|
6504
6535
|
properties = {
|
|
6505
6536
|
component: "video",
|
|
@@ -6512,7 +6543,7 @@ function parseWebElementProperties(componentProperty, elementResource, options)
|
|
|
6512
6543
|
console.warn(`Invalid or non-implemented component name “${unparsedComponentName.toString()}” for the following element: “${parseStringContent(elementResource.identification.label, options)}”`);
|
|
6513
6544
|
break;
|
|
6514
6545
|
}
|
|
6515
|
-
if (properties === null) throw new Error(formatComponentError("Properties not found", componentName, elementResource));
|
|
6546
|
+
if (properties === null) throw new Error(formatComponentError("Properties not found", componentName, elementResource), { cause: componentProperty });
|
|
6516
6547
|
return properties;
|
|
6517
6548
|
}
|
|
6518
6549
|
function parseWebTitle(properties, identification, overrides) {
|
|
@@ -6573,7 +6604,7 @@ function parseWebpage(webpageResource, options, context, slugPrefix) {
|
|
|
6573
6604
|
if (webpageReader.value("presentation") !== "page") return null;
|
|
6574
6605
|
const identification = parseIdentification(webpageResource.identification, options);
|
|
6575
6606
|
const slug = webpageResource.slug?.replace(SEGMENT_UNIQUE_SLUG_PREFIX_REGEX, "") ?? null;
|
|
6576
|
-
if (slug == null) throw new Error(`Slug not found for page (${formatXMLWebsiteResourceMetadata(webpageResource)})
|
|
6607
|
+
if (slug == null) throw new Error(`Slug not found for page (${formatXMLWebsiteResourceMetadata(webpageResource)})`, { cause: webpageResource });
|
|
6577
6608
|
const returnWebpage = {
|
|
6578
6609
|
uuid: webpageResource.uuid,
|
|
6579
6610
|
type: "page",
|
|
@@ -6660,7 +6691,7 @@ function parseWebsiteSegments(resources, context, options, slugPrefix) {
|
|
|
6660
6691
|
if (!("segments" in resource)) continue;
|
|
6661
6692
|
for (const tree of resource.segments.tree) {
|
|
6662
6693
|
const segmentSlug = tree.identification.abbreviation == null ? null : parseStringContent(tree.identification.abbreviation, options);
|
|
6663
|
-
if (segmentSlug == null) throw new Error(`Slug not found for segment website (website uuid “${tree.uuid}”)
|
|
6694
|
+
if (segmentSlug == null) throw new Error(`Slug not found for segment website (website uuid “${tree.uuid}”)`, { cause: tree });
|
|
6664
6695
|
segments.push(parseWebsiteTree(tree, context, "segment", options, prefixSlug(segmentSlug, slugPrefix)));
|
|
6665
6696
|
}
|
|
6666
6697
|
}
|
|
@@ -6841,9 +6872,9 @@ function parseWebBlock(blockResource, options) {
|
|
|
6841
6872
|
for (const resource of blockResources) {
|
|
6842
6873
|
const resourceReader = websitePresentationReader(resource.properties ? parseSimplifiedProperties(resource.properties, options) : []);
|
|
6843
6874
|
const resourceType = resourceReader.value("presentation");
|
|
6844
|
-
if (resourceType !== "element") throw new Error(`Accordion only accepts elements, but got “${resourceType}” (${formatXMLWebsiteResourceMetadata(resource)})
|
|
6875
|
+
if (resourceType !== "element") throw new Error(`Accordion only accepts elements, but got “${resourceType}” (${formatXMLWebsiteResourceMetadata(resource)})`, { cause: resource });
|
|
6845
6876
|
const componentType = resourceReader.nestedByValue("presentation", "element").value("component");
|
|
6846
|
-
if (componentType !== "text") throw new Error(`Accordion only accepts text components, but got “${componentType}” (${formatXMLWebsiteResourceMetadata(resource)})
|
|
6877
|
+
if (componentType !== "text") throw new Error(`Accordion only accepts text components, but got “${componentType}” (${formatXMLWebsiteResourceMetadata(resource)})`, { cause: resource });
|
|
6847
6878
|
const element = parseWebElementForAccordion(resource, options);
|
|
6848
6879
|
accordionItems.push(element);
|
|
6849
6880
|
}
|
|
@@ -6937,7 +6968,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar, options) {
|
|
|
6937
6968
|
name: contactContent[0],
|
|
6938
6969
|
email: contactContent[1] ?? null
|
|
6939
6970
|
};
|
|
6940
|
-
else throw new Error(`Contact property must use “name;email”, got “${contactProperty.values[0]?.content}” (website uuid “${websiteTree.uuid}”)
|
|
6971
|
+
else throw new Error(`Contact property must use “name;email”, got “${contactProperty.values[0]?.content}” (website uuid “${websiteTree.uuid}”)`, { cause: websiteTree });
|
|
6941
6972
|
}
|
|
6942
6973
|
returnProperties.loadingVariant = websiteReader.valueOr("loading-variant", "spinner");
|
|
6943
6974
|
returnProperties.theme.isThemeToggleDisplayed = websiteReader.valueOr("supports-theme-toggle", true);
|
|
@@ -7043,8 +7074,8 @@ function parseFilterContexts(filterContextLevels, options) {
|
|
|
7043
7074
|
return filterContextTreeLevels;
|
|
7044
7075
|
}
|
|
7045
7076
|
function parseWebsiteTree(websiteTree, context, type, options, slugPrefix) {
|
|
7046
|
-
if (!websiteTree.properties) throw new Error(`Website properties not found (website uuid “${websiteTree.uuid}”)
|
|
7047
|
-
if (type === "website" && websiteTree.items?.resource == null) throw new Error(`Website pages not found (website uuid “${websiteTree.uuid}”)
|
|
7077
|
+
if (!websiteTree.properties) throw new Error(`Website properties not found (website uuid “${websiteTree.uuid}”)`, { cause: websiteTree });
|
|
7078
|
+
if (type === "website" && websiteTree.items?.resource == null) throw new Error(`Website pages not found (website uuid “${websiteTree.uuid}”)`, { cause: websiteTree });
|
|
7048
7079
|
const resources = normalizeWebsiteResources(websiteTree.items?.resource);
|
|
7049
7080
|
const sidebar = parseSidebar(resources, options);
|
|
7050
7081
|
const properties = parseWebsiteProperties(websiteTree.properties.property, websiteTree, sidebar, options);
|
|
@@ -7068,7 +7099,7 @@ function parseWebsite(data, options) {
|
|
|
7068
7099
|
const parserOptions = { languages };
|
|
7069
7100
|
const defaultLanguage = resolveDefaultLanguage(rawOchre, languages);
|
|
7070
7101
|
const websiteTree = rawOchre.tree[0];
|
|
7071
|
-
if (websiteTree == null) throw new Error("Website tree not found");
|
|
7102
|
+
if (websiteTree == null) throw new Error("Website tree not found", { cause: data });
|
|
7072
7103
|
return parseWebsiteTree(websiteTree, {
|
|
7073
7104
|
belongsTo: {
|
|
7074
7105
|
uuid: rawOchre.uuidBelongsTo,
|
|
@@ -7089,13 +7120,13 @@ async function fetchWebsite(abbreviation, options) {
|
|
|
7089
7120
|
try {
|
|
7090
7121
|
const cleanAbbreviation = abbreviation.trim().toLocaleLowerCase("en-US");
|
|
7091
7122
|
const response = await (options?.fetch ?? fetch)(`https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?xquery=${encodeURIComponent(`collection('ochre/tree')/ochre[tree/identification/abbreviation/content/string='${cleanAbbreviation}']`)}&xsl=none&lang="*"`);
|
|
7092
|
-
if (!response.ok) throw new Error("Failed to fetch website");
|
|
7123
|
+
if (!response.ok) throw new Error("Failed to fetch website", { cause: response.statusText });
|
|
7093
7124
|
const dataRaw = await response.text();
|
|
7094
7125
|
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
7095
7126
|
const { success, issues, output } = v.safeParse(XMLWebsiteData, data);
|
|
7096
7127
|
if (!success) {
|
|
7097
7128
|
logIssues(issues);
|
|
7098
|
-
throw new Error("Failed to parse website XML");
|
|
7129
|
+
throw new Error("Failed to parse website XML", { cause: issues });
|
|
7099
7130
|
}
|
|
7100
7131
|
restoreXMLMetadata(output, data);
|
|
7101
7132
|
return {
|