ochre-sdk 1.3.3 → 1.3.5

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.
@@ -48,8 +48,8 @@ function normalizePropertyValueDataType(dataType) {
48
48
  function sortPropertyValues(values) {
49
49
  return values.toSorted((a, b) => {
50
50
  if (a.count !== b.count) return b.count - a.count;
51
- const label = a.label?.getText() ?? null;
52
- const otherLabel = b.label?.getText() ?? null;
51
+ const label = a.label?.getText(a.label.getDefaultLanguage()) ?? null;
52
+ const otherLabel = b.label?.getText(b.label.getDefaultLanguage()) ?? null;
53
53
  if (label !== otherLabel) return label?.localeCompare(otherLabel ?? "") ?? 0;
54
54
  return a.content?.toString().localeCompare(b.content?.toString() ?? "") ?? 0;
55
55
  });
@@ -26,7 +26,7 @@ function parseWebsiteMetadata(data, options) {
26
26
  const websiteTree = rawOchre.tree[0];
27
27
  if (websiteTree == null) throw new Error("Website tree not found", { cause: data });
28
28
  const identification = parseIdentification(websiteTree.identification, options);
29
- const websiteName = identification.label.getText().trim();
29
+ const websiteName = identification.label.getText(identification.label.getDefaultLanguage()).trim();
30
30
  const metadataDescription = (parseStringLike(rawOchre.metadata.description) ?? "").trim();
31
31
  const properties = parseSimplifiedProperties(websiteTree.properties, options);
32
32
  const reader = websitePresentationReader(properties);
package/dist/getters.mjs CHANGED
@@ -27,7 +27,7 @@ function withDefaultOptions(options) {
27
27
  };
28
28
  }
29
29
  function getPropertyVariableLabel(property) {
30
- return typeof property.variable.label === "string" ? property.variable.label : property.variable.label.getText();
30
+ return typeof property.variable.label === "string" ? property.variable.label : property.variable.label.getText(property.variable.label.getDefaultLanguage());
31
31
  }
32
32
  function hasPropertyValue(property, value) {
33
33
  for (const candidateValue of property.values) if (deepEqual(candidateValue, value)) return true;
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { MultilingualOptions, MultilingualString, MultilingualStringEntries, MultilingualStringEntry, MultilingualStringInput, MultilingualStringJSON, MultilingualStringObject, MultilingualStringText } from "./parsers/multilingual.mjs";
2
- import { AccordionWebBlock, ContextTree, ContextTreeFilterLevel, ContextTreeFilterVariant, ContextTreeLevel, ContextTreeLevelItem, ProtectedWebsite, ResponsiveStyles, Scope, Style, StylesheetCategory, StylesheetItem, WebAccordionItem, WebBlock, WebBlockByLayout, WebBlockItem, WebBlockLayout, WebElement, WebElementComponent, WebElementComponentName, WebElementComponentOf, WebElementOf, WebIiifViewer, WebImage, WebLoadingVariant, WebOptions, WebSectionDisplay, WebSectionVariant, WebSidebar, WebTitle, Webpage, Website, WebsiteMetadata, WebsitePrivacy, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteSegment, WebsiteType } from "./types/website.mjs";
2
+ import { AccordionWebBlock, ContextTree, ContextTreeFilterLevel, ContextTreeFilterVariant, ContextTreeLevel, ContextTreeLevelItem, ProtectedWebsite, ResponsiveStyles, Scope, Style, StylesheetCategory, StylesheetItem, WebAccordionItem, WebBlock, WebBlockByLayout, WebBlockItem, WebBlockLayout, WebElement, WebElementComponent, WebElementComponentName, WebElementComponentOf, WebElementOf, WebIiifViewer, WebImage, WebLoadingVariant, WebOptions, WebRelationVariant, WebSectionDisplay, WebSectionVariant, WebSidebar, WebTitle, Webpage, Website, WebsiteMetadata, WebsitePrivacy, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteSegment, WebsiteType } from "./types/website.mjs";
3
3
  import { AnyBibliography, AnyConcept, AnyItem, AnyPeriod, AnyPerson, AnyPropertyValue, AnyPropertyVariable, AnyResource, AnySet, AnySpatialUnit, AnyText, AnyTree, BaseItem, BaseItemLink, BelongsTo, Bibliography, BibliographyEntryInfo, BibliographyItemLink, BibliographySourceDocument, Concept, ConceptItemLink, ContainedItemCategory, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Context, ContextItem, ContextItemCategory, ContextNode, Coordinates, CoordinatesSource, DictionaryUnitItemLink, EmbeddedBibliography, EmbeddedConcept, EmbeddedItem, EmbeddedPeriod, EmbeddedPerson, EmbeddedPropertyValue, EmbeddedPropertyVariable, EmbeddedResource, EmbeddedSet, EmbeddedSpatialUnit, EmbeddedText, EmbeddedTree, Event, Gallery, Heading, HeadingItemCategory, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemCategoryWithEmbeddedItems, ItemContainerCategory, ItemLink, ItemLinkCategory, ItemLinks, ItemPayloadKind, ItemProperty, ItemWithoutEmbeddedItems, LanguageCodes, License, Metadata, Note, Observation, OcrString, Period, PeriodItemLink, Person, PersonItemLink, Property, PropertyLike, PropertyRelation, PropertyValue, PropertyValueContent, PropertyValueDataType, PropertyValueItemLink, PropertyValueQueryItem, PropertyVariable, PropertyVariableItemLink, Query, QueryGroup, QueryLeaf, QueryablePropertyValueDataType, RecursiveItemCategory, Resource, ResourceItemLink, Section, Set, SetAttributeValueQueryItem, SetBibliography, SetConcept, SetItem, SetItemCategory, SetItemLink, SetItemLocation, SetItemProperty, SetItemSimplifiedProperty, SetItemsSort, SetItemsSortDirection, SetPeriod, SetResource, SetSpatialUnit, SetStyle, SetStyleProperty, SetTree, SimplifiedProperty, SpatialUnit, SpatialUnitItemLink, Text, TextItemLink, TopLevelItem, Tree, TreeItemCategory, TreeItemLink } from "./types/index.mjs";
4
4
  import { DEFAULT_PAGE_SIZE } from "./constants.mjs";
5
5
  import { fetchGallery } from "./fetchers/gallery.mjs";
@@ -16,4 +16,4 @@ import { fetchWebsite } from "./fetchers/website.mjs";
16
16
  import { PropertyOptions, PropertySelector, getLeafPropertyValues, getProperty, getPropertyValue, getPropertyValues, getUniqueProperties, getUniquePropertyVariableLabels, isPropertyMatchingFilter, normalizePropertyVariableLabel } from "./getters.mjs";
17
17
  import { flattenItemProperties } from "./helpers.mjs";
18
18
  import { defineLanguages } from "./parsers/languages.mjs";
19
- export { type AccordionWebBlock, type AnyBibliography, type AnyConcept, type AnyItem, type AnyPeriod, type AnyPerson, type AnyPropertyValue, type AnyPropertyVariable, type AnyResource, type AnySet, type AnySpatialUnit, type AnyText, type AnyTree, type BaseItem, type BaseItemLink, type BelongsTo, type Bibliography, type BibliographyEntryInfo, type BibliographyItemLink, type BibliographySourceDocument, type Concept, type ConceptItemLink, type ContainedItemCategory, type ContainedItemCategoryFromOption, type ContainedItemCategoryOption, type Context, type ContextItem, type ContextItemCategory, type ContextNode, type ContextTree, type ContextTreeFilterLevel, type ContextTreeFilterVariant, type ContextTreeLevel, type ContextTreeLevelItem, type Coordinates, type CoordinatesSource, DEFAULT_PAGE_SIZE, type DictionaryUnitItemLink, type EmbeddedBibliography, type EmbeddedConcept, type EmbeddedItem, type EmbeddedPeriod, type EmbeddedPerson, type EmbeddedPropertyValue, type EmbeddedPropertyVariable, type EmbeddedResource, type EmbeddedSet, type EmbeddedSpatialUnit, type EmbeddedText, type EmbeddedTree, type Event, type Gallery, type Heading, type HeadingItemCategory, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type Item, type ItemCategory, type ItemCategoryFromOption, type ItemCategoryOption, type ItemCategoryWithEmbeddedItems, type ItemContainerCategory, type ItemLink, type ItemLinkCategory, type ItemLinks, type ItemPayloadKind, type ItemProperty, type ItemWithoutEmbeddedItems, type LanguageCodes, type License, type Metadata, type MultilingualOptions, MultilingualString, type MultilingualStringEntries, type MultilingualStringEntry, type MultilingualStringInput, type MultilingualStringJSON, type MultilingualStringObject, type MultilingualStringText, type Note, type Observation, type OcrString, type Period, type PeriodItemLink, type Person, type PersonItemLink, type Property, type PropertyLike, type PropertyOptions, type PropertyRelation, type PropertySelector, type PropertyValue, type PropertyValueContent, type PropertyValueDataType, type PropertyValueItemLink, type PropertyValueQueryItem, type PropertyVariable, type PropertyVariableItemLink, type ProtectedWebsite, type Query, type QueryGroup, type QueryLeaf, type QueryablePropertyValueDataType, type RecursiveItemCategory, type Resource, type ResourceItemLink, type ResponsiveStyles, type Scope, type Section, type Set, type SetAttributeValueQueryItem, type SetBibliography, type SetConcept, type SetItem, type SetItemCategory, type SetItemLink, type SetItemLocation, type SetItemProperty, type SetItemSimplifiedProperty, type SetItemsSort, type SetItemsSortDirection, type SetPeriod, type SetResource, type SetSpatialUnit, type SetStyle, type SetStyleProperty, type SetTree, type SimplifiedProperty, type SpatialUnit, type SpatialUnitItemLink, type Style, type StylesheetCategory, type StylesheetItem, type Text, type TextItemLink, type TopLevelItem, type Tree, type TreeItemCategory, type TreeItemLink, type WebAccordionItem, type WebBlock, type WebBlockByLayout, type WebBlockItem, type WebBlockLayout, type WebElement, type WebElementComponent, type WebElementComponentName, type WebElementComponentOf, type WebElementOf, type WebIiifViewer, type WebImage, type WebLoadingVariant, type WebOptions, type WebSectionDisplay, type WebSectionVariant, type WebSidebar, type WebTitle, type Webpage, type Website, type WebsiteMetadata, type WebsitePrivacy, type WebsitePropertyQuery, type WebsitePropertyQueryNode, type WebsiteSegment, type WebsiteType, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchItemOcrData, fetchSetItemLocations, fetchSetItems, fetchSetPropertyValues, fetchTreeItems, fetchWebsite, fetchWebsiteMetadata, flattenItemProperties, getLeafPropertyValues, getProperty, getPropertyValue, getPropertyValues, getUniqueProperties, getUniquePropertyVariableLabels, isPropertyMatchingFilter, normalizePropertyVariableLabel };
19
+ export { type AccordionWebBlock, type AnyBibliography, type AnyConcept, type AnyItem, type AnyPeriod, type AnyPerson, type AnyPropertyValue, type AnyPropertyVariable, type AnyResource, type AnySet, type AnySpatialUnit, type AnyText, type AnyTree, type BaseItem, type BaseItemLink, type BelongsTo, type Bibliography, type BibliographyEntryInfo, type BibliographyItemLink, type BibliographySourceDocument, type Concept, type ConceptItemLink, type ContainedItemCategory, type ContainedItemCategoryFromOption, type ContainedItemCategoryOption, type Context, type ContextItem, type ContextItemCategory, type ContextNode, type ContextTree, type ContextTreeFilterLevel, type ContextTreeFilterVariant, type ContextTreeLevel, type ContextTreeLevelItem, type Coordinates, type CoordinatesSource, DEFAULT_PAGE_SIZE, type DictionaryUnitItemLink, type EmbeddedBibliography, type EmbeddedConcept, type EmbeddedItem, type EmbeddedPeriod, type EmbeddedPerson, type EmbeddedPropertyValue, type EmbeddedPropertyVariable, type EmbeddedResource, type EmbeddedSet, type EmbeddedSpatialUnit, type EmbeddedText, type EmbeddedTree, type Event, type Gallery, type Heading, type HeadingItemCategory, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type Item, type ItemCategory, type ItemCategoryFromOption, type ItemCategoryOption, type ItemCategoryWithEmbeddedItems, type ItemContainerCategory, type ItemLink, type ItemLinkCategory, type ItemLinks, type ItemPayloadKind, type ItemProperty, type ItemWithoutEmbeddedItems, type LanguageCodes, type License, type Metadata, type MultilingualOptions, MultilingualString, type MultilingualStringEntries, type MultilingualStringEntry, type MultilingualStringInput, type MultilingualStringJSON, type MultilingualStringObject, type MultilingualStringText, type Note, type Observation, type OcrString, type Period, type PeriodItemLink, type Person, type PersonItemLink, type Property, type PropertyLike, type PropertyOptions, type PropertyRelation, type PropertySelector, type PropertyValue, type PropertyValueContent, type PropertyValueDataType, type PropertyValueItemLink, type PropertyValueQueryItem, type PropertyVariable, type PropertyVariableItemLink, type ProtectedWebsite, type Query, type QueryGroup, type QueryLeaf, type QueryablePropertyValueDataType, type RecursiveItemCategory, type Resource, type ResourceItemLink, type ResponsiveStyles, type Scope, type Section, type Set, type SetAttributeValueQueryItem, type SetBibliography, type SetConcept, type SetItem, type SetItemCategory, type SetItemLink, type SetItemLocation, type SetItemProperty, type SetItemSimplifiedProperty, type SetItemsSort, type SetItemsSortDirection, type SetPeriod, type SetResource, type SetSpatialUnit, type SetStyle, type SetStyleProperty, type SetTree, type SimplifiedProperty, type SpatialUnit, type SpatialUnitItemLink, type Style, type StylesheetCategory, type StylesheetItem, type Text, type TextItemLink, type TopLevelItem, type Tree, type TreeItemCategory, type TreeItemLink, type WebAccordionItem, type WebBlock, type WebBlockByLayout, type WebBlockItem, type WebBlockLayout, type WebElement, type WebElementComponent, type WebElementComponentName, type WebElementComponentOf, type WebElementOf, type WebIiifViewer, type WebImage, type WebLoadingVariant, type WebOptions, type WebRelationVariant, type WebSectionDisplay, type WebSectionVariant, type WebSidebar, type WebTitle, type Webpage, type Website, type WebsiteMetadata, type WebsitePrivacy, type WebsitePropertyQuery, type WebsitePropertyQueryNode, type WebsiteSegment, type WebsiteType, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchItemOcrData, fetchSetItemLocations, fetchSetItems, fetchSetPropertyValues, fetchTreeItems, fetchWebsite, fetchWebsiteMetadata, flattenItemProperties, getLeafPropertyValues, getProperty, getPropertyValue, getPropertyValues, getUniqueProperties, getUniquePropertyVariableLabels, isPropertyMatchingFilter, normalizePropertyVariableLabel };
@@ -58,15 +58,19 @@ function parseRequiredContentLike(value, options) {
58
58
  return parseContentLike(value, options) ?? MultilingualString.empty(options.languages, { defaultLanguage: options.defaultLanguage });
59
59
  }
60
60
  function parseContentLikeText(value, options) {
61
- return parseContentLike(value, options)?.getText().trim() ?? "";
61
+ const content = parseContentLike(value, options);
62
+ return content?.getText(content.getDefaultLanguage()).trim() ?? "";
62
63
  }
63
64
  function parseStringContent(value, options = FALLBACK_PARSER_OPTIONS) {
64
65
  if (value == null) return "";
65
66
  if (typeof value === "string") return value;
66
- if (isXMLContent(value)) return parseXMLContent(value, {
67
- languages: options.languages,
68
- defaultLanguage: options.defaultLanguage
69
- }).getText();
67
+ if (isXMLContent(value)) {
68
+ const content = parseXMLContent(value, {
69
+ languages: options.languages,
70
+ defaultLanguage: options.defaultLanguage
71
+ });
72
+ return content.getText(content.getDefaultLanguage());
73
+ }
70
74
  return parseXMLString(value).text;
71
75
  }
72
76
  //#endregion
@@ -457,7 +457,7 @@ function parsePropertyDataType(dataType) {
457
457
  function parsePropertyValueContent(value, options) {
458
458
  const dataType = parsePropertyDataType(value.dataType);
459
459
  const rawLabel = value.content != null ? parseRequiredContentLike(value, options) : value.payload != null && value.payload !== "" ? multilingualFromText(value.payload, options) : null;
460
- const contentText = readPropertyValueText(value, () => rawLabel?.getText() ?? null);
460
+ const contentText = readPropertyValueText(value, () => rawLabel?.getText(rawLabel.getDefaultLanguage()) ?? null);
461
461
  const common = {
462
462
  hierarchy: {
463
463
  isLeaf: value.inherited == null || !value.inherited,
@@ -40,13 +40,11 @@ export declare function resolveContentLanguages(node: unknown, requestedLanguage
40
40
  * Read the languages a dataset declares in its metadata
41
41
  * @param rawOchre - The raw OCHRE payload root
42
42
  * @param rawOchre.metadata - The payload metadata declaring the languages
43
- * @param rawOchre.languages - The semicolon-separated fallback language list
44
43
  * @returns The declared languages, falling back to {@link DEFAULT_LANGUAGES}
45
44
  * @internal
46
45
  */
47
46
  export declare function parseMetadataLanguages(rawOchre: {
48
47
  metadata: XMLMetadata;
49
- languages?: string;
50
48
  }): Array<string>;
51
49
  /**
52
50
  * Reconcile requested languages against the ones a dataset declares
@@ -76,7 +76,6 @@ function resolveContentLanguages(node, requestedLanguages) {
76
76
  * Read the languages a dataset declares in its metadata
77
77
  * @param rawOchre - The raw OCHRE payload root
78
78
  * @param rawOchre.metadata - The payload metadata declaring the languages
79
- * @param rawOchre.languages - The semicolon-separated fallback language list
80
79
  * @returns The declared languages, falling back to {@link DEFAULT_LANGUAGES}
81
80
  * @internal
82
81
  */
@@ -87,10 +86,6 @@ function parseMetadataLanguages(rawOchre) {
87
86
  const parsedLanguage = parseStringLike(language);
88
87
  if (parsedLanguage != null) languages.push(parsedLanguage);
89
88
  }
90
- if (languages.length > 0) return languages;
91
- if (rawOchre.languages != null) {
92
- for (const language of rawOchre.languages.split(";")) if (language !== "") languages.push(language);
93
- }
94
89
  return languages.length > 0 ? languages : [...DEFAULT_LANGUAGES];
95
90
  }
96
91
  /**
@@ -109,11 +109,11 @@ export declare class MultilingualString<T extends ReadonlyArray<string> = Readon
109
109
  /**
110
110
  * Get text in a specific language, falling back when it has none
111
111
  */
112
- getText(language?: T[number]): string;
112
+ getText(language: T[number]): string;
113
113
  /**
114
114
  * Get rich text in a specific language, falling back when it has none
115
115
  */
116
- getRichText(language?: T[number]): string;
116
+ getRichText(language: T[number]): string;
117
117
  /**
118
118
  * Get text in a specific language, with no fallback
119
119
  */
@@ -133,16 +133,16 @@ export declare class MultilingualString<T extends ReadonlyArray<string> = Readon
133
133
  * can carry several entries for one language, and this returns all of them
134
134
  * rather than only the primary. Each entry carries both `text` and
135
135
  * `richText`, so a caller rendering a rich field reads them from here.
136
- * @param language - The language to read, or undefined for the default
136
+ * @param language - The language to read
137
137
  * @returns The entries, or an empty array when no language has any
138
138
  */
139
- getEntries(language?: T[number]): Array<MultilingualStringEntry>;
139
+ getEntries(language: T[number]): Array<MultilingualStringEntry>;
140
140
  /**
141
141
  * Get the text of every entry for a language, falling back when it has none
142
- * @param language - The language to read, or undefined for the default
142
+ * @param language - The language to read
143
143
  * @returns The texts, or an empty array when no language has any
144
144
  */
145
- getTexts(language?: T[number]): Array<string>;
145
+ getTexts(language: T[number]): Array<string>;
146
146
  /**
147
147
  * Get the text of every entry for a language, with no fallback
148
148
  * @param language - The language to read
@@ -259,10 +259,6 @@ export declare class MultilingualString<T extends ReadonlyArray<string> = Readon
259
259
  * @returns A new multilingual string
260
260
  */
261
261
  filterEntries(shouldKeep: (entry: MultilingualStringEntry, language: T[number]) => boolean): MultilingualString<T>;
262
- /**
263
- * Get the string representation, using the default language
264
- */
265
- toString(): string;
266
262
  /**
267
263
  * Get the JSON representation
268
264
  *
@@ -228,7 +228,7 @@ var MultilingualString = class MultilingualString {
228
228
  * can carry several entries for one language, and this returns all of them
229
229
  * rather than only the primary. Each entry carries both `text` and
230
230
  * `richText`, so a caller rendering a rich field reads them from here.
231
- * @param language - The language to read, or undefined for the default
231
+ * @param language - The language to read
232
232
  * @returns The entries, or an empty array when no language has any
233
233
  */
234
234
  getEntries(language) {
@@ -236,7 +236,7 @@ var MultilingualString = class MultilingualString {
236
236
  }
237
237
  /**
238
238
  * Get the text of every entry for a language, falling back when it has none
239
- * @param language - The language to read, or undefined for the default
239
+ * @param language - The language to read
240
240
  * @returns The texts, or an empty array when no language has any
241
241
  */
242
242
  getTexts(language) {
@@ -423,12 +423,6 @@ var MultilingualString = class MultilingualString {
423
423
  }, newAvailableLanguages);
424
424
  }
425
425
  /**
426
- * Get the string representation, using the default language
427
- */
428
- toString() {
429
- return this.getText();
430
- }
431
- /**
432
426
  * Get the JSON representation
433
427
  *
434
428
  * Carries `defaultLanguage`, because it is not derivable from the content:
@@ -85,6 +85,23 @@ function parseCollectionDisplayedProperties(reader) {
85
85
  label: value.label
86
86
  }]);
87
87
  }
88
+ /**
89
+ * Parses the "customize-special" "relations" properties, each pairing the
90
+ * property variables it links with "use-property" with a display "variant".
91
+ */
92
+ function parseCollectionRelations(reader) {
93
+ const relations = [];
94
+ const relationReaders = reader.nestedAllByValue("customize-special", "relations");
95
+ for (const relationReader of relationReaders) {
96
+ const variant = relationReader.value("variant");
97
+ const properties = parseCollectionDisplayedProperties(relationReader) ?? [];
98
+ for (const property of properties) relations.push({
99
+ ...property,
100
+ variant
101
+ });
102
+ }
103
+ return relations;
104
+ }
88
105
  const THREE_D_VIEWER_COMPONENT_DEFAULTS = {
89
106
  isInteractive: true,
90
107
  isControlsDisplayed: true
@@ -261,6 +278,7 @@ function parseCollectionComponent(parameters) {
261
278
  component: "collection",
262
279
  linkUuids: setLinks.map((link) => link.uuid),
263
280
  displayedProperties: parseCollectionDisplayedProperties(componentReader),
281
+ relations: parseCollectionRelations(componentReader),
264
282
  ...COLLECTION_PROPERTY_DEFAULTS,
265
283
  ...propertyOverrides,
266
284
  image: {
@@ -472,9 +490,12 @@ function parseQueryComponent(parameters) {
472
490
  }
473
491
  if (items.length === 0) throw new Error(formatComponentError("No queries found", "query", elementResource), { cause: componentProperty });
474
492
  const componentOptions = parseWebsiteOptions(elementResource.options, options);
475
- const collectionProperties = parseCollectionPropertyOverrides(componentReader.nestedByValue("sub-component-override", "collection"));
493
+ const overrideReader = componentReader.nestedByValue("sub-component-override", "collection");
494
+ const collectionProperties = parseCollectionPropertyOverrides(overrideReader);
476
495
  const displayedProperties = parseCollectionDisplayedProperties(componentReader);
477
496
  if (displayedProperties != null) collectionProperties.displayedProperties = displayedProperties;
497
+ const relations = parseCollectionRelations(overrideReader);
498
+ if (relations.length > 0) collectionProperties.relations = relations;
478
499
  return {
479
500
  component: "query",
480
501
  linkUuids: setLinks.map((link) => link.uuid),
@@ -104,7 +104,7 @@ function parseWebsiteOptions(rawOptions, options) {
104
104
  };
105
105
  const notes = parseNotes(rawOptions?.notes, options);
106
106
  for (const note of notes) {
107
- if (note.title?.getText() !== "Title label") continue;
107
+ if (note.title?.getText(note.title.getDefaultLanguage()) !== "Title label") continue;
108
108
  parsedOptions.labels.title = note.content;
109
109
  break;
110
110
  }
@@ -76,6 +76,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar, options, paren
76
76
  isPersistentIdentifierDisplayed: parent?.itemPage.isPersistentIdentifierDisplayed ?? true,
77
77
  iiifViewer: parent?.itemPage.iiifViewer ?? "universal-viewer"
78
78
  },
79
+ relations: { variant: parent?.relations.variant ?? "list" },
79
80
  options: {
80
81
  contextTree: parent?.options.contextTree ?? null,
81
82
  scopes: parent?.options.scopes ?? null,
@@ -117,7 +118,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar, options, paren
117
118
  websiteReader.readAllUuids(returnProperties.navbar, { searchBarBoundElementUuid: "bound-element-navbar-search-bar" });
118
119
  websiteReader.readAll(returnProperties.footer, { isDisplayed: "footer-displayed" });
119
120
  websiteReader.readAllUuids(returnProperties.footer, { logoUuid: "footer-logo" });
120
- const itemPageReader = websiteReader.nestedByValue("page-type", "item-page");
121
+ const itemPageReader = websiteReader.nestedByValue("customize-special", "item-page");
121
122
  if (itemPageReader.size > 0) {
122
123
  for (const [key, slug] of [
123
124
  ["description", "description"],
@@ -142,6 +143,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar, options, paren
142
143
  iiifViewer: "item-page-iiif-viewer"
143
144
  });
144
145
  }
146
+ websiteReader.nestedByValue("customize-special", "relations").readAll(returnProperties.relations, { variant: "variant" });
145
147
  if (websiteTree.options != null) {
146
148
  const parsedOptions = parseWebsiteOptions(websiteTree.options, options);
147
149
  returnProperties.options.scopes = (parsedOptions.scopes != null && parsedOptions.scopes.length > 0 ? parsedOptions : returnProperties.options).scopes;
@@ -70,6 +70,7 @@ export declare class WebsitePresentationReader<T extends LanguageCodes> {
70
70
  readAllUuids<O extends object>(target: O, labels: Partial<Record<UuidKeys<O>, string>>): void;
71
71
  nested(label: string): WebsitePresentationReader<T>;
72
72
  nestedByValue(label: string, value: WebsitePropertyContent<T>): WebsitePresentationReader<T>;
73
+ nestedAllByValue(label: string, value: WebsitePropertyContent<T>): Array<WebsitePresentationReader<T>>;
73
74
  get size(): number;
74
75
  }
75
76
  export declare function websitePresentationReader<T extends LanguageCodes>(properties: ReadonlyArray<SimplifiedProperty<T>>): WebsitePresentationReader<T>;
@@ -103,6 +103,14 @@ var WebsitePresentationReader = class WebsitePresentationReader {
103
103
  nestedByValue(label, value) {
104
104
  return new WebsitePresentationReader(this.propertyByValue(label, value)?.properties ?? []);
105
105
  }
106
+ nestedAllByValue(label, value) {
107
+ const readers = [];
108
+ for (const property of this.sourceProperties) if (getProperty([property], {
109
+ label,
110
+ valueContent: value
111
+ }) != null) readers.push(new WebsitePresentationReader(property.properties));
112
+ return readers;
113
+ }
106
114
  get size() {
107
115
  return this.sourceProperties.length;
108
116
  }
@@ -87,6 +87,10 @@ export type WebLoadingVariant = "spinner" | "skeleton" | "animation" | "none";
87
87
  * How an item page groups a repeated section
88
88
  */
89
89
  export type WebSectionVariant = "discrete" | "tabs-horizontal" | "tabs-vertical" | "tabular";
90
+ /**
91
+ * How a website displays an item's related items
92
+ */
93
+ export type WebRelationVariant = "list" | "dropdown-list" | "grid" | "gallery" | "inline";
90
94
  /**
91
95
  * The IIIF viewer a website renders images with
92
96
  */
@@ -206,6 +210,9 @@ export type Website<T extends LanguageCodes = LanguageCodes> = {
206
210
  isPersistentIdentifierDisplayed: boolean;
207
211
  iiifViewer: WebIiifViewer;
208
212
  };
213
+ relations: {
214
+ variant: WebRelationVariant;
215
+ };
209
216
  options: Prettify<WebOptions<T> & {
210
217
  stylesheets: {
211
218
  properties: Array<StylesheetItem>;
@@ -336,6 +343,11 @@ export type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
336
343
  uuid: string;
337
344
  label: MultilingualString<T> | null;
338
345
  }> | null;
346
+ relations: Array<{
347
+ uuid: string;
348
+ label: MultilingualString<T> | null;
349
+ variant: WebRelationVariant | null;
350
+ }>;
339
351
  variant: "slide" | "table" | "card" | "tile" | "showcase";
340
352
  paginationVariant: "default" | "numeric";
341
353
  loadingVariant: WebLoadingVariant;
@@ -5193,7 +5193,6 @@ export declare const XMLWebsiteData: v.ObjectSchema<{
5193
5193
  }, "XMLMetadata: item is object with identification, category, type, and maxLength">, undefined>;
5194
5194
  }, undefined>;
5195
5195
  readonly persistentUrl: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<"XMLWebsiteData: persistentUrl is string and optional">, v.UrlAction<string, "XMLWebsiteData: persistentUrl is not a valid URL">]>, undefined>;
5196
- readonly languages: v.OptionalSchema<v.StringSchema<"XMLWebsiteData: languages is string and optional">, undefined>;
5197
5196
  readonly tree: v.ArraySchema<v.LazySchema<v.ObjectSchema<{
5198
5197
  readonly type: v.OptionalSchema<v.StringSchema<"XMLWebsiteTree: type is string and optional">, undefined>;
5199
5198
  readonly date: v.OptionalSchema<v.UnionSchema<[v.GenericSchema<unknown, Date>, v.ObjectSchema<{
@@ -949,9 +949,8 @@ const XMLData = v.object({ result: v.object({ ochre: v.intersect([v.object({
949
949
  uuidBelongsTo: v.pipe(v.string("XMLData: uuidBelongsTo is string and required"), v.check(isPseudoUuid, "XMLData: uuidBelongsTo is not a valid pseudo-UUID")),
950
950
  publicationDateTime: customDateTime("XMLData: publicationDateTime is not a valid datetime"),
951
951
  metadata: XMLMetadata,
952
- persistentUrl: v.optional(v.pipe(v.string("XMLData: persistentUrl is string and optional"), v.url("XMLData: persistentUrl is not a valid URL"))),
953
- languages: v.optional(v.string("XMLData: languages is string and optional"))
954
- }, "XMLData: ochre is object with uuid, belongsTo, uuidBelongsTo, publicationDateTime, metadata, and languages"), XMLTopLevelDataItem]) }) }, "XMLData: Shape error");
952
+ persistentUrl: v.optional(v.pipe(v.string("XMLData: persistentUrl is string and optional"), v.url("XMLData: persistentUrl is not a valid URL")))
953
+ }, "XMLData: ochre is object with uuid, belongsTo, uuidBelongsTo, publicationDateTime, and metadata"), XMLTopLevelDataItem]) }) }, "XMLData: Shape error");
955
954
  const XMLWebsiteData = v.object({ result: v.object({ ochre: v.object({
956
955
  uuid: v.pipe(v.string("XMLWebsiteData: uuid is string and required"), v.check(isPseudoUuid, "XMLWebsiteData: uuid is not a valid pseudo-UUID")),
957
956
  belongsTo: v.string("XMLWebsiteData: belongsTo is string and required"),
@@ -959,7 +958,6 @@ const XMLWebsiteData = v.object({ result: v.object({ ochre: v.object({
959
958
  publicationDateTime: customDateTime("XMLWebsiteData: publicationDateTime is not a valid datetime"),
960
959
  metadata: XMLMetadata,
961
960
  persistentUrl: v.optional(v.pipe(v.string("XMLWebsiteData: persistentUrl is string and optional"), v.url("XMLWebsiteData: persistentUrl is not a valid URL"))),
962
- languages: v.optional(v.string("XMLWebsiteData: languages is string and optional")),
963
961
  tree: v.array(XMLWebsiteTree)
964
962
  }, "XMLWebsiteData: ochre is object with website tree") }, "XMLWebsiteData: result is object with ochre") }, "XMLWebsiteData: Shape error");
965
963
  //#endregion
@@ -919,7 +919,6 @@ export type XMLData = {
919
919
  publicationDateTime: Date;
920
920
  metadata: XMLMetadata;
921
921
  persistentUrl?: string;
922
- languages?: string;
923
922
  } & XMLDataItem;
924
923
  };
925
924
  };
@@ -932,7 +931,6 @@ export type XMLWebsiteData = {
932
931
  publicationDateTime: Date;
933
932
  metadata: XMLMetadata;
934
933
  persistentUrl?: string;
935
- languages?: string;
936
934
  tree: Array<XMLWebsiteTree>;
937
935
  };
938
936
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
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",
@@ -45,20 +45,20 @@
45
45
  "dist"
46
46
  ],
47
47
  "dependencies": {
48
- "fast-equals": "^6.0.4",
48
+ "fast-equals": "^6.1.0",
49
49
  "fast-xml-parser": "^5.11.2",
50
50
  "valibot": "^1.5.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@antfu/eslint-config": "^9.5.1",
54
- "@types/node": "^24.19.0",
54
+ "@types/node": "^24.19.1",
55
55
  "bumpp": "^12.3.0",
56
- "eslint": "^10.11.0",
56
+ "eslint": "^10.12.0",
57
57
  "eslint-plugin-erasable-syntax-only": "^0.7.2",
58
58
  "eslint-plugin-slop": "^0.1.3",
59
59
  "eslint-plugin-sonarjs": "^4.2.2",
60
- "knip": "^6.39.0",
61
- "oxfmt": "^0.71.0",
60
+ "knip": "^6.40.0",
61
+ "oxfmt": "^0.72.0",
62
62
  "tsdown": "^0.23.0",
63
63
  "typescript": "^6.0.3",
64
64
  "vitest": "^5.0.3"