@digitalculture/ochre-sdk 0.1.20 → 0.1.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.cjs ADDED
@@ -0,0 +1,2121 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ fetchByUuid: () => fetchByUuid,
24
+ fetchConcept: () => fetchConcept,
25
+ fetchGallery: () => fetchGallery,
26
+ fetchResource: () => fetchResource,
27
+ fetchSet: () => fetchSet,
28
+ fetchSpatialUnit: () => fetchSpatialUnit,
29
+ fetchTree: () => fetchTree,
30
+ fetchWebsite: () => fetchWebsite,
31
+ filterProperties: () => filterProperties,
32
+ getAllPropertyLabels: () => getAllPropertyLabels,
33
+ getPropertyByLabel: () => getPropertyByLabel,
34
+ getPropertyValueByLabel: () => getPropertyValueByLabel,
35
+ getPropertyValuesByLabel: () => getPropertyValuesByLabel,
36
+ parseBibliographies: () => parseBibliographies,
37
+ parseBibliography: () => parseBibliography,
38
+ parseConcept: () => parseConcept,
39
+ parseConcepts: () => parseConcepts,
40
+ parseContext: () => parseContext,
41
+ parseCoordinates: () => parseCoordinates,
42
+ parseDocument: () => parseDocument,
43
+ parseEmailAndUrl: () => parseEmailAndUrl,
44
+ parseEvents: () => parseEvents,
45
+ parseFakeString: () => parseFakeString,
46
+ parseIdentification: () => parseIdentification,
47
+ parseImage: () => parseImage,
48
+ parseImageMap: () => parseImageMap,
49
+ parseInterpretations: () => parseInterpretations,
50
+ parseLanguages: () => parseLanguages,
51
+ parseLicense: () => parseLicense,
52
+ parseLink: () => parseLink,
53
+ parseLinks: () => parseLinks,
54
+ parseMetadata: () => parseMetadata,
55
+ parseNotes: () => parseNotes,
56
+ parseObservation: () => parseObservation,
57
+ parseObservations: () => parseObservations,
58
+ parsePeriod: () => parsePeriod,
59
+ parsePeriods: () => parsePeriods,
60
+ parsePersons: () => parsePersons,
61
+ parseProperties: () => parseProperties,
62
+ parseResource: () => parseResource,
63
+ parseResources: () => parseResources,
64
+ parseSet: () => parseSet,
65
+ parseSpatialUnit: () => parseSpatialUnit,
66
+ parseSpatialUnits: () => parseSpatialUnits,
67
+ parseStringContent: () => parseStringContent,
68
+ parseStringDocumentItem: () => parseStringDocumentItem,
69
+ parseStringItem: () => parseStringItem,
70
+ parseTree: () => parseTree,
71
+ parseWebsite: () => parseWebsite,
72
+ trimEndLineBreaks: () => trimEndLineBreaks
73
+ });
74
+ module.exports = __toCommonJS(index_exports);
75
+
76
+ // src/utils/fetchers/generic.ts
77
+ var import_zod = require("zod");
78
+ var uuidSchema = import_zod.z.string().uuid({ message: "Invalid UUID provided" });
79
+ async function fetchByUuid(uuid) {
80
+ try {
81
+ const result = uuidSchema.safeParse(uuid);
82
+ if (!result.success) {
83
+ throw new Error(result.error.issues[0]?.message);
84
+ }
85
+ const response = await fetch(
86
+ `https://ochre.lib.uchicago.edu/ochre?uuid=${uuid}&format=json&lang="*"`
87
+ );
88
+ if (!response.ok) {
89
+ throw new Error("Failed to fetch OCHRE data");
90
+ }
91
+ const dataRaw = await response.json();
92
+ if (!("ochre" in dataRaw)) {
93
+ throw new Error("Invalid OCHRE data: API response missing 'ochre' key");
94
+ }
95
+ return [null, dataRaw];
96
+ } catch (error) {
97
+ return [error instanceof Error ? error.message : "Unknown error", null];
98
+ }
99
+ }
100
+
101
+ // src/utils/parse.ts
102
+ var import_zod3 = require("zod");
103
+
104
+ // src/utils/string.ts
105
+ var import_zod2 = require("zod");
106
+ var renderOptionsSchema = import_zod2.z.string().transform((str) => str.split(" ")).pipe(
107
+ import_zod2.z.array(
108
+ import_zod2.z.enum([
109
+ "bold",
110
+ "italic",
111
+ "underline"
112
+ ])
113
+ )
114
+ );
115
+ var whitespaceSchema = import_zod2.z.string().transform((str) => str.split(" ")).pipe(
116
+ import_zod2.z.array(
117
+ import_zod2.z.enum([
118
+ "newline",
119
+ "trailing",
120
+ "leading"
121
+ ])
122
+ )
123
+ );
124
+ var emailSchema = import_zod2.z.string().email({ message: "Invalid email" });
125
+ var urlSchema = import_zod2.z.string().refine((v) => v ? isUrlValid(v) : false, {
126
+ message: "Invalid URL"
127
+ });
128
+ function isUrlValid(url) {
129
+ const pattern = (
130
+ // eslint-disable-next-line regexp/no-useless-quantifier, regexp/no-unused-capturing-group
131
+ /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\w$&+,:;=-]+@)?[\d.A-Za-z-]+(:\d+)?|(?:www.|[\w$&+,:;=-]+@)[\d.A-Za-z-]+)((?:\/[\w%+./~-]*)?\??[\w%&+.;=@-]*#?\w*)?)/
132
+ );
133
+ return !!pattern.test(url);
134
+ }
135
+ function getStringItemByLanguage(content, language) {
136
+ const stringItemToFind = content.find((item) => item.lang === language);
137
+ return stringItemToFind ?? null;
138
+ }
139
+ function parseEmailAndUrl(string) {
140
+ const splitString = string.split(" ");
141
+ const returnSplitString = [];
142
+ for (const string2 of splitString) {
143
+ const cleanString = string2.replaceAll(/(?<=\s|^)[([{]+|[)\]}]+(?=\s|$)/g, "").replace(/[!),.:;?\]]$/, "");
144
+ const index = string2.indexOf(cleanString);
145
+ const before = string2.slice(0, index);
146
+ const after = string2.slice(index + cleanString.length);
147
+ const isEmail = emailSchema.safeParse(cleanString).success;
148
+ if (isEmail) {
149
+ returnSplitString.push(
150
+ before,
151
+ `${before}<ExternalLink href="mailto:${cleanString}">${cleanString}</ExternalLink>${after}`
152
+ );
153
+ continue;
154
+ }
155
+ const isUrl = urlSchema.safeParse(cleanString).success;
156
+ if (isUrl) {
157
+ returnSplitString.push(
158
+ `${before}<ExternalLink href="${cleanString}">${cleanString}</ExternalLink>${after}`
159
+ );
160
+ continue;
161
+ }
162
+ returnSplitString.push(string2);
163
+ }
164
+ return returnSplitString.join(" ");
165
+ }
166
+ function parseRenderOptions(contentString, renderString) {
167
+ let returnString = contentString;
168
+ const result = renderOptionsSchema.safeParse(renderString);
169
+ if (!result.success) {
170
+ console.warn(`Invalid render options string provided: \u201C${renderString}\u201D`);
171
+ return contentString;
172
+ }
173
+ for (const option of result.data) {
174
+ switch (option) {
175
+ case "bold": {
176
+ returnString = `**${returnString}**`;
177
+ break;
178
+ }
179
+ case "italic": {
180
+ returnString = `*${returnString}*`;
181
+ break;
182
+ }
183
+ case "underline": {
184
+ returnString = `_${returnString}_`;
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ return returnString.replaceAll("&#39;", "'");
190
+ }
191
+ function parseWhitespace(contentString, whitespace) {
192
+ let returnString = contentString;
193
+ const result = whitespaceSchema.safeParse(whitespace);
194
+ if (!result.success) {
195
+ console.warn(`Invalid whitespace string provided: \u201C${whitespace}\u201D`);
196
+ return contentString;
197
+ }
198
+ for (const option of result.data) {
199
+ switch (option) {
200
+ case "newline": {
201
+ returnString = `${returnString}
202
+ <br />`;
203
+ break;
204
+ }
205
+ case "trailing": {
206
+ returnString = `${returnString} `;
207
+ break;
208
+ }
209
+ case "leading": {
210
+ returnString = ` ${returnString}`;
211
+ break;
212
+ }
213
+ }
214
+ }
215
+ return returnString.replaceAll("&#39;", "'");
216
+ }
217
+ function parseFakeString(string) {
218
+ let returnString = "";
219
+ if (typeof string === "string") {
220
+ returnString = string;
221
+ } else if (typeof string === "number") {
222
+ returnString = string.toString();
223
+ } else if (typeof string === "boolean") {
224
+ returnString = string ? "Yes" : "No";
225
+ }
226
+ return returnString.replaceAll("&#39;", "'");
227
+ }
228
+ function parseStringItem(item) {
229
+ let returnString = "";
230
+ switch (typeof item.string) {
231
+ case "string": {
232
+ returnString = item.string;
233
+ break;
234
+ }
235
+ case "number":
236
+ case "boolean": {
237
+ returnString = parseFakeString(item.string);
238
+ break;
239
+ }
240
+ case "object": {
241
+ const stringItems = Array.isArray(item.string) ? item.string : [item.string];
242
+ for (const stringItem of stringItems) {
243
+ const renderedText = stringItem.rend != null ? parseRenderOptions(
244
+ parseFakeString(stringItem.content),
245
+ stringItem.rend
246
+ ) : parseFakeString(stringItem.content);
247
+ const whitespacedText = stringItem.whitespace != null ? parseWhitespace(renderedText, stringItem.whitespace) : renderedText;
248
+ returnString += whitespacedText;
249
+ }
250
+ break;
251
+ }
252
+ default: {
253
+ returnString = "";
254
+ break;
255
+ }
256
+ }
257
+ return returnString.replaceAll("&#39;", "'");
258
+ }
259
+ function parseStringDocumentItem(item, footnotes) {
260
+ if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") {
261
+ return parseEmailAndUrl(parseFakeString(item));
262
+ }
263
+ if ("whitespace" in item && !("content" in item) && !("string" in item)) {
264
+ if (item.whitespace === "newline") {
265
+ return " \n";
266
+ } else {
267
+ return "";
268
+ }
269
+ }
270
+ if ("links" in item) {
271
+ const itemString = parseFakeString(item.string).replaceAll("<", String.raw`\<`).replaceAll("{", String.raw`\{`);
272
+ const itemLinks = Array.isArray(item.links) ? item.links : [item.links];
273
+ for (const link of itemLinks) {
274
+ if ("resource" in link) {
275
+ const linkResource = Array.isArray(link.resource) ? link.resource[0] : link.resource;
276
+ let linkContent = null;
277
+ if (linkResource.content != null) {
278
+ linkContent = parseFakeString(linkResource.content).replaceAll("<", String.raw`\<`).replaceAll("{", String.raw`\{`);
279
+ }
280
+ switch (linkResource.type) {
281
+ case "image": {
282
+ if (linkResource.rend === "inline") {
283
+ return `<InlineImage uuid="${linkResource.uuid}" ${linkContent !== null ? `content="${linkContent}"` : ""} height={${linkResource.height?.toString() ?? "null"}} width={${linkResource.width?.toString() ?? "null"}} />`;
284
+ } else if (linkResource.publicationDateTime != null) {
285
+ return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkResource.uuid}" type="image"${linkContent !== null ? ` content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
286
+ } else {
287
+ return `<TooltipSpan type="image" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</TooltipSpan>`;
288
+ }
289
+ }
290
+ case "internalDocument": {
291
+ const isFootnote = linkContent?.toLocaleLowerCase("en-US").includes("footnote");
292
+ if (isFootnote) {
293
+ if (footnotes) {
294
+ footnotes.push({
295
+ uuid: linkResource.uuid,
296
+ label: itemString,
297
+ content: ""
298
+ });
299
+ }
300
+ return ` <Footnote uuid="${linkResource.uuid}"${itemString ? ` label="${itemString}"` : ""}${linkContent !== null ? ` content="${linkContent}"` : ""} />`;
301
+ } else {
302
+ return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkResource.uuid}" type="internalDocument" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
303
+ }
304
+ }
305
+ case "externalDocument": {
306
+ if (linkResource.publicationDateTime != null) {
307
+ return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkResource.uuid}" type="externalDocument" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
308
+ } else {
309
+ return `<TooltipSpan type="externalDocument" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</TooltipSpan>`;
310
+ }
311
+ }
312
+ default: {
313
+ return "";
314
+ }
315
+ }
316
+ } else if ("concept" in link) {
317
+ const linkConcept = Array.isArray(link.concept) ? link.concept[0] : link.concept;
318
+ if (linkConcept.publicationDateTime != null) {
319
+ return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkConcept.uuid}" type="concept">${itemString}</ExternalLink>`;
320
+ } else {
321
+ return `<TooltipSpan type="concept">${itemString}</TooltipSpan>`;
322
+ }
323
+ } else if ("set" in link) {
324
+ const linkSet = Array.isArray(link.set) ? link.set[0] : link.set;
325
+ if (linkSet.publicationDateTime != null) {
326
+ return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkSet.uuid}" type="set">${itemString}</ExternalLink>`;
327
+ } else {
328
+ return `<TooltipSpan type="set">${itemString}</TooltipSpan>`;
329
+ }
330
+ } else if ("person" in link) {
331
+ const linkPerson = Array.isArray(link.person) ? link.person[0] : link.person;
332
+ const linkContent = linkPerson.identification ? parseStringContent(linkPerson.identification.label) : null;
333
+ if (linkPerson.publicationDateTime != null) {
334
+ return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkPerson.uuid}" type="${linkPerson.type ?? "person"}" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
335
+ } else {
336
+ return `<TooltipSpan type="${linkPerson.type ?? "person"}" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</TooltipSpan>`;
337
+ }
338
+ } else if ("bibliography" in link) {
339
+ const linkBibliography = Array.isArray(link.bibliography) ? link.bibliography[0] : link.bibliography;
340
+ if (linkBibliography.publicationDateTime != null) {
341
+ return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkBibliography.uuid}" type="${linkBibliography.type ?? "bibliography"}">${itemString}</ExternalLink>`;
342
+ } else {
343
+ return `<TooltipSpan type="bibliography">${itemString}</TooltipSpan>`;
344
+ }
345
+ }
346
+ }
347
+ }
348
+ let returnString = "";
349
+ if ("string" in item) {
350
+ const stringItems = Array.isArray(item.string) ? item.string : [item.string];
351
+ for (const stringItem of stringItems) {
352
+ returnString += parseStringDocumentItem(stringItem, footnotes);
353
+ }
354
+ if ("whitespace" in item && item.whitespace != null) {
355
+ returnString = parseWhitespace(
356
+ parseEmailAndUrl(returnString),
357
+ item.whitespace
358
+ );
359
+ }
360
+ return returnString.replaceAll("&#39;", "'");
361
+ } else {
362
+ returnString = parseFakeString(item.content);
363
+ if (item.rend != null) {
364
+ returnString = parseRenderOptions(
365
+ parseEmailAndUrl(returnString),
366
+ item.rend
367
+ );
368
+ }
369
+ if (item.whitespace != null) {
370
+ returnString = parseWhitespace(
371
+ parseEmailAndUrl(returnString),
372
+ item.whitespace
373
+ );
374
+ }
375
+ }
376
+ return returnString.replaceAll("&#39;", "'");
377
+ }
378
+ function trimEndLineBreaks(string) {
379
+ const trimmedString = string.replaceAll(/^\n<br \/>|\n<br \/>$/g, "");
380
+ const finalLineBreaks = /\n<br \/>$/.exec(trimmedString);
381
+ if (finalLineBreaks) {
382
+ return trimEndLineBreaks(trimmedString);
383
+ }
384
+ return trimmedString;
385
+ }
386
+ function parseStringContent(content, language = "eng") {
387
+ switch (typeof content.content) {
388
+ case "string":
389
+ case "number":
390
+ case "boolean": {
391
+ return parseFakeString(content.content);
392
+ }
393
+ case "object": {
394
+ if (Array.isArray(content.content)) {
395
+ const stringItem = getStringItemByLanguage(content.content, language);
396
+ if (stringItem) {
397
+ return parseStringItem(stringItem);
398
+ } else {
399
+ const returnStringItem = content.content[0];
400
+ if (!returnStringItem) {
401
+ throw new Error(
402
+ `No string item found for language \u201C${language}\u201D in the following content:
403
+ ${JSON.stringify(
404
+ content.content
405
+ )}.`
406
+ );
407
+ }
408
+ return parseStringItem(returnStringItem);
409
+ }
410
+ } else {
411
+ return parseStringItem(content.content);
412
+ }
413
+ }
414
+ default: {
415
+ return String(content.content);
416
+ }
417
+ }
418
+ }
419
+
420
+ // src/utils/fetchers/resource.ts
421
+ async function fetchResource(uuid) {
422
+ try {
423
+ const [error, dataRaw] = await fetchByUuid(uuid);
424
+ if (error !== null) {
425
+ throw new Error(error);
426
+ }
427
+ if (!("resource" in dataRaw.ochre)) {
428
+ throw new Error(
429
+ "Invalid OCHRE data: API response missing 'resource' key"
430
+ );
431
+ }
432
+ const resourceItem = parseResource(dataRaw.ochre.resource);
433
+ const data = {
434
+ uuid: parseFakeString(dataRaw.ochre.uuid),
435
+ publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
436
+ belongsTo: {
437
+ uuid: dataRaw.ochre.uuidBelongsTo,
438
+ abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
439
+ },
440
+ metadata: parseMetadata(dataRaw.ochre.metadata),
441
+ item: resourceItem
442
+ };
443
+ return { metadata: data.metadata, resource: data.item };
444
+ } catch (error) {
445
+ console.error(error);
446
+ return null;
447
+ }
448
+ }
449
+
450
+ // src/utils/getters.ts
451
+ var DEFAULT_OPTIONS = {
452
+ searchNestedProperties: false
453
+ };
454
+ function getPropertyByLabel(properties, label, options = DEFAULT_OPTIONS) {
455
+ const { searchNestedProperties } = options;
456
+ const property = properties.find((property2) => property2.label === label);
457
+ if (property) {
458
+ return property;
459
+ }
460
+ if (searchNestedProperties) {
461
+ for (const property2 of properties) {
462
+ if (property2.properties.length > 0) {
463
+ const nestedResult = getPropertyByLabel(property2.properties, label, {
464
+ searchNestedProperties
465
+ });
466
+ if (nestedResult) {
467
+ return nestedResult;
468
+ }
469
+ }
470
+ }
471
+ }
472
+ return null;
473
+ }
474
+ function getPropertyValuesByLabel(properties, label, options = DEFAULT_OPTIONS) {
475
+ const { searchNestedProperties } = options;
476
+ const property = properties.find((property2) => property2.label === label);
477
+ if (property) {
478
+ return property.values.map((value) => value.content);
479
+ }
480
+ if (searchNestedProperties) {
481
+ for (const property2 of properties) {
482
+ if (property2.properties.length > 0) {
483
+ const nestedResult = getPropertyValuesByLabel(
484
+ property2.properties,
485
+ label,
486
+ { searchNestedProperties }
487
+ );
488
+ if (nestedResult) {
489
+ return nestedResult;
490
+ }
491
+ }
492
+ }
493
+ }
494
+ return null;
495
+ }
496
+ function getPropertyValueByLabel(properties, label, options = DEFAULT_OPTIONS) {
497
+ const { searchNestedProperties } = options;
498
+ const values = getPropertyValuesByLabel(properties, label, {
499
+ searchNestedProperties
500
+ });
501
+ if (values !== null && values.length > 0) {
502
+ return values[0];
503
+ }
504
+ if (searchNestedProperties) {
505
+ for (const property of properties) {
506
+ if (property.properties.length > 0) {
507
+ const nestedResult = getPropertyValueByLabel(
508
+ property.properties,
509
+ label,
510
+ { searchNestedProperties }
511
+ );
512
+ if (nestedResult !== null) {
513
+ return nestedResult;
514
+ }
515
+ }
516
+ }
517
+ }
518
+ return null;
519
+ }
520
+ function getAllPropertyLabels(properties, options = DEFAULT_OPTIONS) {
521
+ const { searchNestedProperties } = options;
522
+ const labels = /* @__PURE__ */ new Set();
523
+ for (const property of properties) {
524
+ labels.add(property.label);
525
+ if (property.properties.length > 0 && searchNestedProperties) {
526
+ const nestedLabels = getAllPropertyLabels(property.properties, {
527
+ searchNestedProperties: true
528
+ });
529
+ for (const label of nestedLabels) {
530
+ labels.add(label);
531
+ }
532
+ }
533
+ }
534
+ return [...labels];
535
+ }
536
+ function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
537
+ const { searchNestedProperties } = options;
538
+ const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
539
+ if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
540
+ let isFound = property.values.some(
541
+ (value) => value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"))
542
+ );
543
+ if (!isFound && searchNestedProperties) {
544
+ isFound = property.properties.some(
545
+ (property2) => filterProperties(property2, filter, { searchNestedProperties: true })
546
+ );
547
+ }
548
+ return isFound;
549
+ }
550
+ return false;
551
+ }
552
+
553
+ // src/utils/parse.ts
554
+ var websiteSchema = import_zod3.z.object({
555
+ type: import_zod3.z.enum(
556
+ [
557
+ "traditional",
558
+ "digital-collection",
559
+ "plum",
560
+ "cedar",
561
+ "elm",
562
+ "maple",
563
+ "oak",
564
+ "palm"
565
+ ],
566
+ { message: "Invalid website type" }
567
+ ),
568
+ status: import_zod3.z.enum(
569
+ ["development", "preview", "production"],
570
+ { message: "Invalid website status" }
571
+ ),
572
+ privacy: import_zod3.z.enum(
573
+ ["public", "password", "private"],
574
+ { message: "Invalid website privacy" }
575
+ )
576
+ });
577
+ var componentSchema = import_zod3.z.enum(
578
+ [
579
+ "annotated-document",
580
+ "annotated-image",
581
+ "bibliography",
582
+ "blog",
583
+ "button",
584
+ "collection",
585
+ "iiif-viewer",
586
+ "image",
587
+ "image-gallery",
588
+ "interactive-chapter-table",
589
+ "item-gallery",
590
+ "menu",
591
+ "menu-item",
592
+ "n-columns",
593
+ "n-rows",
594
+ "network-graph",
595
+ "table",
596
+ "text",
597
+ "text-image",
598
+ "timeline"
599
+ ],
600
+ { message: "Invalid component" }
601
+ );
602
+ function parseIdentification(identification) {
603
+ try {
604
+ const returnIdentification = {
605
+ label: parseStringContent(identification.label),
606
+ abbreviation: ""
607
+ };
608
+ for (const key of Object.keys(identification).filter(
609
+ (key2) => key2 !== "label"
610
+ )) {
611
+ returnIdentification[key] = parseStringContent(
612
+ identification[key]
613
+ );
614
+ }
615
+ return returnIdentification;
616
+ } catch (error) {
617
+ console.error(error);
618
+ return {
619
+ label: "",
620
+ abbreviation: ""
621
+ };
622
+ }
623
+ }
624
+ function parseLanguages(language) {
625
+ if (Array.isArray(language)) {
626
+ return language.map((lang) => parseStringContent(lang));
627
+ } else {
628
+ return [parseStringContent(language)];
629
+ }
630
+ }
631
+ function parseMetadata(metadata) {
632
+ let identification = {
633
+ label: "",
634
+ abbreviation: ""
635
+ };
636
+ if (metadata.item) {
637
+ if (metadata.item.label || metadata.item.abbreviation) {
638
+ let label = "";
639
+ let abbreviation = "";
640
+ if (metadata.item.label) {
641
+ label = parseStringContent(metadata.item.label);
642
+ }
643
+ if (metadata.item.abbreviation) {
644
+ abbreviation = parseStringContent(metadata.item.abbreviation);
645
+ }
646
+ identification = { label, abbreviation };
647
+ } else {
648
+ identification = parseIdentification(metadata.item.identification);
649
+ }
650
+ }
651
+ let projectIdentification = null;
652
+ const baseProjectIdentification = metadata.project?.identification ? parseIdentification(metadata.project.identification) : null;
653
+ if (baseProjectIdentification) {
654
+ projectIdentification = {
655
+ ...baseProjectIdentification,
656
+ website: metadata.project?.identification.website ?? null
657
+ };
658
+ }
659
+ return {
660
+ project: projectIdentification ? { identification: projectIdentification } : null,
661
+ item: metadata.item ? {
662
+ identification,
663
+ category: metadata.item.category,
664
+ type: metadata.item.type,
665
+ maxLength: metadata.item.maxLength ?? null
666
+ } : null,
667
+ dataset: parseStringContent(metadata.dataset),
668
+ publisher: parseStringContent(metadata.publisher),
669
+ languages: parseLanguages(metadata.language),
670
+ identifier: parseStringContent(metadata.identifier),
671
+ description: parseStringContent(metadata.description)
672
+ };
673
+ }
674
+ function parseContextItem(contextItem) {
675
+ return {
676
+ uuid: contextItem.uuid,
677
+ publicationDateTime: contextItem.publicationDateTime != null ? new Date(contextItem.publicationDateTime) : null,
678
+ number: contextItem.n,
679
+ content: parseFakeString(contextItem.content)
680
+ };
681
+ }
682
+ function parseContext(context) {
683
+ const contexts = Array.isArray(context.context) ? context.context : [context.context];
684
+ const returnContexts = {
685
+ nodes: contexts.map((context2) => {
686
+ const spatialUnit = [];
687
+ if ("spatialUnit" in context2 && context2.spatialUnit) {
688
+ const contextsToParse = Array.isArray(context2.spatialUnit) ? context2.spatialUnit : [context2.spatialUnit];
689
+ for (const contextItem of contextsToParse) {
690
+ spatialUnit.push(parseContextItem(contextItem));
691
+ }
692
+ }
693
+ return {
694
+ tree: parseContextItem(context2.tree),
695
+ project: parseContextItem(context2.project),
696
+ spatialUnit
697
+ };
698
+ }),
699
+ displayPath: context.displayPath
700
+ };
701
+ return returnContexts;
702
+ }
703
+ function parseLicense(license) {
704
+ if (typeof license.license === "string") {
705
+ return null;
706
+ }
707
+ return {
708
+ content: license.license.content,
709
+ url: license.license.target
710
+ };
711
+ }
712
+ function parsePersons(persons) {
713
+ const returnPersons = [];
714
+ for (const person of persons) {
715
+ returnPersons.push({
716
+ uuid: person.uuid,
717
+ publicationDateTime: person.publicationDateTime != null ? new Date(person.publicationDateTime) : null,
718
+ type: person.type ?? null,
719
+ date: person.date != null ? new Date(person.date) : null,
720
+ identification: person.identification ? parseIdentification(person.identification) : null,
721
+ content: person.content != null ? parseFakeString(person.content) : null
722
+ });
723
+ }
724
+ return returnPersons;
725
+ }
726
+ function parseLink(linkRaw) {
727
+ const links = "resource" in linkRaw ? linkRaw.resource : "concept" in linkRaw ? linkRaw.concept : "set" in linkRaw ? linkRaw.set : "tree" in linkRaw ? linkRaw.tree : "person" in linkRaw ? linkRaw.person : "bibliography" in linkRaw ? linkRaw.bibliography : "epigraphicUnit" in linkRaw ? linkRaw.epigraphicUnit : null;
728
+ if (!links) {
729
+ throw new Error(
730
+ `Invalid link provided: ${JSON.stringify(linkRaw, null, 2)}`
731
+ );
732
+ }
733
+ const linksToParse = Array.isArray(links) ? links : [links];
734
+ const returnLinks = [];
735
+ for (const link of linksToParse) {
736
+ const returnLink = {
737
+ category: "resource" in linkRaw ? "resource" : "concept" in linkRaw ? "concept" : "set" in linkRaw ? "set" : "person" in linkRaw ? "person" : "tree" in linkRaw ? "tree" : "bibliography" in linkRaw ? "bibliography" : "epigraphicUnit" in linkRaw ? "epigraphicUnit" : null,
738
+ content: "content" in link ? link.content != null ? parseFakeString(link.content) : null : null,
739
+ uuid: link.uuid,
740
+ type: link.type ?? null,
741
+ identification: link.identification ? parseIdentification(link.identification) : null,
742
+ image: null,
743
+ bibliographies: "bibliography" in linkRaw ? parseBibliographies(
744
+ Array.isArray(linkRaw.bibliography) ? linkRaw.bibliography : [linkRaw.bibliography]
745
+ ) : null,
746
+ publicationDateTime: link.publicationDateTime != null ? new Date(link.publicationDateTime) : null
747
+ };
748
+ if ("height" in link && link.height != null && link.width != null && link.heightPreview != null && link.widthPreview != null) {
749
+ returnLink.image = {
750
+ isInline: link.rend === "inline",
751
+ heightPreview: link.heightPreview,
752
+ widthPreview: link.widthPreview,
753
+ height: link.height,
754
+ width: link.width
755
+ };
756
+ }
757
+ returnLinks.push(returnLink);
758
+ }
759
+ return returnLinks;
760
+ }
761
+ function parseLinks(links) {
762
+ const returnLinks = [];
763
+ for (const link of links) {
764
+ returnLinks.push(...parseLink(link));
765
+ }
766
+ return returnLinks;
767
+ }
768
+ function parseDocument(document, language = "eng") {
769
+ let returnString = "";
770
+ const footnotes = [];
771
+ const documentWithLanguage = Array.isArray(document) ? document.find((doc) => doc.lang === language) : document;
772
+ if (typeof documentWithLanguage.string === "string" || typeof documentWithLanguage.string === "number" || typeof documentWithLanguage.string === "boolean") {
773
+ returnString += parseEmailAndUrl(
774
+ parseFakeString(documentWithLanguage.string)
775
+ );
776
+ } else {
777
+ const documentItems = Array.isArray(documentWithLanguage.string) ? documentWithLanguage.string : [documentWithLanguage.string];
778
+ for (const item of documentItems) {
779
+ returnString += parseStringDocumentItem(item, footnotes);
780
+ }
781
+ }
782
+ returnString = trimEndLineBreaks(returnString);
783
+ return { content: returnString, footnotes };
784
+ }
785
+ function parseImage(image) {
786
+ return {
787
+ publicationDateTime: image.publicationDateTime != null ? new Date(image.publicationDateTime) : null,
788
+ identification: image.identification ? parseIdentification(image.identification) : null,
789
+ url: image.href ?? (image.htmlImgSrcPrefix == null && image.content != null ? parseFakeString(image.content) : null),
790
+ htmlPrefix: image.htmlImgSrcPrefix ?? null,
791
+ content: image.htmlImgSrcPrefix != null && image.content != null ? parseFakeString(image.content) : null
792
+ };
793
+ }
794
+ function parseNotes(notes, language = "eng") {
795
+ const returnNotes = [];
796
+ for (const note of notes) {
797
+ if (typeof note === "string") {
798
+ if (note === "") {
799
+ continue;
800
+ }
801
+ returnNotes.push({
802
+ number: -1,
803
+ title: null,
804
+ content: note
805
+ });
806
+ continue;
807
+ }
808
+ let content = "";
809
+ const notesToParse = Array.isArray(note.content) ? note.content : [note.content];
810
+ let noteWithLanguage = notesToParse.find((item) => item.lang === language);
811
+ if (!noteWithLanguage) {
812
+ noteWithLanguage = notesToParse[0];
813
+ if (!noteWithLanguage) {
814
+ throw new Error(
815
+ `Note does not have a valid content item: ${JSON.stringify(
816
+ note,
817
+ null,
818
+ 2
819
+ )}`
820
+ );
821
+ }
822
+ }
823
+ if (typeof noteWithLanguage.string === "string" || typeof noteWithLanguage.string === "number" || typeof noteWithLanguage.string === "boolean") {
824
+ content = parseEmailAndUrl(parseFakeString(noteWithLanguage.string));
825
+ } else {
826
+ content = parseEmailAndUrl(parseDocument(noteWithLanguage).content);
827
+ }
828
+ returnNotes.push({
829
+ number: note.noteNo,
830
+ title: noteWithLanguage.title != null ? parseFakeString(noteWithLanguage.title) : null,
831
+ content
832
+ });
833
+ }
834
+ return returnNotes;
835
+ }
836
+ function parseCoordinates(coordinates) {
837
+ return {
838
+ latitude: coordinates.latitude,
839
+ longitude: coordinates.longitude,
840
+ type: coordinates.coord?.coordType ?? null,
841
+ label: coordinates.coord?.coordLabel != null ? parseFakeString(coordinates.coord.coordLabel) : null
842
+ };
843
+ }
844
+ function parseObservation(observation) {
845
+ return {
846
+ number: observation.observationNo,
847
+ date: observation.date != null ? new Date(observation.date) : null,
848
+ observers: observation.observers != null ? parseFakeString(observation.observers).split(";").map((observer) => observer.trim()) : [],
849
+ notes: observation.notes ? parseNotes(
850
+ Array.isArray(observation.notes.note) ? observation.notes.note : [observation.notes.note]
851
+ ) : [],
852
+ links: observation.links ? parseLinks(
853
+ Array.isArray(observation.links) ? observation.links : [observation.links]
854
+ ) : [],
855
+ properties: observation.properties ? parseProperties(
856
+ Array.isArray(observation.properties.property) ? observation.properties.property : [observation.properties.property]
857
+ ) : []
858
+ };
859
+ }
860
+ function parseObservations(observations) {
861
+ const returnObservations = [];
862
+ for (const observation of observations) {
863
+ returnObservations.push(parseObservation(observation));
864
+ }
865
+ return returnObservations;
866
+ }
867
+ function parseEvents(events) {
868
+ const returnEvents = [];
869
+ for (const event of events) {
870
+ returnEvents.push({
871
+ date: event.dateTime != null ? new Date(event.dateTime) : null,
872
+ label: parseStringContent(event.label),
873
+ agent: event.agent ? {
874
+ uuid: event.agent.uuid,
875
+ content: parseFakeString(event.agent.content)
876
+ } : null
877
+ });
878
+ }
879
+ return returnEvents;
880
+ }
881
+ function parseProperties(properties, language = "eng") {
882
+ const returnProperties = [];
883
+ for (const property of properties) {
884
+ const valuesToParse = "value" in property && property.value ? Array.isArray(property.value) ? property.value : [property.value] : [];
885
+ const values = valuesToParse.map((value) => ({
886
+ content: parseStringContent(value),
887
+ type: value.type,
888
+ category: value.category !== "value" ? value.category ?? null : null,
889
+ uuid: value.uuid ?? null,
890
+ publicationDateTime: value.publicationDateTime != null ? new Date(value.publicationDateTime) : null
891
+ }));
892
+ returnProperties.push({
893
+ label: parseStringContent(property.label, language).replace(/\s*\.{3}$/, "").trim(),
894
+ values,
895
+ comment: property.comment != null ? parseFakeString(property.comment) : null,
896
+ properties: property.property ? parseProperties(
897
+ Array.isArray(property.property) ? property.property : [property.property]
898
+ ) : []
899
+ });
900
+ }
901
+ return returnProperties;
902
+ }
903
+ function parseInterpretations(interpretations) {
904
+ const returnInterpretations = [];
905
+ for (const interpretation of interpretations) {
906
+ returnInterpretations.push({
907
+ date: new Date(interpretation.date),
908
+ number: interpretation.interpretationNo,
909
+ properties: interpretation.properties ? parseProperties(
910
+ Array.isArray(interpretation.properties.property) ? interpretation.properties.property : [interpretation.properties.property]
911
+ ) : []
912
+ });
913
+ }
914
+ return returnInterpretations;
915
+ }
916
+ function parseImageMap(imageMap) {
917
+ const returnImageMap = {
918
+ area: [],
919
+ width: imageMap.width,
920
+ height: imageMap.height
921
+ };
922
+ const imageMapAreasToParse = Array.isArray(imageMap.area) ? imageMap.area : [imageMap.area];
923
+ for (const area of imageMapAreasToParse) {
924
+ returnImageMap.area.push({
925
+ uuid: area.uuid,
926
+ publicationDateTime: area.publicationDateTime != null ? new Date(area.publicationDateTime) : null,
927
+ type: area.type,
928
+ title: parseFakeString(area.title),
929
+ shape: area.shape === "rect" ? "rectangle" : "polygon",
930
+ coords: area.coords.split(",").map((coord) => Number.parseInt(coord))
931
+ });
932
+ }
933
+ return returnImageMap;
934
+ }
935
+ function parsePeriod(period) {
936
+ return {
937
+ uuid: period.uuid,
938
+ publicationDateTime: period.publicationDateTime != null ? new Date(period.publicationDateTime) : null,
939
+ type: period.type ?? null,
940
+ number: period.n ?? null,
941
+ identification: parseIdentification(period.identification),
942
+ description: period.description ? parseStringContent(period.description) : null
943
+ };
944
+ }
945
+ function parsePeriods(periods) {
946
+ const returnPeriods = [];
947
+ for (const period of periods) {
948
+ returnPeriods.push(parsePeriod(period));
949
+ }
950
+ return returnPeriods;
951
+ }
952
+ function parseBibliography(bibliography) {
953
+ let resource = null;
954
+ if (bibliography.source?.resource) {
955
+ resource = {
956
+ uuid: bibliography.source.resource.uuid,
957
+ publicationDateTime: bibliography.source.resource.publicationDateTime ? new Date(bibliography.source.resource.publicationDateTime) : null,
958
+ type: bibliography.source.resource.type,
959
+ identification: parseIdentification(
960
+ bibliography.source.resource.identification
961
+ )
962
+ };
963
+ }
964
+ return {
965
+ uuid: bibliography.uuid,
966
+ publicationDateTime: bibliography.publicationDateTime != null ? new Date(bibliography.publicationDateTime) : null,
967
+ type: bibliography.type ?? null,
968
+ number: bibliography.n ?? null,
969
+ identification: bibliography.identification ? parseIdentification(bibliography.identification) : null,
970
+ projectIdentification: bibliography.project?.identification ? parseIdentification(bibliography.project.identification) : null,
971
+ context: bibliography.context ? parseContext(bibliography.context) : null,
972
+ citation: {
973
+ format: bibliography.citationFormat ?? null,
974
+ short: bibliography.citationFormatSpan ? parseFakeString(
975
+ "default:span" in bibliography.citationFormatSpan ? bibliography.citationFormatSpan["default:span"].content : bibliography.citationFormatSpan.span.content
976
+ ) : null,
977
+ long: bibliography.referenceFormatDiv ? parseFakeString(
978
+ "default:div" in bibliography.referenceFormatDiv ? bibliography.referenceFormatDiv["default:div"]["default:div"].content : bibliography.referenceFormatDiv.div.div.content
979
+ ) : null
980
+ },
981
+ publicationInfo: {
982
+ publishers: bibliography.publicationInfo?.publishers ? parsePersons(
983
+ Array.isArray(
984
+ bibliography.publicationInfo.publishers.publishers.person
985
+ ) ? bibliography.publicationInfo.publishers.publishers.person : [bibliography.publicationInfo.publishers.publishers.person]
986
+ ) : [],
987
+ startDate: bibliography.publicationInfo?.startDate ? new Date(
988
+ bibliography.publicationInfo.startDate.year,
989
+ bibliography.publicationInfo.startDate.month,
990
+ bibliography.publicationInfo.startDate.day
991
+ ) : null
992
+ },
993
+ entryInfo: bibliography.entryInfo ? {
994
+ startIssue: parseFakeString(bibliography.entryInfo.startIssue),
995
+ startVolume: parseFakeString(bibliography.entryInfo.startVolume)
996
+ } : null,
997
+ source: {
998
+ resource,
999
+ documentUrl: bibliography.sourceDocument ? `https://ochre.lib.uchicago.edu/ochre?uuid=${bibliography.sourceDocument.uuid}&load` : null
1000
+ },
1001
+ authors: bibliography.authors ? parsePersons(
1002
+ Array.isArray(bibliography.authors.person) ? bibliography.authors.person : [bibliography.authors.person]
1003
+ ) : [],
1004
+ properties: bibliography.properties ? parseProperties(
1005
+ Array.isArray(bibliography.properties.property) ? bibliography.properties.property : [bibliography.properties.property]
1006
+ ) : []
1007
+ };
1008
+ }
1009
+ function parseBibliographies(bibliographies) {
1010
+ const returnBibliographies = [];
1011
+ for (const bibliography of bibliographies) {
1012
+ returnBibliographies.push(parseBibliography(bibliography));
1013
+ }
1014
+ return returnBibliographies;
1015
+ }
1016
+ function parseTree(tree) {
1017
+ let creators = [];
1018
+ if (tree.creators) {
1019
+ creators = parsePersons(
1020
+ Array.isArray(tree.creators.creator) ? tree.creators.creator : [tree.creators.creator]
1021
+ );
1022
+ }
1023
+ let date = null;
1024
+ if (tree.date != null) {
1025
+ date = new Date(tree.date);
1026
+ }
1027
+ let resources = [];
1028
+ let spatialUnits = [];
1029
+ let concepts = [];
1030
+ let periods = [];
1031
+ let bibliographies = [];
1032
+ if (typeof tree.items !== "string" && "resource" in tree.items) {
1033
+ resources = parseResources(
1034
+ Array.isArray(tree.items.resource) ? tree.items.resource : [tree.items.resource]
1035
+ );
1036
+ }
1037
+ if (typeof tree.items !== "string" && "spatialUnit" in tree.items) {
1038
+ spatialUnits = parseSpatialUnits(
1039
+ Array.isArray(tree.items.spatialUnit) ? tree.items.spatialUnit : [tree.items.spatialUnit]
1040
+ );
1041
+ }
1042
+ if (typeof tree.items !== "string" && "concept" in tree.items) {
1043
+ concepts = parseConcepts(
1044
+ Array.isArray(tree.items.concept) ? tree.items.concept : [tree.items.concept]
1045
+ );
1046
+ }
1047
+ if (typeof tree.items !== "string" && "period" in tree.items) {
1048
+ periods = parsePeriods(
1049
+ Array.isArray(tree.items.period) ? tree.items.period : [tree.items.period]
1050
+ );
1051
+ }
1052
+ if (typeof tree.items !== "string" && "bibliography" in tree.items) {
1053
+ bibliographies = parseBibliographies(
1054
+ Array.isArray(tree.items.bibliography) ? tree.items.bibliography : [tree.items.bibliography]
1055
+ );
1056
+ }
1057
+ const returnTree = {
1058
+ uuid: tree.uuid,
1059
+ category: "tree",
1060
+ publicationDateTime: new Date(tree.publicationDateTime),
1061
+ identification: parseIdentification(tree.identification),
1062
+ creators,
1063
+ license: parseLicense(tree.availability),
1064
+ date,
1065
+ type: tree.type,
1066
+ number: tree.n,
1067
+ items: {
1068
+ resources,
1069
+ spatialUnits,
1070
+ concepts,
1071
+ periods,
1072
+ bibliographies
1073
+ },
1074
+ properties: tree.properties ? parseProperties(
1075
+ Array.isArray(tree.properties.property) ? tree.properties.property : [tree.properties.property]
1076
+ ) : []
1077
+ };
1078
+ return returnTree;
1079
+ }
1080
+ function parseSet(set) {
1081
+ let resources = [];
1082
+ let spatialUnits = [];
1083
+ let concepts = [];
1084
+ let periods = [];
1085
+ let bibliographies = [];
1086
+ if (typeof set.items !== "string" && "resource" in set.items) {
1087
+ resources = parseResources(
1088
+ Array.isArray(set.items.resource) ? set.items.resource : [set.items.resource],
1089
+ true
1090
+ );
1091
+ }
1092
+ if (typeof set.items !== "string" && "spatialUnit" in set.items) {
1093
+ spatialUnits = parseSpatialUnits(
1094
+ Array.isArray(set.items.spatialUnit) ? set.items.spatialUnit : [set.items.spatialUnit],
1095
+ true
1096
+ );
1097
+ }
1098
+ if (typeof set.items !== "string" && "concept" in set.items) {
1099
+ concepts = parseConcepts(
1100
+ Array.isArray(set.items.concept) ? set.items.concept : [set.items.concept],
1101
+ true
1102
+ );
1103
+ }
1104
+ if (typeof set.items !== "string" && "period" in set.items) {
1105
+ periods = parsePeriods(
1106
+ Array.isArray(set.items.period) ? set.items.period : [set.items.period]
1107
+ );
1108
+ }
1109
+ if (typeof set.items !== "string" && "bibliography" in set.items) {
1110
+ bibliographies = parseBibliographies(
1111
+ Array.isArray(set.items.bibliography) ? set.items.bibliography : [set.items.bibliography]
1112
+ );
1113
+ }
1114
+ return {
1115
+ uuid: set.uuid,
1116
+ category: "set",
1117
+ publicationDateTime: set.publicationDateTime ? new Date(set.publicationDateTime) : null,
1118
+ date: set.date != null ? new Date(set.date) : null,
1119
+ license: parseLicense(set.availability),
1120
+ identification: parseIdentification(set.identification),
1121
+ isSuppressingBlanks: set.suppressBlanks ?? false,
1122
+ description: set.description ? parseStringContent(set.description) : "",
1123
+ creators: set.creators ? parsePersons(
1124
+ Array.isArray(set.creators.creator) ? set.creators.creator : [set.creators.creator]
1125
+ ) : [],
1126
+ type: set.type,
1127
+ number: set.n,
1128
+ items: {
1129
+ resources,
1130
+ spatialUnits,
1131
+ concepts,
1132
+ periods,
1133
+ bibliographies
1134
+ }
1135
+ };
1136
+ }
1137
+ function parseResource(resource, isNested = false) {
1138
+ const returnResource = {
1139
+ uuid: resource.uuid,
1140
+ category: "resource",
1141
+ publicationDateTime: resource.publicationDateTime ? new Date(resource.publicationDateTime) : null,
1142
+ type: resource.type,
1143
+ number: resource.n,
1144
+ format: resource.format ?? null,
1145
+ context: "context" in resource && resource.context ? parseContext(resource.context) : null,
1146
+ license: "availability" in resource && resource.availability ? parseLicense(resource.availability) : null,
1147
+ copyright: "copyright" in resource && resource.copyright != null ? parseFakeString(resource.copyright) : null,
1148
+ identification: parseIdentification(resource.identification),
1149
+ date: resource.date != null ? new Date(resource.date) : null,
1150
+ image: resource.image ? parseImage(resource.image) : null,
1151
+ creators: resource.creators ? parsePersons(
1152
+ Array.isArray(resource.creators.creator) ? resource.creators.creator : [resource.creators.creator]
1153
+ ) : [],
1154
+ notes: (
1155
+ // TODO: Remove this check once the { rend: "splitNotes" } issue is fixed
1156
+ resource.notes && "note" in resource.notes ? parseNotes(
1157
+ Array.isArray(resource.notes.note) ? resource.notes.note : [resource.notes.note]
1158
+ ) : []
1159
+ ),
1160
+ description: resource.description ? parseStringContent(resource.description) : "",
1161
+ document: resource.document ? parseDocument(resource.document.content) : null,
1162
+ href: resource.href ?? null,
1163
+ imageMap: resource.imagemap ? parseImageMap(resource.imagemap) : null,
1164
+ periods: resource.periods ? parsePeriods(
1165
+ Array.isArray(resource.periods.period) ? resource.periods.period : [resource.periods.period]
1166
+ ) : [],
1167
+ links: resource.links ? parseLinks(
1168
+ Array.isArray(resource.links) ? resource.links : [resource.links]
1169
+ ) : [],
1170
+ reverseLinks: resource.reverseLinks ? parseLinks(
1171
+ Array.isArray(resource.reverseLinks) ? resource.reverseLinks : [resource.reverseLinks]
1172
+ ) : [],
1173
+ properties: resource.properties ? parseProperties(
1174
+ Array.isArray(resource.properties.property) ? resource.properties.property : [resource.properties.property]
1175
+ ) : [],
1176
+ citedBibliographies: resource.citedBibliography ? parseBibliographies(
1177
+ Array.isArray(resource.citedBibliography.reference) ? resource.citedBibliography.reference : [resource.citedBibliography.reference]
1178
+ ) : [],
1179
+ resources: resource.resource ? parseResources(
1180
+ Array.isArray(resource.resource) ? resource.resource : [resource.resource],
1181
+ true
1182
+ ) : []
1183
+ };
1184
+ if (isNested) {
1185
+ const returnNestedResource = {
1186
+ ...returnResource,
1187
+ publicationDateTime: null,
1188
+ context: null,
1189
+ license: null,
1190
+ copyright: null
1191
+ };
1192
+ delete returnNestedResource.publicationDateTime;
1193
+ delete returnNestedResource.license;
1194
+ delete returnNestedResource.copyright;
1195
+ return returnNestedResource;
1196
+ }
1197
+ return returnResource;
1198
+ }
1199
+ function parseResources(resources, isNested = false) {
1200
+ const returnResources = [];
1201
+ const resourcesToParse = Array.isArray(resources) ? resources : [resources];
1202
+ for (const resource of resourcesToParse) {
1203
+ returnResources.push(parseResource(resource, isNested));
1204
+ }
1205
+ return returnResources;
1206
+ }
1207
+ function parseSpatialUnit(spatialUnit, isNested = false) {
1208
+ const returnSpatialUnit = {
1209
+ uuid: spatialUnit.uuid,
1210
+ category: "spatialUnit",
1211
+ publicationDateTime: spatialUnit.publicationDateTime != null ? new Date(spatialUnit.publicationDateTime) : null,
1212
+ type: spatialUnit.type,
1213
+ number: spatialUnit.n,
1214
+ context: "context" in spatialUnit && spatialUnit.context ? parseContext(spatialUnit.context) : null,
1215
+ license: "availability" in spatialUnit && spatialUnit.availability ? parseLicense(spatialUnit.availability) : null,
1216
+ identification: parseIdentification(spatialUnit.identification),
1217
+ image: spatialUnit.image ? parseImage(spatialUnit.image) : null,
1218
+ description: spatialUnit.description ? parseStringContent(spatialUnit.description) : "",
1219
+ coordinates: spatialUnit.coordinates ? parseCoordinates(spatialUnit.coordinates) : null,
1220
+ observations: "observations" in spatialUnit && spatialUnit.observations ? parseObservations(
1221
+ Array.isArray(spatialUnit.observations.observation) ? spatialUnit.observations.observation : [spatialUnit.observations.observation]
1222
+ ) : spatialUnit.observation ? [parseObservation(spatialUnit.observation)] : [],
1223
+ events: "events" in spatialUnit && spatialUnit.events ? parseEvents(
1224
+ Array.isArray(spatialUnit.events.event) ? spatialUnit.events.event : [spatialUnit.events.event]
1225
+ ) : []
1226
+ };
1227
+ if (isNested) {
1228
+ const returnNestedSpatialUnit = {
1229
+ ...returnSpatialUnit,
1230
+ publicationDateTime: null,
1231
+ license: null,
1232
+ properties: "properties" in spatialUnit && spatialUnit.properties ? parseProperties(
1233
+ Array.isArray(spatialUnit.properties.property) ? spatialUnit.properties.property : [spatialUnit.properties.property]
1234
+ ) : []
1235
+ };
1236
+ delete returnNestedSpatialUnit.publicationDateTime;
1237
+ delete returnNestedSpatialUnit.license;
1238
+ return returnNestedSpatialUnit;
1239
+ }
1240
+ return returnSpatialUnit;
1241
+ }
1242
+ function parseSpatialUnits(spatialUnits, isNested = false) {
1243
+ const returnSpatialUnits = [];
1244
+ const spatialUnitsToParse = Array.isArray(spatialUnits) ? spatialUnits : [spatialUnits];
1245
+ for (const spatialUnit of spatialUnitsToParse) {
1246
+ returnSpatialUnits.push(
1247
+ parseSpatialUnit(spatialUnit, isNested)
1248
+ );
1249
+ }
1250
+ return returnSpatialUnits;
1251
+ }
1252
+ function parseConcept(concept, isNested = false) {
1253
+ const returnConcept = {
1254
+ uuid: concept.uuid,
1255
+ category: "concept",
1256
+ publicationDateTime: concept.publicationDateTime ? new Date(concept.publicationDateTime) : null,
1257
+ number: concept.n,
1258
+ license: "availability" in concept && concept.availability ? parseLicense(concept.availability) : null,
1259
+ context: "context" in concept && concept.context ? parseContext(concept.context) : null,
1260
+ identification: parseIdentification(concept.identification),
1261
+ interpretations: parseInterpretations(
1262
+ Array.isArray(concept.interpretations.interpretation) ? concept.interpretations.interpretation : [concept.interpretations.interpretation]
1263
+ )
1264
+ };
1265
+ if (isNested) {
1266
+ const returnNestedConcept = {
1267
+ ...returnConcept,
1268
+ publicationDateTime: null,
1269
+ context: null,
1270
+ license: null
1271
+ };
1272
+ delete returnNestedConcept.publicationDateTime;
1273
+ delete returnNestedConcept.license;
1274
+ return returnNestedConcept;
1275
+ }
1276
+ return returnConcept;
1277
+ }
1278
+ var parseWebpageResources = async (webpageResources, type) => {
1279
+ const returnElements = [];
1280
+ for (const resource of webpageResources) {
1281
+ const resourceProperties = resource.properties ? parseProperties(
1282
+ Array.isArray(resource.properties.property) ? resource.properties.property : [resource.properties.property]
1283
+ ) : [];
1284
+ const resourceProperty = resourceProperties.find(
1285
+ (property) => property.label === "presentation" && property.values[0].content === type
1286
+ );
1287
+ if (!resourceProperty) continue;
1288
+ if (type === "element") {
1289
+ const element = await parseWebElement(
1290
+ resource,
1291
+ resourceProperty.properties
1292
+ );
1293
+ returnElements.push(
1294
+ element
1295
+ );
1296
+ } else {
1297
+ const webpage = await parseWebpage(resource);
1298
+ if (webpage) {
1299
+ returnElements.push(
1300
+ webpage
1301
+ );
1302
+ }
1303
+ }
1304
+ }
1305
+ return returnElements;
1306
+ };
1307
+ function parseConcepts(concepts, isNested = false) {
1308
+ const returnConcepts = [];
1309
+ const conceptsToParse = Array.isArray(concepts) ? concepts : [concepts];
1310
+ for (const concept of conceptsToParse) {
1311
+ returnConcepts.push(parseConcept(concept, isNested));
1312
+ }
1313
+ return returnConcepts;
1314
+ }
1315
+ async function parseWebElementProperties(componentProperty, elementResource) {
1316
+ const componentName = componentSchema.parse(
1317
+ componentProperty.values[0].content
1318
+ );
1319
+ const properties = {
1320
+ component: componentName
1321
+ };
1322
+ const links = elementResource.links ? parseLinks(
1323
+ Array.isArray(elementResource.links) ? elementResource.links : [elementResource.links]
1324
+ ) : [];
1325
+ const imageLink = links.find((link) => link.type === "image");
1326
+ let document = elementResource.document ? parseDocument(elementResource.document.content) : null;
1327
+ if (document === null) {
1328
+ const documentLink = links.find((link) => link.type === "internalDocument");
1329
+ if (documentLink) {
1330
+ const documentResource = await fetchResource(documentLink.uuid);
1331
+ if (documentResource === null) {
1332
+ throw new Error("Failed to fetch OCHRE data");
1333
+ }
1334
+ document = documentResource.resource.document;
1335
+ }
1336
+ }
1337
+ switch (componentName) {
1338
+ case "annotated-document": {
1339
+ if (!document) {
1340
+ throw new Error(
1341
+ `Document not found for the following component: \u201C${componentName}\u201D`
1342
+ );
1343
+ }
1344
+ properties.document = document;
1345
+ break;
1346
+ }
1347
+ case "annotated-image": {
1348
+ if (!imageLink) {
1349
+ throw new Error(
1350
+ `Image link not found for the following component: \u201C${componentName}\u201D`
1351
+ );
1352
+ }
1353
+ let isSearchable = getPropertyValueByLabel(
1354
+ componentProperty.properties,
1355
+ "is-searchable"
1356
+ ) === "Yes";
1357
+ if (!isSearchable) {
1358
+ isSearchable = false;
1359
+ }
1360
+ properties.imageUuid = imageLink.uuid;
1361
+ properties.isSearchable = isSearchable;
1362
+ break;
1363
+ }
1364
+ case "bibliography": {
1365
+ const bibliographyLink = links.find(
1366
+ (link) => link.category === "bibliography"
1367
+ );
1368
+ if (!bibliographyLink) {
1369
+ throw new Error(
1370
+ `Bibliography link not found for the following component: \u201C${componentName}\u201D`
1371
+ );
1372
+ }
1373
+ if (!bibliographyLink.bibliographies) {
1374
+ throw new Error(
1375
+ `Bibliography not found for the following component: \u201C${componentName}\u201D`
1376
+ );
1377
+ }
1378
+ let layout = getPropertyValueByLabel(
1379
+ componentProperty.properties,
1380
+ "layout"
1381
+ );
1382
+ if (layout === null) {
1383
+ layout = "long";
1384
+ }
1385
+ properties.bibliographies = bibliographyLink.bibliographies;
1386
+ properties.layout = layout;
1387
+ break;
1388
+ }
1389
+ case "blog": {
1390
+ const blogLink = links.find((link) => link.category === "tree");
1391
+ if (!blogLink) {
1392
+ throw new Error(
1393
+ `Blog link not found for the following component: \u201C${componentName}\u201D`
1394
+ );
1395
+ }
1396
+ properties.blogId = blogLink.uuid;
1397
+ break;
1398
+ }
1399
+ case "button": {
1400
+ let isExternal = false;
1401
+ let href = getPropertyValueByLabel(
1402
+ componentProperty.properties,
1403
+ "navigate-to"
1404
+ );
1405
+ if (href === null) {
1406
+ href = getPropertyValueByLabel(componentProperty.properties, "link-to");
1407
+ if (href === null) {
1408
+ throw new Error(
1409
+ `Properties \u201Cnavigate-to\u201D or \u201Clink-to\u201D not found for the following component: \u201C${componentName}\u201D`
1410
+ );
1411
+ } else {
1412
+ isExternal = true;
1413
+ }
1414
+ }
1415
+ properties.href = href;
1416
+ properties.isExternal = isExternal;
1417
+ properties.label = parseStringContent(
1418
+ elementResource.identification.label
1419
+ );
1420
+ break;
1421
+ }
1422
+ case "collection": {
1423
+ let variant = getPropertyValueByLabel(
1424
+ componentProperty.properties,
1425
+ "variant"
1426
+ );
1427
+ if (variant === null) {
1428
+ variant = "full";
1429
+ }
1430
+ let layout = getPropertyValueByLabel(
1431
+ componentProperty.properties,
1432
+ "layout"
1433
+ );
1434
+ if (layout === null) {
1435
+ layout = "image-start";
1436
+ }
1437
+ const collectionLink = links.find((link) => link.category === "set");
1438
+ if (!collectionLink) {
1439
+ throw new Error(
1440
+ `Collection link not found for the following component: \u201C${componentName}\u201D`
1441
+ );
1442
+ }
1443
+ properties.variant = variant;
1444
+ properties.layout = layout;
1445
+ properties.collectionId = collectionLink.uuid;
1446
+ break;
1447
+ }
1448
+ case "iiif-viewer": {
1449
+ const manifestLink = links.find((link) => link.type === "IIIF");
1450
+ if (!manifestLink) {
1451
+ throw new Error(
1452
+ `Manifest link not found for the following component: \u201C${componentName}\u201D`
1453
+ );
1454
+ }
1455
+ properties.IIIFId = manifestLink.uuid;
1456
+ break;
1457
+ }
1458
+ case "image": {
1459
+ if (!imageLink) {
1460
+ throw new Error(
1461
+ `Image link not found for the following component: \u201C${componentName}\u201D`
1462
+ );
1463
+ }
1464
+ properties.image = {
1465
+ url: `https://ochre.lib.uchicago.edu/ochre?uuid=${imageLink.uuid}&load`,
1466
+ label: imageLink.identification?.label ?? null,
1467
+ width: imageLink.image?.width ?? 0,
1468
+ height: imageLink.image?.height ?? 0
1469
+ };
1470
+ break;
1471
+ }
1472
+ case "image-gallery": {
1473
+ const galleryLink = links.find((link) => link.category === "tree");
1474
+ if (!galleryLink) {
1475
+ throw new Error(
1476
+ `Image gallery link not found for the following component: \u201C${componentName}\u201D`
1477
+ );
1478
+ }
1479
+ properties.galleryId = galleryLink.uuid;
1480
+ break;
1481
+ }
1482
+ case "interactive-chapter-table": {
1483
+ break;
1484
+ }
1485
+ case "item-gallery": {
1486
+ const galleryLink = links.find((link) => link.category === "tree");
1487
+ if (!galleryLink) {
1488
+ throw new Error(
1489
+ `Item gallery link not found for the following component: \u201C${componentName}\u201D`
1490
+ );
1491
+ }
1492
+ properties.galleryId = galleryLink.uuid;
1493
+ break;
1494
+ }
1495
+ case "menu": {
1496
+ break;
1497
+ }
1498
+ case "menu-item": {
1499
+ break;
1500
+ }
1501
+ case "n-columns": {
1502
+ const subElements = elementResource.resource ? await parseWebpageResources(
1503
+ Array.isArray(elementResource.resource) ? elementResource.resource : [elementResource.resource],
1504
+ "element"
1505
+ ) : [];
1506
+ properties.columns = subElements;
1507
+ break;
1508
+ }
1509
+ case "n-rows": {
1510
+ const subElements = elementResource.resource ? await parseWebpageResources(
1511
+ Array.isArray(elementResource.resource) ? elementResource.resource : [elementResource.resource],
1512
+ "element"
1513
+ ) : [];
1514
+ properties.rows = subElements;
1515
+ break;
1516
+ }
1517
+ case "network-graph": {
1518
+ break;
1519
+ }
1520
+ case "table": {
1521
+ const tableLink = links.find((link) => link.category === "set");
1522
+ if (!tableLink) {
1523
+ throw new Error(
1524
+ `Table link not found for the following component: \u201C${componentName}\u201D`
1525
+ );
1526
+ }
1527
+ properties.tableId = tableLink.uuid;
1528
+ break;
1529
+ }
1530
+ case "text": {
1531
+ if (!document) {
1532
+ throw new Error(
1533
+ `Document not found for the following component: \u201C${componentName}\u201D`
1534
+ );
1535
+ }
1536
+ let variant = getPropertyValueByLabel(
1537
+ componentProperty.properties,
1538
+ "variant"
1539
+ );
1540
+ if (variant === null) {
1541
+ variant = "block";
1542
+ }
1543
+ properties.variant = variant;
1544
+ properties.content = document.content;
1545
+ break;
1546
+ }
1547
+ case "text-image": {
1548
+ if (!document) {
1549
+ throw new Error(
1550
+ `Document not found for the following component: \u201C${componentName}\u201D`
1551
+ );
1552
+ }
1553
+ let variant = getPropertyValueByLabel(
1554
+ componentProperty.properties,
1555
+ "variant"
1556
+ );
1557
+ if (variant === null) {
1558
+ variant = "block";
1559
+ }
1560
+ let layout = getPropertyValueByLabel(
1561
+ componentProperty.properties,
1562
+ "layout"
1563
+ );
1564
+ if (layout === null) {
1565
+ layout = "image-start";
1566
+ }
1567
+ let captionLayout = getPropertyValueByLabel(
1568
+ componentProperty.properties,
1569
+ "caption-layout"
1570
+ );
1571
+ if (captionLayout === null) {
1572
+ captionLayout = "bottom";
1573
+ }
1574
+ const imageLink2 = links.find(
1575
+ (link) => link.type === "image" || link.type === "IIIF"
1576
+ );
1577
+ if (!imageLink2) {
1578
+ throw new Error(
1579
+ `Image link not found for the following component: \u201C${componentName}\u201D: ${JSON.stringify(
1580
+ links
1581
+ )}`
1582
+ );
1583
+ }
1584
+ properties.variant = variant;
1585
+ properties.layout = layout;
1586
+ properties.captionLayout = captionLayout;
1587
+ properties.content = document.content;
1588
+ properties.image = {
1589
+ url: `https://ochre.lib.uchicago.edu/ochre?uuid=${imageLink2.uuid}&preview`,
1590
+ label: imageLink2.identification?.label ?? null,
1591
+ width: imageLink2.image?.width ?? 0,
1592
+ height: imageLink2.image?.height ?? 0
1593
+ };
1594
+ properties.imageOpacity = null;
1595
+ break;
1596
+ }
1597
+ case "timeline": {
1598
+ const timelineLink = links.find((link) => link.category === "tree");
1599
+ if (!timelineLink) {
1600
+ throw new Error(
1601
+ `Timeline link not found for the following component: \u201C${componentName}\u201D`
1602
+ );
1603
+ }
1604
+ properties.timelineId = timelineLink.uuid;
1605
+ break;
1606
+ }
1607
+ default: {
1608
+ console.warn(
1609
+ `Invalid or non-implemented component name \u201C${componentName}\u201D for the following element: \u201C${parseStringContent(
1610
+ elementResource.identification.label
1611
+ )}\u201D`
1612
+ );
1613
+ }
1614
+ }
1615
+ return properties;
1616
+ }
1617
+ async function parseWebElement(elementResource, elementProperties) {
1618
+ const identification = parseIdentification(elementResource.identification);
1619
+ const componentProperty = elementProperties.find(
1620
+ (property) => property.label === "component"
1621
+ );
1622
+ if (!componentProperty) {
1623
+ throw new Error(
1624
+ `Component for element \u201C${identification.label}\u201D not found`
1625
+ );
1626
+ }
1627
+ const properties = await parseWebElementProperties(
1628
+ componentProperty,
1629
+ elementResource
1630
+ );
1631
+ const elementResourceProperties = elementResource.properties?.property ? parseProperties(
1632
+ Array.isArray(elementResource.properties.property) ? elementResource.properties.property : [elementResource.properties.property]
1633
+ ) : [];
1634
+ const cssProperties = elementResourceProperties.find(
1635
+ (property) => property.label === "presentation" && property.values[0].content === "css"
1636
+ )?.properties ?? [];
1637
+ const cssStyles = [];
1638
+ for (const property of cssProperties) {
1639
+ const cssStyle = property.values[0].content;
1640
+ cssStyles.push({ label: property.label, value: cssStyle });
1641
+ }
1642
+ return {
1643
+ uuid: elementResource.uuid,
1644
+ title: identification.label,
1645
+ cssStyles,
1646
+ ...properties
1647
+ };
1648
+ }
1649
+ async function parseWebpage(webpageResource) {
1650
+ const webpageProperties = webpageResource.properties ? parseProperties(
1651
+ Array.isArray(webpageResource.properties.property) ? webpageResource.properties.property : [webpageResource.properties.property]
1652
+ ) : [];
1653
+ if (webpageProperties.length === 0 || webpageProperties.find((property) => property.label === "presentation")?.values[0]?.content !== "page") {
1654
+ return null;
1655
+ }
1656
+ const identification = parseIdentification(webpageResource.identification);
1657
+ const slug = webpageResource.slug === "/" ? "" : webpageResource.slug;
1658
+ if (slug === void 0) {
1659
+ throw new Error(`Slug not found for page \u201C${identification.label}\u201D`);
1660
+ }
1661
+ const links = webpageResource.links ? parseLinks(
1662
+ Array.isArray(webpageResource.links) ? webpageResource.links : [webpageResource.links]
1663
+ ) : [];
1664
+ const imageLink = links.find(
1665
+ (link) => link.type === "image" || link.type === "IIIF"
1666
+ );
1667
+ const elements = webpageResource.resource ? await parseWebpageResources(
1668
+ Array.isArray(webpageResource.resource) ? webpageResource.resource : [webpageResource.resource],
1669
+ "element"
1670
+ ) : [];
1671
+ const webpages = webpageResource.resource ? await parseWebpageResources(
1672
+ Array.isArray(webpageResource.resource) ? webpageResource.resource : [webpageResource.resource],
1673
+ "page"
1674
+ ) : [];
1675
+ let displayedInHeader = true;
1676
+ let width = "default";
1677
+ let variant = "default";
1678
+ const webpageSubProperties = webpageProperties.find(
1679
+ (property) => property.label === "presentation" && property.values[0]?.content === "page"
1680
+ )?.properties;
1681
+ if (webpageSubProperties) {
1682
+ const headerProperty = webpageSubProperties.find(
1683
+ (property) => property.label === "header"
1684
+ )?.values[0];
1685
+ if (headerProperty) {
1686
+ displayedInHeader = headerProperty.content === "Yes";
1687
+ }
1688
+ const widthProperty = webpageSubProperties.find(
1689
+ (property) => property.label === "width"
1690
+ )?.values[0];
1691
+ if (widthProperty) {
1692
+ width = widthProperty.content;
1693
+ }
1694
+ const variantProperty = webpageSubProperties.find(
1695
+ (property) => property.label === "variant"
1696
+ )?.values[0];
1697
+ if (variantProperty) {
1698
+ variant = variantProperty.content;
1699
+ }
1700
+ }
1701
+ const cssStyleSubProperties = webpageProperties.find(
1702
+ (property) => property.label === "presentation" && property.values[0]?.content === "css"
1703
+ )?.properties;
1704
+ const cssStyles = [];
1705
+ if (cssStyleSubProperties) {
1706
+ for (const property of cssStyleSubProperties) {
1707
+ cssStyles.push({
1708
+ label: property.label,
1709
+ value: property.values[0].content
1710
+ });
1711
+ }
1712
+ }
1713
+ return {
1714
+ title: identification.label,
1715
+ slug,
1716
+ elements,
1717
+ properties: {
1718
+ displayedInHeader,
1719
+ width,
1720
+ variant,
1721
+ backgroundImageUrl: imageLink ? `https://ochre.lib.uchicago.edu/ochre?uuid=${imageLink.uuid}&preview` : null,
1722
+ cssStyles
1723
+ },
1724
+ webpages
1725
+ };
1726
+ }
1727
+ async function parseWebpages(webpageResources) {
1728
+ const returnPages = [];
1729
+ const pagesToParse = Array.isArray(webpageResources) ? webpageResources : [webpageResources];
1730
+ for (const page of pagesToParse) {
1731
+ const webpage = await parseWebpage(page);
1732
+ if (webpage) {
1733
+ returnPages.push(webpage);
1734
+ }
1735
+ }
1736
+ return returnPages;
1737
+ }
1738
+ function parseWebsiteProperties(properties) {
1739
+ const mainProperties = parseProperties(properties);
1740
+ const websiteProperties = mainProperties.find(
1741
+ (property) => property.label === "presentation"
1742
+ )?.properties;
1743
+ if (!websiteProperties) {
1744
+ throw new Error("Presentation property not found");
1745
+ }
1746
+ const type = websiteProperties.find((property) => property.label === "webUI")?.values[0]?.content;
1747
+ if (type == null) {
1748
+ throw new Error("Website type not found");
1749
+ }
1750
+ const status = websiteProperties.find(
1751
+ (property) => property.label === "status"
1752
+ )?.values[0]?.content;
1753
+ if (status == null) {
1754
+ throw new Error("Website status not found");
1755
+ }
1756
+ let privacy = websiteProperties.find(
1757
+ (property) => property.label === "privacy"
1758
+ )?.values[0]?.content;
1759
+ if (privacy == null) {
1760
+ privacy = "public";
1761
+ }
1762
+ const result = websiteSchema.safeParse({
1763
+ type,
1764
+ status,
1765
+ privacy
1766
+ });
1767
+ if (!result.success) {
1768
+ throw new Error(`Invalid website properties: ${result.error.message}`);
1769
+ }
1770
+ const logoUuid = websiteProperties.find((property) => property.label === "logo")?.values[0]?.uuid ?? null;
1771
+ let isHeaderDisplayed = true;
1772
+ let headerVariant = "default";
1773
+ let isFooterDisplayed = true;
1774
+ let isSidebarDisplayed = false;
1775
+ let searchCollectionUuid = null;
1776
+ const headerProperty = websiteProperties.find(
1777
+ (property) => property.label === "navbar-visible"
1778
+ )?.values[0];
1779
+ if (headerProperty) {
1780
+ isHeaderDisplayed = headerProperty.content === "Yes";
1781
+ }
1782
+ const headerVariantProperty = websiteProperties.find(
1783
+ (property) => property.label === "navbar-variant"
1784
+ )?.values[0];
1785
+ if (headerVariantProperty) {
1786
+ headerVariant = headerVariantProperty.content;
1787
+ }
1788
+ const footerProperty = websiteProperties.find(
1789
+ (property) => property.label === "footer-visible"
1790
+ )?.values[0];
1791
+ if (footerProperty) {
1792
+ isFooterDisplayed = footerProperty.content === "Yes";
1793
+ }
1794
+ const sidebarProperty = websiteProperties.find(
1795
+ (property) => property.label === "sidebar-visible"
1796
+ )?.values[0];
1797
+ if (sidebarProperty) {
1798
+ isSidebarDisplayed = sidebarProperty.content === "Yes";
1799
+ }
1800
+ const collectionSearchProperty = websiteProperties.find(
1801
+ (property) => property.label === "search-collection"
1802
+ )?.values[0];
1803
+ if (collectionSearchProperty) {
1804
+ searchCollectionUuid = collectionSearchProperty.uuid;
1805
+ }
1806
+ const {
1807
+ type: validatedType,
1808
+ status: validatedStatus,
1809
+ privacy: validatedPrivacy
1810
+ } = result.data;
1811
+ return {
1812
+ type: validatedType,
1813
+ privacy: validatedPrivacy,
1814
+ status: validatedStatus,
1815
+ isHeaderDisplayed,
1816
+ headerVariant,
1817
+ isFooterDisplayed,
1818
+ isSidebarDisplayed,
1819
+ searchCollectionUuid,
1820
+ logoUrl: logoUuid !== null ? `https://ochre.lib.uchicago.edu/ochre?uuid=${logoUuid}&load` : null
1821
+ };
1822
+ }
1823
+ async function parseWebsite(websiteTree, projectName, website) {
1824
+ if (!websiteTree.properties) {
1825
+ throw new Error("Website properties not found");
1826
+ }
1827
+ const properties = parseWebsiteProperties(
1828
+ Array.isArray(websiteTree.properties.property) ? websiteTree.properties.property : [websiteTree.properties.property]
1829
+ );
1830
+ if (typeof websiteTree.items === "string" || !("resource" in websiteTree.items)) {
1831
+ throw new Error("Website pages not found");
1832
+ }
1833
+ const resources = Array.isArray(websiteTree.items.resource) ? websiteTree.items.resource : [websiteTree.items.resource];
1834
+ const pages = await parseWebpages(resources);
1835
+ const sidebarElements = [];
1836
+ const sidebar = resources.find((resource) => {
1837
+ const resourceProperties = resource.properties ? parseProperties(
1838
+ Array.isArray(resource.properties.property) ? resource.properties.property : [resource.properties.property]
1839
+ ) : [];
1840
+ return resourceProperties.some(
1841
+ (property) => property.label === "presentation" && property.values[0]?.content === "element" && property.properties[0]?.label === "component" && property.properties[0]?.values[0]?.content === "sidebar"
1842
+ );
1843
+ });
1844
+ if (sidebar) {
1845
+ const sidebarResources = sidebar.resource ? Array.isArray(sidebar.resource) ? sidebar.resource : [sidebar.resource] : [];
1846
+ for (const resource of sidebarResources) {
1847
+ const sidebarResourceProperties = resource.properties ? parseProperties(
1848
+ Array.isArray(resource.properties.property) ? resource.properties.property : [resource.properties.property]
1849
+ ) : [];
1850
+ const element = await parseWebElement(
1851
+ resource,
1852
+ sidebarResourceProperties.find(
1853
+ (property) => property.label === "presentation" && property.values[0]?.content === "element"
1854
+ )?.properties ?? []
1855
+ );
1856
+ sidebarElements.push(element);
1857
+ }
1858
+ }
1859
+ return {
1860
+ uuid: websiteTree.uuid,
1861
+ publicationDateTime: websiteTree.publicationDateTime ? new Date(websiteTree.publicationDateTime) : null,
1862
+ identification: parseIdentification(websiteTree.identification),
1863
+ project: {
1864
+ name: parseFakeString(projectName),
1865
+ website: website !== null ? parseFakeString(website) : null
1866
+ },
1867
+ creators: websiteTree.creators ? parsePersons(
1868
+ Array.isArray(websiteTree.creators.creator) ? websiteTree.creators.creator : [websiteTree.creators.creator]
1869
+ ) : [],
1870
+ license: parseLicense(websiteTree.availability),
1871
+ pages,
1872
+ sidebarElements,
1873
+ properties
1874
+ };
1875
+ }
1876
+
1877
+ // src/utils/fetchers/concept.ts
1878
+ async function fetchConcept(uuid) {
1879
+ try {
1880
+ const [error, dataRaw] = await fetchByUuid(uuid);
1881
+ if (error !== null) {
1882
+ throw new Error(error);
1883
+ }
1884
+ if (!("concept" in dataRaw.ochre)) {
1885
+ throw new Error("Invalid OCHRE data: API response missing 'concept' key");
1886
+ }
1887
+ const conceptItem = parseConcept(dataRaw.ochre.concept);
1888
+ const data = {
1889
+ uuid: parseFakeString(dataRaw.ochre.uuid),
1890
+ publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
1891
+ belongsTo: {
1892
+ uuid: dataRaw.ochre.uuidBelongsTo,
1893
+ abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
1894
+ },
1895
+ metadata: parseMetadata(dataRaw.ochre.metadata),
1896
+ item: conceptItem
1897
+ };
1898
+ return { metadata: data.metadata, concept: data.item };
1899
+ } catch (error) {
1900
+ console.error(error);
1901
+ return null;
1902
+ }
1903
+ }
1904
+
1905
+ // src/utils/fetchers/gallery.ts
1906
+ var import_zod4 = require("zod");
1907
+ var gallerySchema = import_zod4.z.object({
1908
+ uuid: import_zod4.z.string().uuid({ message: "Invalid UUID" }),
1909
+ filter: import_zod4.z.string().optional(),
1910
+ page: import_zod4.z.number().positive({ message: "Page must be positive" }),
1911
+ perPage: import_zod4.z.number().positive({ message: "Per page must be positive" })
1912
+ }).strict();
1913
+ async function fetchGallery(uuid, filter, page, perPage) {
1914
+ try {
1915
+ const parsed = gallerySchema.safeParse({ uuid, filter, page, perPage });
1916
+ if (!parsed.success) {
1917
+ throw new Error(parsed.error.message);
1918
+ }
1919
+ const response = await fetch(
1920
+ `https://ochre.lib.uchicago.edu/ochre?xquery=${encodeURIComponent(`
1921
+ for $q in input()/ochre[@uuid='${uuid}']
1922
+ let $filtered := $q/tree/items/resource[contains(lower-case(identification/label), lower-case('${filter}'))]
1923
+ let $maxLength := count($filtered)
1924
+ return <gallery maxLength='{$maxLength}'>
1925
+ {$q/metadata/project}
1926
+ {$q/metadata/item}
1927
+ {$filtered[position() >= ${((page - 1) * perPage + 1).toString()} and position() < ${(page * perPage + 1).toString()}]}
1928
+ </gallery>
1929
+ `)}&format=json`
1930
+ );
1931
+ if (!response.ok) {
1932
+ throw new Error("Error fetching gallery items, please try again later.");
1933
+ }
1934
+ const data = await response.json();
1935
+ if (!("gallery" in data.result)) {
1936
+ throw new Error("Failed to fetch gallery");
1937
+ }
1938
+ const galleryIdentification = parseIdentification(data.result.gallery.item);
1939
+ const galleryProjectIdentification = parseIdentification(
1940
+ data.result.gallery.project.identification
1941
+ );
1942
+ const gallery = {
1943
+ identification: galleryIdentification,
1944
+ projectIdentification: galleryProjectIdentification,
1945
+ resources: Array.isArray(data.result.gallery.resource) ? parseResources(data.result.gallery.resource) : [parseResource(data.result.gallery.resource)],
1946
+ maxLength: data.result.gallery.maxLength
1947
+ };
1948
+ return gallery;
1949
+ } catch (error) {
1950
+ console.error(error);
1951
+ return null;
1952
+ }
1953
+ }
1954
+
1955
+ // src/utils/fetchers/set.ts
1956
+ async function fetchSet(uuid) {
1957
+ try {
1958
+ const [error, dataRaw] = await fetchByUuid(uuid);
1959
+ if (error !== null) {
1960
+ throw new Error(error);
1961
+ }
1962
+ if (!("set" in dataRaw.ochre)) {
1963
+ throw new Error("Invalid OCHRE data: API response missing 'set' key");
1964
+ }
1965
+ const setItem = parseSet(dataRaw.ochre.set);
1966
+ const data = {
1967
+ uuid: parseFakeString(dataRaw.ochre.uuid),
1968
+ publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
1969
+ belongsTo: {
1970
+ uuid: dataRaw.ochre.uuidBelongsTo,
1971
+ abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
1972
+ },
1973
+ metadata: parseMetadata(dataRaw.ochre.metadata),
1974
+ item: setItem
1975
+ };
1976
+ return { metadata: data.metadata, set: data.item };
1977
+ } catch (error) {
1978
+ console.error(error);
1979
+ return null;
1980
+ }
1981
+ }
1982
+
1983
+ // src/utils/fetchers/spatial-unit.ts
1984
+ async function fetchSpatialUnit(uuid) {
1985
+ try {
1986
+ const [error, dataRaw] = await fetchByUuid(uuid);
1987
+ if (error !== null) {
1988
+ throw new Error(error);
1989
+ }
1990
+ if (!("spatialUnit" in dataRaw.ochre)) {
1991
+ throw new Error(
1992
+ "Invalid OCHRE data: API response missing 'spatialUnit' key"
1993
+ );
1994
+ }
1995
+ const spatialUnitItem = parseSpatialUnit(dataRaw.ochre.spatialUnit);
1996
+ const data = {
1997
+ uuid: parseFakeString(dataRaw.ochre.uuid),
1998
+ publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
1999
+ belongsTo: {
2000
+ uuid: dataRaw.ochre.uuidBelongsTo,
2001
+ abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2002
+ },
2003
+ metadata: parseMetadata(dataRaw.ochre.metadata),
2004
+ item: spatialUnitItem
2005
+ };
2006
+ return { metadata: data.metadata, spatialUnit: data.item };
2007
+ } catch (error) {
2008
+ console.error(error);
2009
+ return null;
2010
+ }
2011
+ }
2012
+
2013
+ // src/utils/fetchers/tree.ts
2014
+ async function fetchTree(uuid) {
2015
+ try {
2016
+ const [error, dataRaw] = await fetchByUuid(uuid);
2017
+ if (error !== null) {
2018
+ throw new Error(error);
2019
+ }
2020
+ if (!("tree" in dataRaw.ochre)) {
2021
+ throw new Error("Invalid OCHRE data: API response missing 'tree' key");
2022
+ }
2023
+ const tree = parseTree(dataRaw.ochre.tree);
2024
+ if (!tree) {
2025
+ throw new Error("Invalid OCHRE data: Could not parse tree");
2026
+ }
2027
+ const data = {
2028
+ uuid: parseFakeString(dataRaw.ochre.uuid),
2029
+ publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2030
+ belongsTo: {
2031
+ uuid: dataRaw.ochre.uuidBelongsTo,
2032
+ abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2033
+ },
2034
+ metadata: parseMetadata(dataRaw.ochre.metadata),
2035
+ item: tree
2036
+ };
2037
+ return { metadata: data.metadata, tree: data.item };
2038
+ } catch (error) {
2039
+ console.error(error);
2040
+ return null;
2041
+ }
2042
+ }
2043
+
2044
+ // src/utils/fetchers/website.ts
2045
+ async function fetchWebsite(abbreviation) {
2046
+ try {
2047
+ const response = await fetch(
2048
+ `https://ochre.lib.uchicago.edu/ochre?xquery=for $q in input()/ochre[tree[@type='lesson'][identification/abbreviation='${abbreviation.toLocaleLowerCase("en-US")}']] return $q&format=json`
2049
+ );
2050
+ if (!response.ok) {
2051
+ throw new Error("Failed to fetch website");
2052
+ }
2053
+ const data = await response.json();
2054
+ if (!("ochre" in data.result) || !("tree" in data.result.ochre)) {
2055
+ throw new Error("Failed to fetch website");
2056
+ }
2057
+ const projectIdentification = data.result.ochre.metadata.project?.identification ? parseIdentification(data.result.ochre.metadata.project.identification) : null;
2058
+ const website = await parseWebsite(
2059
+ data.result.ochre.tree,
2060
+ projectIdentification?.label ?? "",
2061
+ data.result.ochre.metadata.project?.identification.website ?? null
2062
+ );
2063
+ return website;
2064
+ } catch (error) {
2065
+ console.error(error);
2066
+ return null;
2067
+ }
2068
+ }
2069
+ // Annotate the CommonJS export names for ESM import in node:
2070
+ 0 && (module.exports = {
2071
+ fetchByUuid,
2072
+ fetchConcept,
2073
+ fetchGallery,
2074
+ fetchResource,
2075
+ fetchSet,
2076
+ fetchSpatialUnit,
2077
+ fetchTree,
2078
+ fetchWebsite,
2079
+ filterProperties,
2080
+ getAllPropertyLabels,
2081
+ getPropertyByLabel,
2082
+ getPropertyValueByLabel,
2083
+ getPropertyValuesByLabel,
2084
+ parseBibliographies,
2085
+ parseBibliography,
2086
+ parseConcept,
2087
+ parseConcepts,
2088
+ parseContext,
2089
+ parseCoordinates,
2090
+ parseDocument,
2091
+ parseEmailAndUrl,
2092
+ parseEvents,
2093
+ parseFakeString,
2094
+ parseIdentification,
2095
+ parseImage,
2096
+ parseImageMap,
2097
+ parseInterpretations,
2098
+ parseLanguages,
2099
+ parseLicense,
2100
+ parseLink,
2101
+ parseLinks,
2102
+ parseMetadata,
2103
+ parseNotes,
2104
+ parseObservation,
2105
+ parseObservations,
2106
+ parsePeriod,
2107
+ parsePeriods,
2108
+ parsePersons,
2109
+ parseProperties,
2110
+ parseResource,
2111
+ parseResources,
2112
+ parseSet,
2113
+ parseSpatialUnit,
2114
+ parseSpatialUnits,
2115
+ parseStringContent,
2116
+ parseStringDocumentItem,
2117
+ parseStringItem,
2118
+ parseTree,
2119
+ parseWebsite,
2120
+ trimEndLineBreaks
2121
+ });