ochre-sdk 1.0.52 → 1.0.54

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.
@@ -13,7 +13,8 @@ function normalizeInputText(text) {
13
13
  }
14
14
  function normalizeAliases(aliases) {
15
15
  const normalizedAliases = [];
16
- for (const alias of aliases ?? []) if (alias !== "") normalizedAliases.push(alias);
16
+ const candidateAliases = aliases ?? [];
17
+ for (const alias of candidateAliases) if (alias !== "") normalizedAliases.push(alias);
17
18
  return normalizedAliases;
18
19
  }
19
20
  function entriesFromTexts(texts) {
@@ -27,15 +28,11 @@ function entriesFromTexts(texts) {
27
28
  function cloneContent(content) {
28
29
  const clonedContent = {};
29
30
  const entriesByLanguage = Object.entries(content);
30
- for (const [language, entries] of entriesByLanguage) {
31
- const clonedEntries = [];
32
- for (const entry of entries ?? []) clonedEntries.push({
33
- text: entry.text,
34
- richText: entry.richText,
35
- isPrimary: entry.isPrimary
36
- });
37
- clonedContent[language] = normalizePrimary(clonedEntries);
38
- }
31
+ for (const [language, entries] of entriesByLanguage) clonedContent[language] = normalizePrimary(Array.from(entries ?? [], (entry) => ({
32
+ text: entry.text,
33
+ richText: entry.richText,
34
+ isPrimary: entry.isPrimary
35
+ })));
39
36
  return clonedContent;
40
37
  }
41
38
  function normalizePrimary(entries) {
@@ -54,35 +51,18 @@ function getLanguagesWithEntries(content, languages) {
54
51
  }
55
52
  function getImplicitLanguages(content, options) {
56
53
  const languages = [];
57
- for (const language of options.availableLanguages ?? []) if (!languages.includes(language)) languages.push(language);
54
+ const availableLanguages = options.availableLanguages ?? [];
55
+ for (const language of availableLanguages) if (!languages.includes(language)) languages.push(language);
58
56
  for (const language of Object.keys(content)) if (!languages.includes(language)) languages.push(language);
59
57
  return languages.length > 0 ? languages : [...DEFAULT_LANGUAGES];
60
58
  }
61
59
  function isInternalInit(value) {
62
- return typeof value === "object" && value != null && MULTILINGUAL_STRING_INTERNAL_INIT in value;
60
+ return typeof value === "object" && value != null && Object.hasOwn(value, MULTILINGUAL_STRING_INTERNAL_INIT);
63
61
  }
64
62
  /**
65
63
  * Multilingual string
66
64
  */
67
65
  var MultilingualString = class MultilingualString {
68
- _content;
69
- _options;
70
- _availableLanguages;
71
- _aliases;
72
- constructor(content = {}, languages, options = {}) {
73
- if (isInternalInit(content)) {
74
- this._content = Object.freeze(cloneContent(content.content));
75
- this._options = Object.freeze({ ...content.options });
76
- this._availableLanguages = Object.freeze([...content.availableLanguages]);
77
- this._aliases = Object.freeze([...content.options.aliases]);
78
- return;
79
- }
80
- const parsed = languages === void 0 ? MultilingualString.fromObject(content, void 0, options) : MultilingualString.fromObject(content, languages, options);
81
- this._content = parsed._content;
82
- this._options = parsed._options;
83
- this._availableLanguages = parsed._availableLanguages;
84
- this._aliases = parsed._aliases;
85
- }
86
66
  static fromNormalized(content, options, availableLanguages) {
87
67
  return new MultilingualString({
88
68
  [MULTILINGUAL_STRING_INTERNAL_INIT]: true,
@@ -94,8 +74,8 @@ var MultilingualString = class MultilingualString {
94
74
  static fromObject(content, languages, options = {}) {
95
75
  const entries = {};
96
76
  for (const [language, text] of Object.entries(content)) if (text != null) entries[language] = [text];
97
- if (languages === void 0) return MultilingualString.fromEntries(entries, void 0, options);
98
- return MultilingualString.fromEntries(entries, languages, options);
77
+ if (languages === void 0) return this.fromEntries(entries, void 0, options);
78
+ return this.fromEntries(entries, languages, options);
99
79
  }
100
80
  static fromEntries(content, languages, options = {}) {
101
81
  if (languages === void 0) {
@@ -108,7 +88,7 @@ var MultilingualString = class MultilingualString {
108
88
  availableLanguages: actualLanguages,
109
89
  aliases: normalizeAliases(options.aliases)
110
90
  };
111
- return MultilingualString.fromNormalized(normalizedContent, defaultOptions, availableLanguages);
91
+ return this.fromNormalized(normalizedContent, defaultOptions, availableLanguages);
112
92
  }
113
93
  const normalizedContent = {};
114
94
  for (const language of languages) {
@@ -121,21 +101,21 @@ var MultilingualString = class MultilingualString {
121
101
  availableLanguages: languages,
122
102
  aliases: normalizeAliases(options.aliases)
123
103
  };
124
- return MultilingualString.fromNormalized(normalizedContent, defaultOptions, availableLanguages);
104
+ return this.fromNormalized(normalizedContent, defaultOptions, availableLanguages);
125
105
  }
126
106
  static create(language, text, languages, options = {}) {
127
- if (languages === void 0) return MultilingualString.fromObject({ [language]: text }, void 0, {
107
+ if (languages === void 0) return this.fromObject({ [language]: text }, void 0, {
128
108
  ...options,
129
109
  defaultLanguage: language
130
110
  });
131
- return MultilingualString.fromObject({ [language]: text }, languages, {
111
+ return this.fromObject({ [language]: text }, languages, {
132
112
  ...options,
133
113
  defaultLanguage: language
134
114
  });
135
115
  }
136
116
  static empty(languages, options = {}) {
137
- if (languages === void 0) return MultilingualString.fromObject({}, void 0, options);
138
- return MultilingualString.fromObject({}, languages, options);
117
+ if (languages === void 0) return this.fromObject({}, void 0, options);
118
+ return this.fromObject({}, languages, options);
139
119
  }
140
120
  static fromJSON(json, languages, options = {}) {
141
121
  const content = json.content;
@@ -143,8 +123,26 @@ var MultilingualString = class MultilingualString {
143
123
  ...options,
144
124
  aliases: json.aliases
145
125
  };
146
- if (languages === void 0) return MultilingualString.fromEntries(content, void 0, mergedOptions);
147
- return MultilingualString.fromEntries(content, languages, mergedOptions);
126
+ if (languages === void 0) return this.fromEntries(content, void 0, mergedOptions);
127
+ return this.fromEntries(content, languages, mergedOptions);
128
+ }
129
+ _content;
130
+ _options;
131
+ _availableLanguages;
132
+ _aliases;
133
+ constructor(content = {}, languages, options = {}) {
134
+ if (isInternalInit(content)) {
135
+ this._content = Object.freeze(cloneContent(content.content));
136
+ this._options = Object.freeze({ ...content.options });
137
+ this._availableLanguages = Object.freeze([...content.availableLanguages]);
138
+ this._aliases = Object.freeze([...content.options.aliases]);
139
+ return;
140
+ }
141
+ const parsed = languages === void 0 ? MultilingualString.fromObject(content, void 0, options) : MultilingualString.fromObject(content, languages, options);
142
+ this._content = parsed._content;
143
+ this._options = parsed._options;
144
+ this._availableLanguages = parsed._availableLanguages;
145
+ this._aliases = parsed._aliases;
148
146
  }
149
147
  getPrimaryEntry(language) {
150
148
  const entries = this._content[language] ?? [];
@@ -207,17 +205,13 @@ var MultilingualString = class MultilingualString {
207
205
  * Get all text entries in a specific language without fallback
208
206
  */
209
207
  getExactTexts(language) {
210
- const texts = [];
211
- for (const entry of this._content[language] ?? []) texts.push(entry.text);
212
- return texts;
208
+ return Array.from(this._content[language] ?? [], (entry) => entry.text);
213
209
  }
214
210
  /**
215
211
  * Get all rich text entries in a specific language without fallback
216
212
  */
217
213
  getExactRichTexts(language) {
218
- const texts = [];
219
- for (const entry of this._content[language] ?? []) texts.push(entry.richText);
220
- return texts;
214
+ return Array.from(this._content[language] ?? [], (entry) => entry.richText);
221
215
  }
222
216
  /**
223
217
  * Get all text entries in a specific language with fallback
@@ -243,13 +237,11 @@ var MultilingualString = class MultilingualString {
243
237
  * Get all entries in a specific language without fallback
244
238
  */
245
239
  getExactEntries(language) {
246
- const entries = [];
247
- for (const entry of this._content[language] ?? []) entries.push({
240
+ return Array.from(this._content[language] ?? [], (entry) => ({
248
241
  text: entry.text,
249
242
  richText: entry.richText,
250
243
  isPrimary: entry.isPrimary
251
- });
252
- return entries;
244
+ }));
253
245
  }
254
246
  /**
255
247
  * Get all entries in a specific language with fallback
@@ -301,7 +293,10 @@ var MultilingualString = class MultilingualString {
301
293
  * Check if the multilingual string has any content
302
294
  */
303
295
  hasContent() {
304
- for (const language of this._availableLanguages) for (const entry of this._content[language] ?? []) if (entry.text.trim().length > 0 || entry.richText.trim().length > 0) return true;
296
+ for (const language of this._availableLanguages) {
297
+ const entries = this._content[language] ?? [];
298
+ for (const entry of entries) if (entry.text.trim().length > 0 || entry.richText.trim().length > 0) return true;
299
+ }
305
300
  return false;
306
301
  }
307
302
  /**
@@ -357,27 +352,24 @@ var MultilingualString = class MultilingualString {
357
352
  /**
358
353
  * Transform all language versions (returns new instance)
359
354
  */
360
- map(fn) {
355
+ map(function_) {
361
356
  const newContent = {};
362
- for (const language of this._availableLanguages) {
363
- const mappedEntries = [];
364
- for (const entry of this._content[language] ?? []) mappedEntries.push({
365
- text: fn(entry.text, language),
366
- richText: fn(entry.richText, language),
367
- isPrimary: entry.isPrimary
368
- });
369
- newContent[language] = normalizePrimary(mappedEntries);
370
- }
357
+ for (const language of this._availableLanguages) newContent[language] = normalizePrimary(Array.from(this._content[language] ?? [], (entry) => ({
358
+ text: function_(entry.text, language),
359
+ richText: function_(entry.richText, language),
360
+ isPrimary: entry.isPrimary
361
+ })));
371
362
  return MultilingualString.fromNormalized(newContent, this._options, this._availableLanguages);
372
363
  }
373
364
  /**
374
365
  * Filter languages based on predicate (returns new instance)
375
366
  */
376
- filter(predicate) {
367
+ filter(shouldInclude) {
377
368
  const newContent = {};
378
369
  for (const language of this._availableLanguages) {
379
370
  const entries = [];
380
- for (const entry of this._content[language] ?? []) if (predicate(entry.text, language)) entries.push(entry);
371
+ const languageEntries = this._content[language] ?? [];
372
+ for (const entry of languageEntries) if (shouldInclude(entry.text, language)) entries.push(entry);
381
373
  newContent[language] = normalizePrimary(entries);
382
374
  }
383
375
  const newAvailableLanguages = getLanguagesWithEntries(newContent, this._options.availableLanguages);
@@ -174,12 +174,12 @@ function parsePropertyValueText(property, options) {
174
174
  function normalizePropertyToken(value) {
175
175
  return value.trim().toLowerCase().replaceAll(/[\s_]+/g, "-");
176
176
  }
177
- function propertyLabelMatches(property, uuid, tokens, options) {
177
+ function hasMatchingPropertyLabel(property, uuid, tokens, options) {
178
178
  if (uuid !== "" && property.label.uuid === uuid) return true;
179
179
  const label = normalizePropertyToken(parseContentLikeForLanguage(property.label, options));
180
180
  return tokens.includes(label);
181
181
  }
182
- function propertyValueMatches(property, uuid, tokens, options) {
182
+ function hasMatchingPropertyValue(property, uuid, tokens, options) {
183
183
  if (uuid !== "" && getPropertyValueUuid(property) === uuid) return true;
184
184
  const value = normalizePropertyToken(parsePropertyValueText(property, options));
185
185
  return tokens.includes(value);
@@ -191,33 +191,35 @@ function extractAnnotationMetadata(item, options) {
191
191
  };
192
192
  const itemProperty = item.properties?.property[0];
193
193
  if (itemProperty == null) return result;
194
- if (!propertyLabelMatches(itemProperty, "f1c131b6-1498-48a4-95bf-a9edae9fd518", ["presentation"], options) || !propertyValueMatches(itemProperty, "b9ca2732-78f4-416e-b77f-dae7647e68a9", [TEXT_ANNOTATION_TOKEN], options)) return result;
195
- for (const textAnnotationProperty of itemProperty.property ?? []) {
196
- if (propertyValueMatches(textAnnotationProperty, "c7f6a08a-f07b-49b6-bcb1-af485da3c58f", [HOVER_CARD_TOKEN], options)) {
194
+ if (!hasMatchingPropertyLabel(itemProperty, "f1c131b6-1498-48a4-95bf-a9edae9fd518", ["presentation"], options) || !hasMatchingPropertyValue(itemProperty, "b9ca2732-78f4-416e-b77f-dae7647e68a9", [TEXT_ANNOTATION_TOKEN], options)) return result;
195
+ const textAnnotationProperties = itemProperty.property ?? [];
196
+ for (const textAnnotationProperty of textAnnotationProperties) {
197
+ if (hasMatchingPropertyValue(textAnnotationProperty, "c7f6a08a-f07b-49b6-bcb1-af485da3c58f", [HOVER_CARD_TOKEN], options)) {
197
198
  result.linkVariant = "hover-card";
198
199
  continue;
199
200
  }
200
- if (propertyValueMatches(textAnnotationProperty, "bf4476ab-6bc8-40d0-a001-1446213c72ce", [ITEM_PAGE_TOKEN], options)) {
201
+ if (hasMatchingPropertyValue(textAnnotationProperty, "bf4476ab-6bc8-40d0-a001-1446213c72ce", [ITEM_PAGE_TOKEN], options)) {
201
202
  result.linkVariant = "item-page";
202
203
  continue;
203
204
  }
204
- if (propertyValueMatches(textAnnotationProperty, "9d52db95-a9cf-45f7-a0bf-fc9ba9f0aae0", [ENTRY_PAGE_TOKEN], options)) {
205
+ if (hasMatchingPropertyValue(textAnnotationProperty, "9d52db95-a9cf-45f7-a0bf-fc9ba9f0aae0", [ENTRY_PAGE_TOKEN], options)) {
205
206
  result.linkVariant = "entry-page";
206
207
  continue;
207
208
  }
208
- if (propertyValueMatches(textAnnotationProperty, "3e6f86ab-df81-45ae-8257-e2867357df56", [TEXT_STYLING_TOKEN], options)) {
209
+ if (hasMatchingPropertyValue(textAnnotationProperty, "3e6f86ab-df81-45ae-8257-e2867357df56", [TEXT_STYLING_TOKEN], options)) {
209
210
  let variant = "block";
210
211
  let size = "md";
211
212
  let headingLevel = null;
212
213
  const cssStyles = [];
213
214
  const textStylingProperties = textAnnotationProperty.property ?? [];
214
215
  for (const textStylingProperty of textStylingProperties) {
215
- if (propertyLabelMatches(textStylingProperty, "e1647bef-d801-4100-bdde-d081c422f763", [VARIANT_TOKEN], options)) {
216
+ if (hasMatchingPropertyLabel(textStylingProperty, "e1647bef-d801-4100-bdde-d081c422f763", [VARIANT_TOKEN], options)) {
216
217
  variant = parsePropertyValueText(textStylingProperty, options);
217
- for (const nestedProperty of textStylingProperty.property ?? []) if (propertyLabelMatches(nestedProperty, "", ["size"], options)) size = parsePropertyValueText(nestedProperty, options);
218
+ const nestedProperties = textStylingProperty.property ?? [];
219
+ for (const nestedProperty of nestedProperties) if (hasMatchingPropertyLabel(nestedProperty, "", ["size"], options)) size = parsePropertyValueText(nestedProperty, options);
218
220
  continue;
219
221
  }
220
- if (propertyLabelMatches(textStylingProperty, "d4266f0b-3f8d-4b32-8c15-4b229c8bb11e", [HEADING_LEVEL_TOKEN], options)) {
222
+ if (hasMatchingPropertyLabel(textStylingProperty, "d4266f0b-3f8d-4b32-8c15-4b229c8bb11e", [HEADING_LEVEL_TOKEN], options)) {
221
223
  headingLevel = parsePropertyValueText(textStylingProperty, options);
222
224
  continue;
223
225
  }
@@ -232,7 +234,6 @@ function extractAnnotationMetadata(item, options) {
232
234
  headingLevel,
233
235
  cssStyles
234
236
  };
235
- continue;
236
237
  }
237
238
  }
238
239
  return result;
@@ -243,10 +244,10 @@ function hasRichTextEnvelope(item) {
243
244
  function parseXMLStringItem(item, contentItem, options) {
244
245
  if (!(item.payload != null && item.payload !== "" || item.string != null) && getXMLRichTextLinks(item).length === 0) {
245
246
  const hasNewlineWhitespace = item.whitespace?.split(" ").includes("newline") === true;
246
- const nextHasNewlineWhitespace = options.nextItem?.whitespace?.split(" ").includes("newline") === true;
247
- if (hasNewlineWhitespace && options.rendering === "plain") return nextHasNewlineWhitespace ? "\n" : "\n\n";
248
- if (hasNewlineWhitespace && options.rendering === "rawMDX") return nextHasNewlineWhitespace ? "\n<br />" : "\n<br />\n";
249
- if (hasNewlineWhitespace && options.rendering === "rich") return nextHasNewlineWhitespace ? "<br />\n" : "<br />\n<br />\n";
247
+ const isNextContainingNewlineWhitespace = options.nextItem?.whitespace?.split(" ").includes("newline") === true;
248
+ if (hasNewlineWhitespace && options.rendering === "plain") return isNextContainingNewlineWhitespace ? "\n" : "\n\n";
249
+ if (hasNewlineWhitespace && options.rendering === "rawMDX") return isNextContainingNewlineWhitespace ? "\n<br />" : "\n<br />\n";
250
+ if (hasNewlineWhitespace && options.rendering === "rich") return isNextContainingNewlineWhitespace ? "<br />\n" : "<br />\n<br />\n";
250
251
  return applyNewlineWhitespace("", item.whitespace, options.rendering);
251
252
  }
252
253
  if (hasRichTextEnvelope(item)) {
@@ -319,9 +320,11 @@ function createInternalLinkComponent(properties) {
319
320
  function getXMLRichTextLinks(item) {
320
321
  const links = [];
321
322
  let fallbackIndex = 0;
322
- for (const rawLinks of Object.values(item.links ?? {})) {
323
+ const linkGroups = Object.values(item.links ?? {});
324
+ for (const rawLinks of linkGroups) {
323
325
  if (!Array.isArray(rawLinks)) continue;
324
- for (const rawLink of rawLinks) if (isXMLRichTextLink(rawLink) && !isTextAnnotationMarkerLink(rawLink)) {
326
+ for (const rawLink of rawLinks) {
327
+ if (!(isXMLRichTextLink(rawLink) && !isTextAnnotationMarkerLink(rawLink))) continue;
325
328
  links.push({
326
329
  link: rawLink,
327
330
  fallbackIndex
@@ -350,34 +353,30 @@ function renderRichTextItem(item, linkString, contentItem, options) {
350
353
  const contentText = (rendering === "plain" ? linkContent.getExactText(contentItem.lang) : linkContent.getExactRichText(contentItem.lang)) ?? "";
351
354
  if ("type" in link && link.type != null) switch (link.type) {
352
355
  case "IIIF":
353
- case "image":
354
- if ("rend" in link && link.rend === "inline") {
355
- const component = createMDXComponent("inlineImage", {
356
- uuid: getLinkStringProperty(link, "uuid"),
357
- href: getLinkStringProperty(link, "href") ?? void 0,
358
- height: getLinkStringProperty(link, "height") ?? void 0,
359
- width: getLinkStringProperty(link, "width") ?? void 0,
360
- content: contentText,
361
- text: linkString
362
- });
363
- result += component;
364
- } else if (link.publicationDateTime != null) {
365
- const component = createInternalLinkComponent({
366
- uuid: getLinkStringProperty(link, "uuid"),
367
- text: linkString,
368
- content: contentText,
369
- annotationMetadata
370
- });
371
- result += component;
372
- } else {
373
- const component = createMDXComponent("tooltipSpan", {
374
- uuid: getLinkStringProperty(link, "uuid"),
375
- text: linkString,
376
- content: contentText
377
- });
378
- result += component;
379
- }
356
+ case "image": {
357
+ let component;
358
+ if ("rend" in link && link.rend === "inline") component = createMDXComponent("inlineImage", {
359
+ uuid: getLinkStringProperty(link, "uuid"),
360
+ href: getLinkStringProperty(link, "href") ?? void 0,
361
+ height: getLinkStringProperty(link, "height") ?? void 0,
362
+ width: getLinkStringProperty(link, "width") ?? void 0,
363
+ content: contentText,
364
+ text: linkString
365
+ });
366
+ else if (link.publicationDateTime != null) component = createInternalLinkComponent({
367
+ uuid: getLinkStringProperty(link, "uuid"),
368
+ text: linkString,
369
+ content: contentText,
370
+ annotationMetadata
371
+ });
372
+ else component = createMDXComponent("tooltipSpan", {
373
+ uuid: getLinkStringProperty(link, "uuid"),
374
+ text: linkString,
375
+ content: contentText
376
+ });
377
+ result += component;
380
378
  break;
379
+ }
381
380
  case "internalDocument": {
382
381
  const component = createInternalLinkComponent({
383
382
  uuid: getLinkStringProperty(link, "uuid"),
@@ -390,11 +389,7 @@ function renderRichTextItem(item, linkString, contentItem, options) {
390
389
  break;
391
390
  }
392
391
  case "externalDocument": {
393
- const component = link.publicationDateTime != null ? createMDXComponent("documentLink", {
394
- uuid: getLinkStringProperty(link, "uuid"),
395
- text: linkString,
396
- content: contentText
397
- }) : createMDXComponent("tooltipSpan", {
392
+ const component = createMDXComponent(link.publicationDateTime != null ? "documentLink" : "tooltipSpan", {
398
393
  uuid: getLinkStringProperty(link, "uuid"),
399
394
  text: linkString,
400
395
  content: contentText
@@ -412,6 +407,18 @@ function renderRichTextItem(item, linkString, contentItem, options) {
412
407
  result += component;
413
408
  break;
414
409
  }
410
+ default:
411
+ result += link.publicationDateTime != null ? createInternalLinkComponent({
412
+ uuid: getLinkStringProperty(link, "uuid"),
413
+ text: linkString,
414
+ content: contentText,
415
+ annotationMetadata
416
+ }) : createMDXComponent("tooltipSpan", {
417
+ uuid: getLinkStringProperty(link, "uuid"),
418
+ text: linkString,
419
+ content: contentText
420
+ });
421
+ break;
415
422
  }
416
423
  else if (link.publicationDateTime != null) {
417
424
  const component = createInternalLinkComponent({
@@ -470,7 +477,7 @@ function parseXMLContentItem(contentItem, options) {
470
477
  rendering: "rich",
471
478
  rawMDXBlocks
472
479
  }));
473
- for (const [index, rawMDXBlock] of rawMDXBlocks.entries()) serializedRichText = serializedRichText.replaceAll(`${RAW_MDX_BLOCK_PLACEHOLDER_PREFIX}${index}${RAW_MDX_BLOCK_PLACEHOLDER_SUFFIX}`, rawMDXBlock);
480
+ for (const [index, rawMDXBlock] of rawMDXBlocks.entries()) serializedRichText = serializedRichText.replaceAll(`${RAW_MDX_BLOCK_PLACEHOLDER_PREFIX}${index}${RAW_MDX_BLOCK_PLACEHOLDER_SUFFIX}`, () => rawMDXBlock);
474
481
  return {
475
482
  text: parseNestedStringItems(contentItem.string, contentItem, {
476
483
  ...options,
@@ -8,8 +8,8 @@ import * as v from "valibot";
8
8
  function isWebsiteLink(link, category) {
9
9
  return link.category === category;
10
10
  }
11
- function findWebsiteLink(links, category, predicate) {
12
- for (const link of links) if (isWebsiteLink(link, category) && (predicate == null || predicate(link))) return link;
11
+ function findWebsiteLink(links, category, isMatch) {
12
+ for (const link of links) if (isWebsiteLink(link, category) && (isMatch == null || isMatch(link))) return link;
13
13
  return null;
14
14
  }
15
15
  function findWebsiteLinkByCategories(links, categories) {
@@ -26,7 +26,8 @@ function transformPermanentIdentificationUrlToItemLink(url) {
26
26
  }
27
27
  function normalizeWebsiteResources(resources) {
28
28
  const normalized = [];
29
- for (const resource of resources ?? []) {
29
+ const resourcesToNormalize = resources ?? [];
30
+ for (const resource of resourcesToNormalize) {
30
31
  if ("identification" in resource) {
31
32
  normalized.push(resource);
32
33
  continue;
@@ -45,7 +46,8 @@ function prefixSlug(slug, slugPrefix) {
45
46
  return `${slugPrefix}/${slug}`;
46
47
  }
47
48
  function collectWebsitePageSlugs(resources, options, slugPrefix, pageSlugsByUuid = /* @__PURE__ */ new Map(), segmentSlugPrefix = slugPrefix) {
48
- for (const resource of resources ?? []) {
49
+ const slugResources = resources ?? [];
50
+ for (const resource of slugResources) {
49
51
  if ("segments" in resource) {
50
52
  for (const tree of resource.segments.tree) {
51
53
  const segmentSlug = tree.identification.abbreviation == null ? null : parseStringContent(tree.identification.abbreviation, options);
@@ -124,7 +126,7 @@ function parseResponsiveCssStyles(properties) {
124
126
  * @returns Parsed bounds object
125
127
  */
126
128
  function parseBounds(bounds) {
127
- const [southWest, northEast] = bounds.trim().startsWith("[") ? parseJsonBounds(bounds) : bounds.split(";").map((pair) => pair.split(",").map((coordinate) => Number.parseFloat(coordinate.trim())));
129
+ const [southWest, northEast] = bounds.trim().startsWith("[") ? parseJsonBounds(bounds) : bounds.split(";").map((pair) => pair.split(",").map((coordinate) => Number(coordinate.trim())));
128
130
  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 });
129
131
  return [[southWest[0], southWest[1]], [northEast[0], northEast[1]]];
130
132
  }
@@ -175,13 +177,11 @@ function parseAllOptionContexts(options, parserOptions) {
175
177
  }
176
178
  function parseWebsiteScopes(scopes, options) {
177
179
  if (scopes == null) return null;
178
- const parsedScopes = [];
179
- for (const scope of scopes.scope) parsedScopes.push({
180
+ return Array.from(scopes.scope, (scope) => ({
180
181
  uuid: scope.uuid.payload,
181
182
  type: scope.uuid.type,
182
183
  identification: parseIdentification(scope.identification, options)
183
- });
184
- return parsedScopes;
184
+ }));
185
185
  }
186
186
  function parseWebsiteOptions(rawOptions, options) {
187
187
  const parsedOptions = {
@@ -189,7 +189,9 @@ function parseWebsiteOptions(rawOptions, options) {
189
189
  contextTree: rawOptions == null ? null : parseAllOptionContexts(rawOptions, options),
190
190
  labels: { title: null }
191
191
  };
192
- for (const note of parseNotes(rawOptions?.notes, options)) if (note.title?.getText() === "Title label") {
192
+ const notes = parseNotes(rawOptions?.notes, options);
193
+ for (const note of notes) {
194
+ if (note.title?.getText() !== "Title label") continue;
193
195
  parsedOptions.labels.title = note.content;
194
196
  break;
195
197
  }
@@ -200,7 +202,13 @@ function parseStylesheets(styles) {
200
202
  for (const style of styles) {
201
203
  const defaultStyles = [];
202
204
  for (const [label, value] of Object.entries(style)) {
203
- if (label === "variableUuid" || label === "valueUuid" || label === "category" || label === "payload" || label === "content") continue;
205
+ if ([
206
+ "variableUuid",
207
+ "valueUuid",
208
+ "category",
209
+ "payload",
210
+ "content"
211
+ ].includes(label)) continue;
204
212
  const valueString = value?.toString();
205
213
  if (valueString != null) defaultStyles.push({
206
214
  label,
@@ -389,10 +397,8 @@ function parseWebElementProperties(componentProperty, elementResource, options,
389
397
  if (href === null) {
390
398
  href = parseWebsiteLinkTarget(componentReader.valueNode("link-to"), context);
391
399
  if (href === null) throw new Error(formatComponentError("Properties “navigate-to” or “link-to” not found", componentName, elementResource), { cause: componentProperty });
392
- else {
393
- isExternal = href.startsWith("http");
394
- isRelative = !href.startsWith("/");
395
- }
400
+ isExternal = href.startsWith("http");
401
+ isRelative = !href.startsWith("/");
396
402
  }
397
403
  const startIcon = componentReader.value("start-icon");
398
404
  const endIcon = componentReader.value("end-icon");
@@ -406,6 +412,14 @@ function parseWebElementProperties(componentProperty, elementResource, options,
406
412
  description: imageLink.description,
407
413
  quality: "high"
408
414
  };
415
+ const childResources = elementResource.resource ? normalizeWebsiteResources(elementResource.resource) : [];
416
+ const elements = [];
417
+ for (const childResource of childResources) {
418
+ const childReader = websitePresentationReader(childResource.properties ? parseSimplifiedProperties(childResource.properties, options) : []);
419
+ if (childReader.value("presentation") !== "element") continue;
420
+ if (childReader.nestedByValue("presentation", "element").value("component") === "button") continue;
421
+ elements.push(parseWebElement(childResource, options, context));
422
+ }
409
423
  properties = {
410
424
  component: "button",
411
425
  variant,
@@ -415,7 +429,8 @@ function parseWebElementProperties(componentProperty, elementResource, options,
415
429
  label: elementResource.document && "content" in elementResource.document ? parseXMLContent(elementResource.document, options) : null,
416
430
  startIcon,
417
431
  endIcon,
418
- image
432
+ image,
433
+ elements
419
434
  };
420
435
  break;
421
436
  }
@@ -492,28 +507,27 @@ function parseWebElementProperties(componentProperty, elementResource, options,
492
507
  case "image": {
493
508
  if (websiteLinks.length === 0) throw new Error(formatComponentError("No links found", componentName, elementResource), { cause: componentProperty });
494
509
  const imageQuality = componentReader.valueOr("image-quality", "high");
495
- const images = [];
496
- for (const link of websiteLinks) images.push({
510
+ const images = Array.from(websiteLinks, (link) => ({
497
511
  uuid: link.uuid,
498
512
  label: link.identification.label,
499
513
  width: "image" in link ? link.image?.width ?? 0 : 0,
500
514
  height: "image" in link ? link.image?.height ?? 0 : 0,
501
515
  description: link.description,
502
516
  quality: imageQuality
503
- });
517
+ }));
504
518
  const variant = componentReader.valueOr("variant", "default");
505
519
  const captionLayout = componentReader.valueOr("layout-caption", "bottom");
506
520
  let width = null;
507
521
  const widthProperty = componentReader.value("width");
508
522
  if (widthProperty !== null) {
509
523
  if (typeof widthProperty === "number") width = widthProperty;
510
- else if (typeof widthProperty === "string") width = Number.parseFloat(widthProperty);
524
+ else if (typeof widthProperty === "string") width = Number(widthProperty);
511
525
  }
512
526
  let height = null;
513
527
  const heightProperty = componentReader.value("height");
514
528
  if (heightProperty !== null) {
515
529
  if (typeof heightProperty === "number") height = heightProperty;
516
- else if (typeof heightProperty === "string") height = Number.parseFloat(heightProperty);
530
+ else if (typeof heightProperty === "string") height = Number(heightProperty);
517
531
  }
518
532
  const isFullWidth = componentReader.valueOr("is-full-width", true);
519
533
  const isFullHeight = componentReader.valueOr("is-full-height", true);
@@ -529,7 +543,7 @@ function parseWebElementProperties(componentProperty, elementResource, options,
529
543
  const secondsPerImageProperty = variantReader.value("seconds-per-image");
530
544
  if (secondsPerImageProperty !== null) {
531
545
  if (typeof secondsPerImageProperty === "number") secondsPerImage = secondsPerImageProperty;
532
- else if (typeof secondsPerImageProperty === "string") secondsPerImage = Number.parseFloat(secondsPerImageProperty);
546
+ else if (typeof secondsPerImageProperty === "string") secondsPerImage = Number(secondsPerImageProperty);
533
547
  }
534
548
  }
535
549
  carouselOptions = { secondsPerImage };
@@ -601,8 +615,8 @@ function parseWebElementProperties(componentProperty, elementResource, options,
601
615
  case "query": {
602
616
  const setLinks = getWebsiteLinks(websiteLinks, "set");
603
617
  if (setLinks.length === 0) throw new Error(formatComponentError("Set links not found", componentName, elementResource), { cause: componentProperty });
604
- const items = [];
605
618
  if (componentProperty.properties.length === 0) throw new Error(formatComponentError("Query properties not found", componentName, elementResource), { cause: componentProperty });
619
+ const items = [];
606
620
  for (const queryItem of componentProperty.properties) {
607
621
  const queryReader = websitePresentationReader(queryItem.properties);
608
622
  const label = queryReader.multilingualValue("query-prompt", options);
@@ -776,7 +790,11 @@ function parseWebElement(elementResource, options, context) {
776
790
  const properties = parseWebElementProperties(websitePresentationReader(websitePresentationReader(elementProperties).requiredProperty("presentation", `Presentation property not found for element (${formatXMLWebsiteResourceMetadata(elementResource)})`).properties).requiredProperty("component", `Component property not found for element (${formatXMLWebsiteResourceMetadata(elementResource)})`), elementResource, options, context);
777
791
  const cssStyles = parseResponsiveCssStyles(elementProperties);
778
792
  const title = parseWebTitle(elementProperties, identification, {
779
- isNameDisplayed: properties.component === "annotated-image" || properties.component === "annotated-document" || properties.component === "collection",
793
+ isNameDisplayed: [
794
+ "annotated-image",
795
+ "annotated-document",
796
+ "collection"
797
+ ].includes(properties.component),
780
798
  isCountDisplayed: properties.component === "collection"
781
799
  });
782
800
  return {
@@ -816,6 +834,7 @@ function parseWebpage(webpageResource, options, context, slugPrefix) {
816
834
  isSidebarDisplayed: true,
817
835
  isDisplayedInNavbar: true,
818
836
  isNavbarSearchBarDisplayed: true,
837
+ redirect: null,
819
838
  backgroundImage: null,
820
839
  sidebar: null,
821
840
  cssStyles: {
@@ -859,6 +878,11 @@ function parseWebpage(webpageResource, options, context, slugPrefix) {
859
878
  returnWebpage.properties.isSidebarDisplayed = pageReader.valueOr("sidebar-displayed", true);
860
879
  returnWebpage.properties.isBreadcrumbsDisplayed = pageReader.valueOr("breadcrumbs-displayed", false);
861
880
  returnWebpage.properties.isNavbarSearchBarDisplayed = pageReader.valueOr("navbar-search-bar-displayed", true);
881
+ const redirectHref = parseWebsiteLinkTarget(pageReader.valueNode("redirect-to"), context);
882
+ if (redirectHref != null) returnWebpage.properties.redirect = {
883
+ href: redirectHref,
884
+ isExternal: redirectHref.startsWith("http")
885
+ };
862
886
  }
863
887
  if (imageLink != null) returnWebpage.properties.backgroundImage = {
864
888
  uuid: imageLink.uuid,
@@ -890,7 +914,8 @@ function parseWebpageView(view, options, context) {
890
914
  }
891
915
  function parseWebsiteSegments(resources, context, options, slugPrefix) {
892
916
  const segments = [];
893
- for (const resource of resources ?? []) {
917
+ const segmentResources = resources ?? [];
918
+ for (const resource of segmentResources) {
894
919
  if (!("segments" in resource)) continue;
895
920
  for (const tree of resource.segments.tree) {
896
921
  const segmentSlug = tree.identification.abbreviation == null ? null : parseStringContent(tree.identification.abbreviation, options);
@@ -1066,7 +1091,7 @@ function parseWebBlock(blockResource, options, context) {
1066
1091
  }
1067
1092
  }
1068
1093
  const blockResources = blockResource.resource ? normalizeWebsiteResources(blockResource.resource) : [];
1069
- const supportsAccordionItems = returnBlock.properties.default.layout === "accordion" || returnBlock.properties.tablet?.layout === "accordion" || returnBlock.properties.mobile?.layout === "accordion";
1094
+ const isSupportingAccordionItems = returnBlock.properties.default.layout === "accordion" || returnBlock.properties.tablet?.layout === "accordion" || returnBlock.properties.mobile?.layout === "accordion";
1070
1095
  const blockItems = [];
1071
1096
  for (const resource of blockResources) {
1072
1097
  const resourceReader = websitePresentationReader(resource.properties ? parseSimplifiedProperties(resource.properties, options) : []);
@@ -1076,7 +1101,7 @@ function parseWebBlock(blockResource, options, context) {
1076
1101
  case "element": {
1077
1102
  const childResources = resource.resource ? normalizeWebsiteResources(resource.resource) : [];
1078
1103
  const componentType = resourceReader.nestedByValue("presentation", "element").value("component");
1079
- if (supportsAccordionItems && componentType === "text" && childResources.length > 0) {
1104
+ if (isSupportingAccordionItems && componentType === "text" && childResources.length > 0) {
1080
1105
  const item = parseWebAccordionItem(resource, childResources, options, context);
1081
1106
  blockItems.push(item);
1082
1107
  break;
@@ -1204,7 +1229,8 @@ function parseWebsiteProperties(properties, websiteTree, sidebar, options) {
1204
1229
  function parseContextItem(contextItemToParse, options) {
1205
1230
  let type = "";
1206
1231
  const levels = [];
1207
- for (const level of contextItemToParse.levels?.level ?? []) {
1232
+ const levelsToParse = contextItemToParse.levels?.level ?? [];
1233
+ for (const level of levelsToParse) {
1208
1234
  const [rawVariableUuid = "", rawValueUuid] = level.payload.split(",");
1209
1235
  const valueUuid = rawValueUuid == null || rawValueUuid.trim() === "null" ? null : rawValueUuid.trim();
1210
1236
  type = level.dataType ?? type;