ochre-sdk 0.22.20 → 0.22.22

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.d.mts CHANGED
@@ -1288,11 +1288,39 @@ declare function fetchGallery(params: {
1288
1288
  error: string;
1289
1289
  }>;
1290
1290
  //#endregion
1291
+ //#region src/utils/fetchers/item-links.d.ts
1292
+ /**
1293
+ * Fetches and parses an OCHRE item links from the OCHRE API
1294
+ *
1295
+ * @param uuid - The UUID of the OCHRE item to fetch
1296
+ * @param category - The category of the OCHRE item to fetch
1297
+ * @param itemCategories - The categories of the OCHRE linked items to fetch
1298
+ * @param options - The options for the fetch
1299
+ * @param options.fetch - The fetch function to use
1300
+ * @param options.version - The version of the OCHRE API to use
1301
+ * @returns Object containing the parsed OCHRE item links, or an error message if the fetch/parse fails
1302
+ */
1303
+ declare function fetchItemLinks<T extends DataCategory = DataCategory, U extends DataCategory | Array<DataCategory> = (T extends "tree" ? Exclude<DataCategory, "tree"> : T extends "set" ? Array<DataCategory> : never)>(uuid: string, category?: T, itemCategories?: U, options?: {
1304
+ fetch?: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response>;
1305
+ version?: ApiVersion;
1306
+ }): Promise<{
1307
+ error: null;
1308
+ items: Array<Item<T, U>>;
1309
+ } | {
1310
+ error: string;
1311
+ items: never;
1312
+ }>;
1313
+ //#endregion
1291
1314
  //#region src/utils/fetchers/item.d.ts
1292
1315
  /**
1293
1316
  * Fetches and parses an OCHRE item from the OCHRE API
1294
1317
  *
1295
1318
  * @param uuid - The UUID of the OCHRE item to fetch
1319
+ * @param category - The category of the OCHRE item to fetch
1320
+ * @param itemCategories - The categories of the OCHRE items to fetch
1321
+ * @param options - The options for the fetch
1322
+ * @param options.fetch - The fetch function to use
1323
+ * @param options.version - The version of the OCHRE API to use
1296
1324
  * @returns Object containing the parsed OCHRE item, or an error message if the fetch/parse fails
1297
1325
  */
1298
1326
  declare function fetchItem<T extends DataCategory = DataCategory, U extends DataCategory | Array<DataCategory> = (T extends "tree" ? Exclude<DataCategory, "tree"> : T extends "set" ? Array<DataCategory> : never)>(uuid: string, category?: T, itemCategories?: U, options?: {
@@ -1596,4 +1624,4 @@ declare const DEFAULT_PAGE_SIZE = 48;
1596
1624
  */
1597
1625
  declare function flattenItemProperties<T extends DataCategory = DataCategory, U extends DataCategory | Array<DataCategory> = (T extends "tree" ? Exclude<DataCategory, "tree"> : T extends "set" ? Array<DataCategory> : never)>(item: Item<T, U>): Item<T, U>;
1598
1626
  //#endregion
1599
- export { ApiVersion, Bibliography, Concept, Context, ContextItem, ContextNode, ContextTree, ContextTreeFilterLevel, ContextTreeLevel, ContextTreeLevelItem, Coordinate, DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, Data, DataCategory, Event, FileFormat, Gallery, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, License, Link, Metadata, Note, Observation, Period, Person, Property, PropertyValue, PropertyValueContent, PropertyValueContentType, PropertyValueQueryItem, PropertyVariable, Query, QueryGroup, QueryLeaf, Resource, Scope, Section, Set, SetAttributeValueQueryItem, SetItemsSort, SetItemsSortDirection, SpatialUnit, Style, StylesheetCategory, StylesheetItem, Text, Tree, WebBlock, WebBlockLayout, WebElement, WebElementComponent, WebImage, WebSegment, WebSegmentItem, WebTitle, Webpage, Website, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteType, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValueContent, getPropertyByLabelAndValueContents, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValueContentByLabel, getPropertyValueContentByUuid, getPropertyValueContentsByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
1627
+ export { ApiVersion, Bibliography, Concept, Context, ContextItem, ContextNode, ContextTree, ContextTreeFilterLevel, ContextTreeLevel, ContextTreeLevelItem, Coordinate, DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, Data, DataCategory, Event, FileFormat, Gallery, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, License, Link, Metadata, Note, Observation, Period, Person, Property, PropertyValue, PropertyValueContent, PropertyValueContentType, PropertyValueQueryItem, PropertyVariable, Query, QueryGroup, QueryLeaf, Resource, Scope, Section, Set, SetAttributeValueQueryItem, SetItemsSort, SetItemsSortDirection, SpatialUnit, Style, StylesheetCategory, StylesheetItem, Text, Tree, WebBlock, WebBlockLayout, WebElement, WebElementComponent, WebImage, WebSegment, WebSegmentItem, WebTitle, Webpage, Website, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteType, fetchGallery, fetchItem, fetchItemLinks, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValueContent, getPropertyByLabelAndValueContents, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValueContentByLabel, getPropertyValueContentByUuid, getPropertyValueContentsByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
package/dist/index.mjs CHANGED
@@ -2038,6 +2038,99 @@ async function fetchGallery(params, options) {
2038
2038
  }
2039
2039
  }
2040
2040
  //#endregion
2041
+ //#region src/utils/fetchers/item-links.ts
2042
+ /**
2043
+ * Build an XQuery string to fetch item links from the OCHRE API
2044
+ * @param params - The parameters for the fetch
2045
+ * @param params.uuid - The UUID of the OCHRE item to fetch
2046
+ * @returns An XQuery string
2047
+ */
2048
+ function buildXQuery$2(params) {
2049
+ const { uuid } = params;
2050
+ return `<ochre>{${`let $item-uuid := "${uuid}"
2051
+
2052
+ let $uuids :=
2053
+ distinct-values((
2054
+
2055
+ (: Direct links on most item categories :)
2056
+ fn:collection("ochre/resource")/ochre[@uuid = $item-uuid]/resource/links/*/@uuid/string(),
2057
+ fn:collection("ochre/bibliography")/ochre[@uuid = $item-uuid]/bibliography/links/*/@uuid/string(),
2058
+ fn:collection("ochre/period")/ochre[@uuid = $item-uuid]/period/links/*/@uuid/string(),
2059
+ fn:collection("ochre/person")/ochre[@uuid = $item-uuid]/person/links/*/@uuid/string(),
2060
+ fn:collection("ochre/propertyVariable")/ochre[@uuid = $item-uuid]/propertyVariable/links/*/@uuid/string(),
2061
+ fn:collection("ochre/propertyValue")/ochre[@uuid = $item-uuid]/propertyValue/links/*/@uuid/string(),
2062
+ fn:collection("ochre/text")/ochre[@uuid = $item-uuid]/text/links/*/@uuid/string(),
2063
+ fn:collection("ochre/tree")/ochre[@uuid = $item-uuid]/tree/links/*/@uuid/string(),
2064
+ fn:collection("ochre/set")/ochre[@uuid = $item-uuid]/set/links/*/@uuid/string(),
2065
+
2066
+ (: Special category structures :)
2067
+ fn:collection("ochre/spatialUnit")/ochre[@uuid = $item-uuid]/spatialUnit/observations/observation/links/*/@uuid/string(),
2068
+ fn:collection("ochre/concept")/ochre[@uuid = $item-uuid]/concept/interpretations/interpretation/links/*/@uuid/string()
2069
+ ))
2070
+
2071
+ return
2072
+ <items>{(
2073
+ fn:collection("ochre/resource")/ochre/resource[@uuid = $uuids],
2074
+ fn:collection("ochre/bibliography")/ochre/bibliography[@uuid = $uuids],
2075
+ fn:collection("ochre/period")/ochre/period[@uuid = $uuids],
2076
+ fn:collection("ochre/person")/ochre/person[@uuid = $uuids],
2077
+ fn:collection("ochre/propertyVariable")/ochre/propertyVariable[@uuid = $uuids],
2078
+ fn:collection("ochre/propertyValue")/ochre/propertyValue[@uuid = $uuids],
2079
+ fn:collection("ochre/text")/ochre/text[@uuid = $uuids],
2080
+ fn:collection("ochre/tree")/ochre/tree[@uuid = $uuids],
2081
+ fn:collection("ochre/set")/ochre/set[@uuid = $uuids],
2082
+ fn:collection("ochre/spatialUnit")/ochre/spatialUnit[@uuid = $uuids],
2083
+ fn:collection("ochre/concept")/ochre/concept[@uuid = $uuids]
2084
+ )}</items>`}}</ochre>`;
2085
+ }
2086
+ /**
2087
+ * Fetches and parses an OCHRE item links from the OCHRE API
2088
+ *
2089
+ * @param uuid - The UUID of the OCHRE item to fetch
2090
+ * @param category - The category of the OCHRE item to fetch
2091
+ * @param itemCategories - The categories of the OCHRE linked items to fetch
2092
+ * @param options - The options for the fetch
2093
+ * @param options.fetch - The fetch function to use
2094
+ * @param options.version - The version of the OCHRE API to use
2095
+ * @returns Object containing the parsed OCHRE item links, or an error message if the fetch/parse fails
2096
+ */
2097
+ async function fetchItemLinks(uuid, category, itemCategories, options) {
2098
+ try {
2099
+ if (options?.version != null && options.version !== 2) throw new Error("Set item queries only support API version 2");
2100
+ const xquery = buildXQuery$2({ uuid });
2101
+ const response = await (options?.fetch ?? fetch)("https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?xquery&format=json", {
2102
+ method: "POST",
2103
+ body: xquery,
2104
+ headers: { "Content-Type": "application/xquery" }
2105
+ });
2106
+ if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`);
2107
+ const data = await response.json();
2108
+ if (Array.isArray(data.result) || Object.keys(data.result).length === 0) throw new Error("Invalid OCHRE API response");
2109
+ const rawItems = data.result.ochre.items;
2110
+ const items = [];
2111
+ if (rawItems.resource != null) items.push(...parseResources(ensureArray(rawItems.resource)));
2112
+ if (rawItems.spatialUnit != null) items.push(...parseSpatialUnits(ensureArray(rawItems.spatialUnit)));
2113
+ if (rawItems.concept != null) items.push(...parseConcepts(ensureArray(rawItems.concept)));
2114
+ if (rawItems.period != null) items.push(...parsePeriods(ensureArray(rawItems.period)));
2115
+ if (rawItems.bibliography != null) items.push(...parseBibliographies(ensureArray(rawItems.bibliography)));
2116
+ if (rawItems.person != null) items.push(...parsePersons(ensureArray(rawItems.person)));
2117
+ if (rawItems.propertyVariable != null) items.push(...parsePropertyVariables(ensureArray(rawItems.propertyVariable)));
2118
+ if (rawItems.propertyValue != null) items.push(...parsePropertyValues(ensureArray(rawItems.propertyValue)));
2119
+ if (rawItems.text != null) items.push(...parseTexts(ensureArray(rawItems.text)));
2120
+ if (rawItems.set != null) for (const linkedSet of ensureArray(rawItems.set)) items.push(parseSet(linkedSet, itemCategories));
2121
+ if (rawItems.tree != null) for (const linkedTree of ensureArray(rawItems.tree)) items.push(parseTree(linkedTree, itemCategories));
2122
+ return {
2123
+ error: null,
2124
+ items
2125
+ };
2126
+ } catch (error) {
2127
+ return {
2128
+ error: error instanceof Error ? error.message : "Unknown error",
2129
+ items: void 0
2130
+ };
2131
+ }
2132
+ }
2133
+ //#endregion
2041
2134
  //#region src/utils/fetchers/uuid.ts
2042
2135
  /**
2043
2136
  * Fetches raw OCHRE data by UUID from the OCHRE API
@@ -2065,6 +2158,11 @@ async function fetchByUuid(uuid, options) {
2065
2158
  * Fetches and parses an OCHRE item from the OCHRE API
2066
2159
  *
2067
2160
  * @param uuid - The UUID of the OCHRE item to fetch
2161
+ * @param category - The category of the OCHRE item to fetch
2162
+ * @param itemCategories - The categories of the OCHRE items to fetch
2163
+ * @param options - The options for the fetch
2164
+ * @param options.fetch - The fetch function to use
2165
+ * @param options.version - The version of the OCHRE API to use
2068
2166
  * @returns Object containing the parsed OCHRE item, or an error message if the fetch/parse fails
2069
2167
  */
2070
2168
  async function fetchItem(uuid, category, itemCategories, options) {
@@ -4050,6 +4148,15 @@ function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
4050
4148
  //#region src/utils/parse/website.ts
4051
4149
  const SEGMENT_UNIQUE_SLUG_PREFIX_REGEX = /^\$[^-]*-/;
4052
4150
  const TRAILING_SLASH_REGEX = /\/$/;
4151
+ function formatRawResourceMetadata(resource) {
4152
+ const metadata = [`label “${parseStringContent(resource.identification.label)}”`, `uuid “${resource.uuid}”`];
4153
+ if (resource.slug != null) metadata.push(`slug “${resource.slug}”`);
4154
+ if (resource.identification.abbreviation != null) metadata.push(`abbreviation “${parseFakeStringOrContent(resource.identification.abbreviation)}”`);
4155
+ return metadata.join(", ");
4156
+ }
4157
+ function formatComponentError(message, componentName, elementResource) {
4158
+ return `${message} for component “${componentName ?? "(unknown)"}” (${formatRawResourceMetadata(elementResource)})`;
4159
+ }
4053
4160
  /**
4054
4161
  * Extracts CSS style properties for a given presentation variant.
4055
4162
  *
@@ -4173,7 +4280,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4173
4280
  switch (componentName) {
4174
4281
  case "3d-viewer": {
4175
4282
  const resourceLink = links.find((link) => link.category === "resource" && link.fileFormat === "model/obj");
4176
- if (resourceLink?.uuid == null) throw new Error(`Resource link not found for the following component: “${componentName}”`);
4283
+ if (resourceLink?.uuid == null) throw new Error(formatComponentError("Resource link not found", componentName, elementResource));
4177
4284
  let isInteractive = getPropertyValueContentByLabel(componentProperty.properties, "is-interactive");
4178
4285
  isInteractive ??= true;
4179
4286
  let isControlsDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "controls-displayed");
@@ -4191,7 +4298,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4191
4298
  const boundElementPropertyUuid = getPropertyByLabel(componentProperty.properties, "bound-element")?.values[0]?.uuid ?? null;
4192
4299
  const linkToProperty = getPropertyByLabel(componentProperty.properties, "link-to");
4193
4300
  const href = linkToProperty?.values[0]?.href != null ? transformPermanentIdentificationUrl(linkToProperty.values[0].href) : linkToProperty?.values[0]?.slug ?? null;
4194
- if (boundElementPropertyUuid == null && href == null) throw new Error(`Bound element or href not found for the following component: “${componentName}”`);
4301
+ if (boundElementPropertyUuid == null && href == null) throw new Error(formatComponentError("Bound element or href not found", componentName, elementResource));
4195
4302
  properties = {
4196
4303
  component: "advanced-search",
4197
4304
  boundElementUuid: boundElementPropertyUuid,
@@ -4201,7 +4308,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4201
4308
  }
4202
4309
  case "annotated-document": {
4203
4310
  const documentLink = links.find((link) => link.type === "internalDocument");
4204
- if (documentLink?.uuid == null) throw new Error(`Document link not found for the following component: “${componentName}”`);
4311
+ if (documentLink?.uuid == null) throw new Error(formatComponentError("Document link not found", componentName, elementResource));
4205
4312
  properties = {
4206
4313
  component: "annotated-document",
4207
4314
  linkUuid: documentLink.uuid
@@ -4210,7 +4317,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4210
4317
  }
4211
4318
  case "annotated-image": {
4212
4319
  const imageLinks = links.filter((link) => link.type === "image" || link.type === "IIIF");
4213
- if (imageLinks.length === 0 || imageLinks[0].uuid == null) throw new Error(`Image link not found for the following component: “${componentName}”`);
4320
+ if (imageLinks.length === 0 || imageLinks[0].uuid == null) throw new Error(formatComponentError("Image link not found", componentName, elementResource));
4214
4321
  let isFilterInputDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "filter-input-displayed");
4215
4322
  isFilterInputDisplayed ??= true;
4216
4323
  let isOptionsDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "options-displayed");
@@ -4231,7 +4338,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4231
4338
  }
4232
4339
  case "audio-player": {
4233
4340
  const audioLink = links.find((link) => link.type === "audio");
4234
- if (audioLink?.uuid == null) throw new Error(`Audio link not found for the following component: “${componentName}”`);
4341
+ if (audioLink?.uuid == null) throw new Error(formatComponentError("Audio link not found", componentName, elementResource));
4235
4342
  let isSpeedControlsDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "speed-controls-displayed");
4236
4343
  isSpeedControlsDisplayed ??= true;
4237
4344
  let isVolumeControlsDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "volume-controls-displayed");
@@ -4250,7 +4357,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4250
4357
  case "bibliography": {
4251
4358
  const itemLinks = links.filter((link) => link.category !== "bibliography");
4252
4359
  const bibliographyLink = links.find((link) => link.category === "bibliography");
4253
- if (itemLinks.length === 0 && bibliographyLink?.bibliographies == null) throw new Error(`No links found for the following component: “${componentName}”`);
4360
+ if (itemLinks.length === 0 && bibliographyLink?.bibliographies == null) throw new Error(formatComponentError("No links found", componentName, elementResource));
4254
4361
  let layout = getPropertyValueContentByLabel(componentProperty.properties, "layout");
4255
4362
  layout ??= "long";
4256
4363
  let isSourceDocumentDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "source-document-displayed");
@@ -4273,7 +4380,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4273
4380
  if (href === null) {
4274
4381
  const linkToProperty = getPropertyByLabel(componentProperty.properties, "link-to");
4275
4382
  href = linkToProperty?.values[0]?.href != null ? transformPermanentIdentificationUrl(linkToProperty.values[0].href) : linkToProperty?.values[0]?.slug ?? null;
4276
- if (href === null) throw new Error(`Properties “navigate-to” or “link-to” not found for the following component: “${componentName}”`);
4383
+ if (href === null) throw new Error(formatComponentError("Properties “navigate-to” or “link-to” not found", componentName, elementResource));
4277
4384
  else isExternal = true;
4278
4385
  }
4279
4386
  let startIcon = getPropertyValueContentByLabel(componentProperty.properties, "start-icon");
@@ -4304,7 +4411,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4304
4411
  }
4305
4412
  case "collection": {
4306
4413
  const setLinks = links.filter((link) => link.category === "set");
4307
- if (setLinks.every((link) => link.uuid === null)) throw new Error(`Set links not found for the following component: “${componentName}”`);
4414
+ if (setLinks.every((link) => link.uuid === null)) throw new Error(formatComponentError("Set links not found", componentName, elementResource));
4308
4415
  const displayedProperties = getPropertyByLabel(componentProperty.properties, "use-property");
4309
4416
  let variant = getPropertyValueContentByLabel(componentProperty.properties, "variant");
4310
4417
  variant ??= "slide";
@@ -4383,7 +4490,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4383
4490
  }
4384
4491
  case "entries": {
4385
4492
  const entriesLink = links.find((link) => link.category === "tree" || link.category === "set");
4386
- if (entriesLink?.uuid == null) throw new Error(`Entries link not found for the following component: “${componentName}”`);
4493
+ if (entriesLink?.uuid == null) throw new Error(formatComponentError("Entries link not found", componentName, elementResource));
4387
4494
  let variant = getPropertyValueContentByLabel(componentProperty.properties, "variant");
4388
4495
  variant ??= "entry";
4389
4496
  let isFilterInputDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "filter-input-displayed");
@@ -4398,7 +4505,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4398
4505
  }
4399
4506
  case "iframe": {
4400
4507
  const href = links.find((link) => link.type === "webpage")?.href;
4401
- if (!href) throw new Error(`URL not found for the following component: “${componentName}”`);
4508
+ if (!href) throw new Error(formatComponentError("URL not found", componentName, elementResource));
4402
4509
  const height = getPropertyValueContentByLabel(componentProperty.properties, "height");
4403
4510
  const width = getPropertyValueContentByLabel(componentProperty.properties, "width");
4404
4511
  properties = {
@@ -4411,7 +4518,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4411
4518
  }
4412
4519
  case "iiif-viewer": {
4413
4520
  const manifestLink = links.find((link) => link.type === "IIIF");
4414
- if (manifestLink?.uuid == null) throw new Error(`Manifest link not found for the following component: “${componentName}”`);
4521
+ if (manifestLink?.uuid == null) throw new Error(formatComponentError("Manifest link not found", componentName, elementResource));
4415
4522
  let variant = getPropertyValueContentByLabel(componentProperty.properties, "variant");
4416
4523
  variant ??= "universal-viewer";
4417
4524
  properties = {
@@ -4422,7 +4529,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4422
4529
  break;
4423
4530
  }
4424
4531
  case "image": {
4425
- if (links.length === 0) throw new Error(`No links found for the following component: “${componentName}”`);
4532
+ if (links.length === 0) throw new Error(formatComponentError("No links found", componentName, elementResource));
4426
4533
  let imageQuality = getPropertyValueContentByLabel(componentProperty.properties, "image-quality");
4427
4534
  imageQuality ??= "high";
4428
4535
  const images = [];
@@ -4510,7 +4617,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4510
4617
  }
4511
4618
  case "image-gallery": {
4512
4619
  const galleryLink = links.find((link) => link.category === "tree" || link.category === "set");
4513
- if (galleryLink?.uuid == null) throw new Error(`Image gallery link not found for the following component: “${componentName}”`);
4620
+ if (galleryLink?.uuid == null) throw new Error(formatComponentError("Image gallery link not found", componentName, elementResource));
4514
4621
  let isFilterInputDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "filter-input-displayed");
4515
4622
  isFilterInputDisplayed ??= true;
4516
4623
  properties = {
@@ -4522,7 +4629,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4522
4629
  }
4523
4630
  case "map": {
4524
4631
  const mapLink = links.find((link) => link.category === "set" || link.category === "tree");
4525
- if (mapLink?.uuid == null) throw new Error(`Map link not found for the following component: “${componentName}”`);
4632
+ if (mapLink?.uuid == null) throw new Error(formatComponentError("Map link not found", componentName, elementResource));
4526
4633
  let isInteractive = getPropertyValueContentByLabel(componentProperty.properties, "is-interactive");
4527
4634
  isInteractive ??= true;
4528
4635
  let isClustered = getPropertyValueContentByLabel(componentProperty.properties, "is-clustered");
@@ -4557,17 +4664,17 @@ function parseWebElementProperties(componentProperty, elementResource) {
4557
4664
  }
4558
4665
  case "query": {
4559
4666
  const setLinks = links.filter((link) => link.category === "set");
4560
- if (setLinks.every((link) => link.uuid === null)) throw new Error(`Set links not found for the following component: “${componentName}”`);
4667
+ if (setLinks.every((link) => link.uuid === null)) throw new Error(formatComponentError("Set links not found", componentName, elementResource));
4561
4668
  const items = [];
4562
- if (componentProperty.properties.length === 0) throw new Error(`Query properties not found for the following component: “${componentName}”`);
4669
+ if (componentProperty.properties.length === 0) throw new Error(formatComponentError("Query properties not found", componentName, elementResource));
4563
4670
  for (const queryItem of componentProperty.properties) {
4564
4671
  const querySubProperties = queryItem.properties;
4565
4672
  const label = getPropertyValueContentByLabel(querySubProperties, "query-prompt");
4566
4673
  if (label === null) continue;
4567
4674
  const queries = (getPropertyByLabel(querySubProperties, "use-property")?.values.filter((value) => value.uuid !== null) ?? []).map((propertyVariable) => {
4568
- if (propertyVariable.uuid === null) throw new Error(`Property variable UUID not found for the following component: “${componentName}”`);
4675
+ if (propertyVariable.uuid === null) throw new Error(formatComponentError("Property variable UUID not found", componentName, elementResource));
4569
4676
  const dataType = propertyVariable.dataType;
4570
- if (dataType === "coordinate") throw new Error(`Query prompts with data type "coordinate" are not supported for the following component: “${componentName}”`);
4677
+ if (dataType === "coordinate") throw new Error(formatComponentError("Query prompts with data type \"coordinate\" are not supported", componentName, elementResource));
4571
4678
  return {
4572
4679
  target: "property",
4573
4680
  propertyVariable: propertyVariable.uuid,
@@ -4588,7 +4695,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4588
4695
  endIcon
4589
4696
  });
4590
4697
  }
4591
- if (items.length === 0) throw new Error(`No queries found for the following component: “${componentName}”`);
4698
+ if (items.length === 0) throw new Error(formatComponentError("No queries found", componentName, elementResource));
4592
4699
  const options = {
4593
4700
  scopes: elementResource.options?.scopes != null ? ensureArray(elementResource.options.scopes.scope).map((scope) => ({
4594
4701
  uuid: scope.uuid.content,
@@ -4634,7 +4741,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4634
4741
  }
4635
4742
  case "table": {
4636
4743
  const tableLink = links.find((link) => link.category === "set");
4637
- if (tableLink?.uuid == null) throw new Error(`Table link not found for the following component: “${componentName}”`);
4744
+ if (tableLink?.uuid == null) throw new Error(formatComponentError("Table link not found", componentName, elementResource));
4638
4745
  properties = {
4639
4746
  component: "table",
4640
4747
  linkUuid: tableLink.uuid
@@ -4648,7 +4755,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4648
4755
  const boundElementUuid = getPropertyByLabel(componentProperty.properties, "bound-element")?.values[0]?.uuid ?? null;
4649
4756
  const linkToProperty = getPropertyByLabel(componentProperty.properties, "link-to");
4650
4757
  const href = linkToProperty?.values[0]?.href != null ? transformPermanentIdentificationUrl(linkToProperty.values[0].href) : linkToProperty?.values[0]?.slug ?? null;
4651
- if (!boundElementUuid && !href) throw new Error(`Bound element or href not found for the following component: “${componentName}”`);
4758
+ if (!boundElementUuid && !href) throw new Error(formatComponentError("Bound element or href not found", componentName, elementResource));
4652
4759
  let placeholder = getPropertyValueContentByLabel(componentProperty.properties, "placeholder-text");
4653
4760
  placeholder ??= null;
4654
4761
  let baseFilterQueries = getPropertyValueContentByLabel(componentProperty.properties, "base-filter-queries");
@@ -4665,7 +4772,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4665
4772
  }
4666
4773
  case "text": {
4667
4774
  const content = elementResource.document && "content" in elementResource.document ? parseDocument(elementResource.document.content) : null;
4668
- if (!content) throw new Error(`Content not found for the following component: “${componentName}”`);
4775
+ if (!content) throw new Error(formatComponentError("Content not found", componentName, elementResource));
4669
4776
  let variantName = "block";
4670
4777
  let variant;
4671
4778
  const variantProperty = getPropertyByLabel(componentProperty.properties, "variant");
@@ -4692,7 +4799,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4692
4799
  }
4693
4800
  case "timeline": {
4694
4801
  const timelineLink = links.find((link) => link.category === "tree");
4695
- if (timelineLink?.uuid == null) throw new Error(`Timeline link not found for the following component: “${componentName}”`);
4802
+ if (timelineLink?.uuid == null) throw new Error(formatComponentError("Timeline link not found", componentName, elementResource));
4696
4803
  properties = {
4697
4804
  component: "timeline",
4698
4805
  linkUuid: timelineLink.uuid
@@ -4701,7 +4808,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4701
4808
  }
4702
4809
  case "video": {
4703
4810
  const videoLink = links.find((link) => link.type === "video");
4704
- if (videoLink?.uuid == null) throw new Error(`Video link not found for the following component: “${componentName}”`);
4811
+ if (videoLink?.uuid == null) throw new Error(formatComponentError("Video link not found", componentName, elementResource));
4705
4812
  let isChaptersDisplayed = getPropertyValueContentByLabel(componentProperty.properties, "chapters-displayed");
4706
4813
  isChaptersDisplayed ??= true;
4707
4814
  properties = {
@@ -4715,7 +4822,7 @@ function parseWebElementProperties(componentProperty, elementResource) {
4715
4822
  console.warn(`Invalid or non-implemented component name “${unparsedComponentName?.toString() ?? "(unknown)"}” for the following element: “${parseStringContent(elementResource.identification.label)}”`);
4716
4823
  break;
4717
4824
  }
4718
- if (properties === null) throw new Error(`Properties not found for the following component: “${componentName}”`);
4825
+ if (properties === null) throw new Error(formatComponentError("Properties not found", componentName, elementResource));
4719
4826
  return properties;
4720
4827
  }
4721
4828
  function parseWebTitle(properties, identification, overrides) {
@@ -4751,9 +4858,9 @@ function parseWebElement(elementResource) {
4751
4858
  const identification = parseIdentification(elementResource.identification);
4752
4859
  const elementProperties = elementResource.properties?.property ? parseProperties(Array.isArray(elementResource.properties.property) ? elementResource.properties.property : [elementResource.properties.property]) : [];
4753
4860
  const presentationProperty = getPropertyByLabel(elementProperties, "presentation");
4754
- if (presentationProperty === null) throw new Error(`Presentation property not found for element “${identification.label}”`);
4861
+ if (presentationProperty === null) throw new Error(`Presentation property not found for element (${formatRawResourceMetadata(elementResource)})`);
4755
4862
  const componentProperty = getPropertyByLabel(presentationProperty.properties, "component");
4756
- if (componentProperty === null) throw new Error(`Component for element “${identification.label}” not found`);
4863
+ if (componentProperty === null) throw new Error(`Component property not found for element (${formatRawResourceMetadata(elementResource)})`);
4757
4864
  const properties = parseWebElementProperties(componentProperty, elementResource);
4758
4865
  const cssStyles = parseResponsiveCssStyles(elementProperties);
4759
4866
  const title = parseWebTitle(elementProperties, identification, {
@@ -4810,7 +4917,7 @@ function parseWebpage(webpageResource, slugPrefix) {
4810
4917
  if (webpageProperties.length === 0 || getPropertyValueContentByLabel(webpageProperties, "presentation") !== "page") return null;
4811
4918
  const identification = parseIdentification(webpageResource.identification);
4812
4919
  const slug = webpageResource.slug?.replace(SEGMENT_UNIQUE_SLUG_PREFIX_REGEX, "") ?? null;
4813
- if (slug == null) throw new Error(`Slug not found for page “${identification.label}”`);
4920
+ if (slug == null) throw new Error(`Slug not found for page (${formatRawResourceMetadata(webpageResource)})`);
4814
4921
  const returnWebpage = {
4815
4922
  uuid: webpageResource.uuid,
4816
4923
  type: "page",
@@ -4905,7 +5012,7 @@ function parseWebSegment(segmentResource, slugPrefix) {
4905
5012
  if (webpageProperties.length === 0 || getPropertyValueContentByLabel(webpageProperties, "presentation") !== "segment") return null;
4906
5013
  const identification = parseIdentification(segmentResource.identification);
4907
5014
  const slug = segmentResource.identification.abbreviation != null ? parseFakeStringOrContent(segmentResource.identification.abbreviation) : null;
4908
- if (slug == null) throw new Error(`Slug not found for segment “${identification.label}”`);
5015
+ if (slug == null) throw new Error(`Slug not found for segment (${formatRawResourceMetadata(segmentResource)})`);
4909
5016
  const returnSegment = {
4910
5017
  uuid: segmentResource.uuid,
4911
5018
  type: "segment",
@@ -4942,7 +5049,7 @@ function parseWebSegmentItem(segmentItemResource, slugPrefix) {
4942
5049
  if (webpageProperties.length === 0 || getPropertyValueContentByLabel(webpageProperties, "presentation") !== "segment-item") return null;
4943
5050
  const identification = parseIdentification(segmentItemResource.identification);
4944
5051
  const slug = segmentItemResource.identification.abbreviation != null ? parseFakeStringOrContent(segmentItemResource.identification.abbreviation) : null;
4945
- if (slug == null) throw new Error(`Slug not found for segment item “${identification.label}”`);
5052
+ if (slug == null) throw new Error(`Slug not found for segment item (${formatRawResourceMetadata(segmentItemResource)})`);
4946
5053
  const returnSegmentItem = {
4947
5054
  uuid: segmentItemResource.uuid,
4948
5055
  type: "segment-item",
@@ -5168,9 +5275,9 @@ function parseWebBlock(blockResource) {
5168
5275
  for (const resource of blockResources) {
5169
5276
  const resourceProperties = resource.properties ? parseProperties(ensureArray(resource.properties.property)) : [];
5170
5277
  const resourceType = getPropertyValueContentByLabel(resourceProperties, "presentation");
5171
- if (resourceType !== "element") throw new Error(`Accordion only accepts elements, but got “${resourceType}” for the following resource: “${parseStringContent(resource.identification.label)}”`);
5278
+ if (resourceType !== "element") throw new Error(`Accordion only accepts elements, but got “${resourceType}” (${formatRawResourceMetadata(resource)})`);
5172
5279
  const componentType = getPropertyValueContentByLabel(getPropertyByLabel(resourceProperties, "presentation")?.properties ?? [], "component");
5173
- if (componentType !== "text") throw new Error(`Accordion only accepts text components, but got “${componentType}” for the following resource: “${parseStringContent(resource.identification.label)}”`);
5280
+ if (componentType !== "text") throw new Error(`Accordion only accepts text components, but got “${componentType}” (${formatRawResourceMetadata(resource)})`);
5174
5281
  const element = parseWebElementForAccordion(resource);
5175
5282
  accordionItems.push(element);
5176
5283
  }
@@ -5269,7 +5376,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar) {
5269
5376
  name: contactContent[0],
5270
5377
  email: contactContent[1] ?? null
5271
5378
  };
5272
- else throw new Error(`Contact property must be in the format “name;email”, but got “${contactProperty.values[0]?.content}”`);
5379
+ else throw new Error(`Contact property must use “name;email”, got “${contactProperty.values[0]?.content}” (website uuid “${websiteTree.uuid}”)`);
5273
5380
  }
5274
5381
  returnProperties.loadingVariant = getPropertyValueContentByLabel(websiteProperties, "loading-variant") ?? "spinner";
5275
5382
  returnProperties.theme.isThemeToggleDisplayed = getPropertyValueContentByLabel(websiteProperties, "supports-theme-toggle") ?? true;
@@ -5389,8 +5496,8 @@ function parseFilterContexts(filterContextLevels) {
5389
5496
  return filterContextTreeLevels;
5390
5497
  }
5391
5498
  function parseWebsite(websiteTree, metadata, belongsTo, { version = 2 } = {}) {
5392
- if (!websiteTree.properties) throw new Error("Website properties not found");
5393
- if (typeof websiteTree.items === "string" || !("resource" in websiteTree.items)) throw new Error("Website pages not found");
5499
+ if (!websiteTree.properties) throw new Error(`Website properties not found (website uuid “${websiteTree.uuid}”)`);
5500
+ if (typeof websiteTree.items === "string" || !("resource" in websiteTree.items)) throw new Error(`Website pages not found (website uuid “${websiteTree.uuid}”)`);
5394
5501
  const resources = ensureArray(websiteTree.items.resource);
5395
5502
  const items = [...parseWebpages(resources), ...parseSegments(resources)];
5396
5503
  const sidebar = parseSidebar(resources);
@@ -5481,4 +5588,4 @@ async function fetchWebsite(abbreviation, options) {
5481
5588
  }
5482
5589
  }
5483
5590
  //#endregion
5484
- export { DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValueContent, getPropertyByLabelAndValueContents, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValueContentByLabel, getPropertyValueContentByUuid, getPropertyValueContentsByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
5591
+ export { DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, fetchGallery, fetchItem, fetchItemLinks, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValueContent, getPropertyByLabelAndValueContents, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValueContentByLabel, getPropertyValueContentByUuid, getPropertyValueContentsByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "0.22.20",
3
+ "version": "0.22.22",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Node.js library for working with OCHRE (Online Cultural and Historical Research Environment) data",