@digitalculture/ochre-sdk 0.5.19 → 0.6.1

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.js CHANGED
@@ -1,52 +1,244 @@
1
- // src/utils/parse.ts
2
- import { z as z3 } from "zod";
3
-
4
- // src/utils/fetchers/generic.ts
1
+ // src/schemas.ts
5
2
  import { z } from "zod";
6
3
  var uuidSchema = z.string().uuid({ message: "Invalid UUID provided" });
7
- async function fetchByUuid(uuid) {
8
- try {
9
- const result = uuidSchema.safeParse(uuid);
10
- if (!result.success) {
11
- throw new Error(result.error.issues[0]?.message);
12
- }
13
- const response = await fetch(
14
- `https://ochre.lib.uchicago.edu/ochre?uuid=${uuid}&format=json&lang="*"`
15
- );
16
- if (!response.ok) {
17
- throw new Error("Failed to fetch OCHRE data");
18
- }
19
- const dataRaw = await response.json();
20
- if (!("ochre" in dataRaw)) {
21
- throw new Error("Invalid OCHRE data: API response missing 'ochre' key");
22
- }
23
- return [null, dataRaw];
24
- } catch (error) {
25
- return [error instanceof Error ? error.message : "Unknown error", null];
26
- }
27
- }
28
-
29
- // src/utils/string.ts
30
- import { z as z2 } from "zod";
31
- var renderOptionsSchema = z2.string().transform((str) => str.split(" ")).pipe(
32
- z2.array(
33
- z2.enum([
4
+ var websiteSchema = z.object({
5
+ type: z.enum(
6
+ [
7
+ "traditional",
8
+ "digital-collection",
9
+ "plum",
10
+ "cedar",
11
+ "elm",
12
+ "maple",
13
+ "oak",
14
+ "palm"
15
+ ],
16
+ { message: "Invalid website type" }
17
+ ),
18
+ status: z.enum(
19
+ ["development", "preview", "production"],
20
+ { message: "Invalid website status" }
21
+ ),
22
+ privacy: z.enum(
23
+ ["public", "password", "private"],
24
+ { message: "Invalid website privacy" }
25
+ )
26
+ });
27
+ var componentSchema = z.enum(
28
+ [
29
+ "annotated-document",
30
+ "annotated-image",
31
+ "bibliography",
32
+ "blog",
33
+ "button",
34
+ "collection",
35
+ "empty-space",
36
+ "filter-categories",
37
+ "iframe",
38
+ "iiif-viewer",
39
+ "image",
40
+ "image-gallery",
41
+ "n-columns",
42
+ "n-rows",
43
+ "network-graph",
44
+ "search-bar",
45
+ "table",
46
+ "text",
47
+ "timeline",
48
+ "video"
49
+ ],
50
+ { message: "Invalid component" }
51
+ );
52
+ var categorySchema = z.enum([
53
+ "resource",
54
+ "spatialUnit",
55
+ "concept",
56
+ "period",
57
+ "bibliography",
58
+ "person",
59
+ "propertyValue",
60
+ "set",
61
+ "tree"
62
+ ]);
63
+ var gallerySchema = z.object({
64
+ uuid: z.string().uuid({ message: "Invalid UUID" }),
65
+ filter: z.string().optional(),
66
+ page: z.number().positive({ message: "Page must be positive" }),
67
+ perPage: z.number().positive({ message: "Per page must be positive" })
68
+ }).strict();
69
+ var renderOptionsSchema = z.string().transform((str) => str.split(" ")).pipe(
70
+ z.array(
71
+ z.enum([
34
72
  "bold",
35
73
  "italic",
36
74
  "underline"
37
75
  ])
38
76
  )
39
77
  );
40
- var whitespaceSchema = z2.string().transform((str) => str.split(" ")).pipe(
41
- z2.array(
42
- z2.enum([
78
+ var whitespaceSchema = z.string().transform((str) => str.split(" ")).pipe(
79
+ z.array(
80
+ z.enum([
43
81
  "newline",
44
82
  "trailing",
45
83
  "leading"
46
84
  ])
47
85
  )
48
86
  );
49
- var emailSchema = z2.string().email({ message: "Invalid email" });
87
+ var emailSchema = z.string().email({ message: "Invalid email" });
88
+
89
+ // src/utils/helpers.ts
90
+ function getItemCategory(keys) {
91
+ const categoryFound = keys.find(
92
+ (key) => categorySchema.safeParse(key).success
93
+ );
94
+ if (!categoryFound) {
95
+ const unknownKey = keys.find(
96
+ (key) => ![
97
+ "uuid",
98
+ "uuidBelongsTo",
99
+ "belongsTo",
100
+ "publicationDateTime",
101
+ "metadata",
102
+ "languages"
103
+ ].includes(key)
104
+ );
105
+ throw new Error(`Invalid OCHRE data; found unexpected "${unknownKey}" key`);
106
+ }
107
+ const categoryKey = categorySchema.parse(categoryFound);
108
+ return categoryKey;
109
+ }
110
+
111
+ // src/utils/getters.ts
112
+ var DEFAULT_OPTIONS = {
113
+ searchNestedProperties: false
114
+ };
115
+ function getPropertyByLabel(properties, label, options = DEFAULT_OPTIONS) {
116
+ const { searchNestedProperties } = options;
117
+ const property = properties.find((property2) => property2.label === label);
118
+ if (property) {
119
+ return property;
120
+ }
121
+ if (searchNestedProperties) {
122
+ for (const property2 of properties) {
123
+ if (property2.properties.length > 0) {
124
+ const nestedResult = getPropertyByLabel(property2.properties, label, {
125
+ searchNestedProperties
126
+ });
127
+ if (nestedResult) {
128
+ return nestedResult;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ return null;
134
+ }
135
+ function getPropertyValuesByLabel(properties, label, options = DEFAULT_OPTIONS) {
136
+ const { searchNestedProperties } = options;
137
+ const property = properties.find((property2) => property2.label === label);
138
+ if (property) {
139
+ return property.values.map((value) => value.content);
140
+ }
141
+ if (searchNestedProperties) {
142
+ for (const property2 of properties) {
143
+ if (property2.properties.length > 0) {
144
+ const nestedResult = getPropertyValuesByLabel(
145
+ property2.properties,
146
+ label,
147
+ { searchNestedProperties }
148
+ );
149
+ if (nestedResult) {
150
+ return nestedResult;
151
+ }
152
+ }
153
+ }
154
+ }
155
+ return null;
156
+ }
157
+ function getPropertyValueByLabel(properties, label, options = DEFAULT_OPTIONS) {
158
+ const { searchNestedProperties } = options;
159
+ const values = getPropertyValuesByLabel(properties, label, {
160
+ searchNestedProperties
161
+ });
162
+ if (values !== null && values.length > 0) {
163
+ return values[0];
164
+ }
165
+ if (searchNestedProperties) {
166
+ for (const property of properties) {
167
+ if (property.properties.length > 0) {
168
+ const nestedResult = getPropertyValueByLabel(
169
+ property.properties,
170
+ label,
171
+ { searchNestedProperties }
172
+ );
173
+ if (nestedResult !== null) {
174
+ return nestedResult;
175
+ }
176
+ }
177
+ }
178
+ }
179
+ return null;
180
+ }
181
+ function getAllPropertyLabels(properties, options = DEFAULT_OPTIONS) {
182
+ const { searchNestedProperties } = options;
183
+ const labels = /* @__PURE__ */ new Set();
184
+ for (const property of properties) {
185
+ labels.add(property.label);
186
+ if (property.properties.length > 0 && searchNestedProperties) {
187
+ const nestedLabels = getAllPropertyLabels(property.properties, {
188
+ searchNestedProperties: true
189
+ });
190
+ for (const label of nestedLabels) {
191
+ labels.add(label);
192
+ }
193
+ }
194
+ }
195
+ return [...labels];
196
+ }
197
+ function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
198
+ const { searchNestedProperties } = options;
199
+ const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
200
+ if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
201
+ let isFound = property.values.some((value) => {
202
+ if (value.content === null) {
203
+ return false;
204
+ }
205
+ if (typeof value.content === "string") {
206
+ if (typeof filter.value !== "string") {
207
+ return false;
208
+ }
209
+ return value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"));
210
+ }
211
+ if (typeof value.content === "number") {
212
+ if (typeof filter.value !== "number") {
213
+ return false;
214
+ }
215
+ return value.content === filter.value;
216
+ }
217
+ if (typeof value.content === "boolean") {
218
+ if (typeof filter.value !== "boolean") {
219
+ return false;
220
+ }
221
+ return value.booleanValue === filter.value;
222
+ }
223
+ if (value.content instanceof Date) {
224
+ if (!(filter.value instanceof Date)) {
225
+ return false;
226
+ }
227
+ return value.content.getTime() === filter.value.getTime();
228
+ }
229
+ return false;
230
+ });
231
+ if (!isFound && searchNestedProperties) {
232
+ isFound = property.properties.some(
233
+ (property2) => filterProperties(property2, filter, { searchNestedProperties: true })
234
+ );
235
+ }
236
+ return isFound;
237
+ }
238
+ return false;
239
+ }
240
+
241
+ // src/utils/string.ts
50
242
  function getStringItemByLanguage(content, language) {
51
243
  const stringItemToFind = content.find((item) => item.lang === language);
52
244
  return stringItemToFind ?? null;
@@ -289,250 +481,42 @@ function parseStringDocumentItem(item, footnotes) {
289
481
  }
290
482
  }
291
483
  return returnString.replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
292
- }
293
- function parseStringContent(content, language = "eng") {
294
- switch (typeof content.content) {
295
- case "string":
296
- case "number":
297
- case "boolean": {
298
- return parseFakeString(content.content);
299
- }
300
- case "object": {
301
- if (Array.isArray(content.content)) {
302
- const stringItem = getStringItemByLanguage(content.content, language);
303
- if (stringItem) {
304
- return parseStringItem(stringItem);
305
- } else {
306
- const returnStringItem = content.content[0];
307
- if (!returnStringItem) {
308
- throw new Error(
309
- `No string item found for language \u201C${language}\u201D in the following content:
310
- ${JSON.stringify(
311
- content.content
312
- )}.`
313
- );
314
- }
315
- return parseStringItem(returnStringItem);
316
- }
317
- } else {
318
- return parseStringItem(content.content);
319
- }
320
- }
321
- default: {
322
- return String(content.content).replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
323
- }
324
- }
325
- }
326
-
327
- // src/utils/fetchers/resource.ts
328
- async function fetchResource(uuid) {
329
- try {
330
- const [error, dataRaw] = await fetchByUuid(uuid);
331
- if (error !== null) {
332
- throw new Error(error);
333
- }
334
- if (!("resource" in dataRaw.ochre)) {
335
- throw new Error(
336
- "Invalid OCHRE data: API response missing 'resource' key"
337
- );
338
- }
339
- const resourceItem = parseResource(dataRaw.ochre.resource);
340
- const data = {
341
- uuid: parseFakeString(dataRaw.ochre.uuid),
342
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
343
- belongsTo: {
344
- uuid: dataRaw.ochre.uuidBelongsTo,
345
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
346
- },
347
- metadata: parseMetadata(dataRaw.ochre.metadata),
348
- item: resourceItem
349
- };
350
- return { metadata: data.metadata, resource: data.item };
351
- } catch (error) {
352
- console.error(error);
353
- return null;
354
- }
355
- }
356
-
357
- // src/utils/getters.ts
358
- var DEFAULT_OPTIONS = {
359
- searchNestedProperties: false
360
- };
361
- function getPropertyByLabel(properties, label, options = DEFAULT_OPTIONS) {
362
- const { searchNestedProperties } = options;
363
- const property = properties.find((property2) => property2.label === label);
364
- if (property) {
365
- return property;
366
- }
367
- if (searchNestedProperties) {
368
- for (const property2 of properties) {
369
- if (property2.properties.length > 0) {
370
- const nestedResult = getPropertyByLabel(property2.properties, label, {
371
- searchNestedProperties
372
- });
373
- if (nestedResult) {
374
- return nestedResult;
375
- }
376
- }
377
- }
378
- }
379
- return null;
380
- }
381
- function getPropertyValuesByLabel(properties, label, options = DEFAULT_OPTIONS) {
382
- const { searchNestedProperties } = options;
383
- const property = properties.find((property2) => property2.label === label);
384
- if (property) {
385
- return property.values.map((value) => value.content);
386
- }
387
- if (searchNestedProperties) {
388
- for (const property2 of properties) {
389
- if (property2.properties.length > 0) {
390
- const nestedResult = getPropertyValuesByLabel(
391
- property2.properties,
392
- label,
393
- { searchNestedProperties }
394
- );
395
- if (nestedResult) {
396
- return nestedResult;
397
- }
398
- }
399
- }
400
- }
401
- return null;
402
- }
403
- function getPropertyValueByLabel(properties, label, options = DEFAULT_OPTIONS) {
404
- const { searchNestedProperties } = options;
405
- const values = getPropertyValuesByLabel(properties, label, {
406
- searchNestedProperties
407
- });
408
- if (values !== null && values.length > 0) {
409
- return values[0];
410
- }
411
- if (searchNestedProperties) {
412
- for (const property of properties) {
413
- if (property.properties.length > 0) {
414
- const nestedResult = getPropertyValueByLabel(
415
- property.properties,
416
- label,
417
- { searchNestedProperties }
418
- );
419
- if (nestedResult !== null) {
420
- return nestedResult;
421
- }
422
- }
423
- }
424
- }
425
- return null;
426
- }
427
- function getAllPropertyLabels(properties, options = DEFAULT_OPTIONS) {
428
- const { searchNestedProperties } = options;
429
- const labels = /* @__PURE__ */ new Set();
430
- for (const property of properties) {
431
- labels.add(property.label);
432
- if (property.properties.length > 0 && searchNestedProperties) {
433
- const nestedLabels = getAllPropertyLabels(property.properties, {
434
- searchNestedProperties: true
435
- });
436
- for (const label of nestedLabels) {
437
- labels.add(label);
438
- }
439
- }
440
- }
441
- return [...labels];
442
- }
443
- function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
444
- const { searchNestedProperties } = options;
445
- const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
446
- if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
447
- let isFound = property.values.some((value) => {
448
- if (value.content === null) {
449
- return false;
450
- }
451
- if (typeof value.content === "string") {
452
- if (typeof filter.value !== "string") {
453
- return false;
454
- }
455
- return value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"));
456
- }
457
- if (typeof value.content === "number") {
458
- if (typeof filter.value !== "number") {
459
- return false;
460
- }
461
- return value.content === filter.value;
462
- }
463
- if (typeof value.content === "boolean") {
464
- if (typeof filter.value !== "boolean") {
465
- return false;
466
- }
467
- return value.booleanValue === filter.value;
468
- }
469
- if (value.content instanceof Date) {
470
- if (!(filter.value instanceof Date)) {
471
- return false;
472
- }
473
- return value.content.getTime() === filter.value.getTime();
474
- }
475
- return false;
476
- });
477
- if (!isFound && searchNestedProperties) {
478
- isFound = property.properties.some(
479
- (property2) => filterProperties(property2, filter, { searchNestedProperties: true })
480
- );
481
- }
482
- return isFound;
483
- }
484
- return false;
485
- }
486
-
487
- // src/utils/parse.ts
488
- var websiteSchema = z3.object({
489
- type: z3.enum(
490
- [
491
- "traditional",
492
- "digital-collection",
493
- "plum",
494
- "cedar",
495
- "elm",
496
- "maple",
497
- "oak",
498
- "palm"
499
- ],
500
- { message: "Invalid website type" }
501
- ),
502
- status: z3.enum(
503
- ["development", "preview", "production"],
504
- { message: "Invalid website status" }
505
- ),
506
- privacy: z3.enum(
507
- ["public", "password", "private"],
508
- { message: "Invalid website privacy" }
509
- )
510
- });
511
- var componentSchema = z3.enum(
512
- [
513
- "annotated-document",
514
- "annotated-image",
515
- "bibliography",
516
- "blog",
517
- "button",
518
- "collection",
519
- "empty-space",
520
- "filter-categories",
521
- "iframe",
522
- "iiif-viewer",
523
- "image",
524
- "image-gallery",
525
- "n-columns",
526
- "n-rows",
527
- "network-graph",
528
- "search-bar",
529
- "table",
530
- "text",
531
- "timeline",
532
- "video"
533
- ],
534
- { message: "Invalid component" }
535
- );
484
+ }
485
+ function parseStringContent(content, language = "eng") {
486
+ switch (typeof content.content) {
487
+ case "string":
488
+ case "number":
489
+ case "boolean": {
490
+ return parseFakeString(content.content);
491
+ }
492
+ case "object": {
493
+ if (Array.isArray(content.content)) {
494
+ const stringItem = getStringItemByLanguage(content.content, language);
495
+ if (stringItem) {
496
+ return parseStringItem(stringItem);
497
+ } else {
498
+ const returnStringItem = content.content[0];
499
+ if (!returnStringItem) {
500
+ throw new Error(
501
+ `No string item found for language \u201C${language}\u201D in the following content:
502
+ ${JSON.stringify(
503
+ content.content
504
+ )}.`
505
+ );
506
+ }
507
+ return parseStringItem(returnStringItem);
508
+ }
509
+ } else {
510
+ return parseStringItem(content.content);
511
+ }
512
+ }
513
+ default: {
514
+ return String(content.content).replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
515
+ }
516
+ }
517
+ }
518
+
519
+ // src/utils/parse.ts
536
520
  function parseIdentification(identification) {
537
521
  try {
538
522
  const returnIdentification = {
@@ -1117,54 +1101,83 @@ function parseTree(tree) {
1117
1101
  return returnTree;
1118
1102
  }
1119
1103
  function parseSet(set) {
1120
- let resources = [];
1121
- let spatialUnits = [];
1122
- let concepts = [];
1123
- let periods = [];
1124
- let bibliographies = [];
1125
- let persons = [];
1126
- let propertyValues = [];
1127
- if (typeof set.items !== "string" && "resource" in set.items) {
1128
- resources = parseResources(
1129
- Array.isArray(set.items.resource) ? set.items.resource : [set.items.resource],
1130
- true
1131
- );
1132
- }
1133
- if (typeof set.items !== "string" && "spatialUnit" in set.items) {
1134
- spatialUnits = parseSpatialUnits(
1135
- Array.isArray(set.items.spatialUnit) ? set.items.spatialUnit : [set.items.spatialUnit],
1136
- true
1137
- );
1138
- }
1139
- if (typeof set.items !== "string" && "concept" in set.items) {
1140
- concepts = parseConcepts(
1141
- Array.isArray(set.items.concept) ? set.items.concept : [set.items.concept],
1142
- true
1143
- );
1144
- }
1145
- if (typeof set.items !== "string" && "period" in set.items) {
1146
- periods = parsePeriods(
1147
- Array.isArray(set.items.period) ? set.items.period : [set.items.period]
1148
- );
1149
- }
1150
- if (typeof set.items !== "string" && "bibliography" in set.items) {
1151
- bibliographies = parseBibliographies(
1152
- Array.isArray(set.items.bibliography) ? set.items.bibliography : [set.items.bibliography]
1153
- );
1154
- }
1155
- if (typeof set.items !== "string" && "person" in set.items) {
1156
- persons = parsePersons(
1157
- Array.isArray(set.items.person) ? set.items.person : [set.items.person]
1158
- );
1159
- }
1160
- if (typeof set.items !== "string" && "propertyValue" in set.items) {
1161
- propertyValues = parsePropertyValues(
1162
- Array.isArray(set.items.propertyValue) ? set.items.propertyValue : [set.items.propertyValue]
1163
- );
1104
+ if (typeof set.items === "string") {
1105
+ throw new TypeError("Invalid OCHRE data: Set has no items");
1106
+ }
1107
+ const itemCategory = getItemCategory(Object.keys(set.items));
1108
+ let items = [];
1109
+ switch (itemCategory) {
1110
+ case "resource": {
1111
+ if (!("resource" in set.items)) {
1112
+ throw new Error("Invalid OCHRE data: Set has no resources");
1113
+ }
1114
+ items = parseResources(
1115
+ Array.isArray(set.items.resource) ? set.items.resource : [set.items.resource]
1116
+ );
1117
+ break;
1118
+ }
1119
+ case "spatialUnit": {
1120
+ if (!("spatialUnit" in set.items)) {
1121
+ throw new Error("Invalid OCHRE data: Set has no spatial units");
1122
+ }
1123
+ items = parseSpatialUnits(
1124
+ Array.isArray(set.items.spatialUnit) ? set.items.spatialUnit : [set.items.spatialUnit]
1125
+ );
1126
+ break;
1127
+ }
1128
+ case "concept": {
1129
+ if (!("concept" in set.items)) {
1130
+ throw new Error("Invalid OCHRE data: Set has no concepts");
1131
+ }
1132
+ items = parseConcepts(
1133
+ Array.isArray(set.items.concept) ? set.items.concept : [set.items.concept]
1134
+ );
1135
+ break;
1136
+ }
1137
+ case "period": {
1138
+ if (!("period" in set.items)) {
1139
+ throw new Error("Invalid OCHRE data: Set has no periods");
1140
+ }
1141
+ items = parsePeriods(
1142
+ Array.isArray(set.items.period) ? set.items.period : [set.items.period]
1143
+ );
1144
+ break;
1145
+ }
1146
+ case "bibliography": {
1147
+ if (!("bibliography" in set.items)) {
1148
+ throw new Error("Invalid OCHRE data: Set has no bibliographies");
1149
+ }
1150
+ items = parseBibliographies(
1151
+ Array.isArray(set.items.bibliography) ? set.items.bibliography : [set.items.bibliography]
1152
+ );
1153
+ break;
1154
+ }
1155
+ case "person": {
1156
+ if (!("person" in set.items)) {
1157
+ throw new Error("Invalid OCHRE data: Set has no persons");
1158
+ }
1159
+ items = parsePersons(
1160
+ Array.isArray(set.items.person) ? set.items.person : [set.items.person]
1161
+ );
1162
+ break;
1163
+ }
1164
+ case "propertyValue": {
1165
+ if (!("propertyValue" in set.items)) {
1166
+ throw new Error("Invalid OCHRE data: Set has no property values");
1167
+ }
1168
+ items = parsePropertyValues(
1169
+ Array.isArray(set.items.propertyValue) ? set.items.propertyValue : [set.items.propertyValue]
1170
+ );
1171
+ break;
1172
+ }
1173
+ default: {
1174
+ throw new Error("Invalid OCHRE data: Set has no items or is malformed");
1175
+ }
1164
1176
  }
1165
1177
  return {
1166
1178
  uuid: set.uuid,
1167
1179
  category: "set",
1180
+ itemCategory,
1168
1181
  publicationDateTime: set.publicationDateTime ? new Date(set.publicationDateTime) : null,
1169
1182
  date: set.date != null ? new Date(set.date) : null,
1170
1183
  license: parseLicense(set.availability),
@@ -1176,18 +1189,10 @@ function parseSet(set) {
1176
1189
  ) : [],
1177
1190
  type: set.type,
1178
1191
  number: set.n,
1179
- items: {
1180
- resources,
1181
- spatialUnits,
1182
- concepts,
1183
- periods,
1184
- bibliographies,
1185
- persons,
1186
- propertyValues
1187
- }
1192
+ items
1188
1193
  };
1189
1194
  }
1190
- function parseResource(resource, isNested = false) {
1195
+ function parseResource(resource) {
1191
1196
  const returnResource = {
1192
1197
  uuid: resource.uuid,
1193
1198
  category: "resource",
@@ -1230,34 +1235,20 @@ function parseResource(resource, isNested = false) {
1230
1235
  Array.isArray(resource.citedBibliography.reference) ? resource.citedBibliography.reference : [resource.citedBibliography.reference]
1231
1236
  ) : [],
1232
1237
  resources: resource.resource ? parseResources(
1233
- Array.isArray(resource.resource) ? resource.resource : [resource.resource],
1234
- true
1238
+ Array.isArray(resource.resource) ? resource.resource : [resource.resource]
1235
1239
  ) : []
1236
1240
  };
1237
- if (isNested) {
1238
- const returnNestedResource = {
1239
- ...returnResource,
1240
- publicationDateTime: null,
1241
- context: null,
1242
- license: null,
1243
- copyright: null
1244
- };
1245
- delete returnNestedResource.publicationDateTime;
1246
- delete returnNestedResource.license;
1247
- delete returnNestedResource.copyright;
1248
- return returnNestedResource;
1249
- }
1250
1241
  return returnResource;
1251
1242
  }
1252
- function parseResources(resources, isNested = false) {
1243
+ function parseResources(resources) {
1253
1244
  const returnResources = [];
1254
1245
  const resourcesToParse = Array.isArray(resources) ? resources : [resources];
1255
1246
  for (const resource of resourcesToParse) {
1256
- returnResources.push(parseResource(resource, isNested));
1247
+ returnResources.push(parseResource(resource));
1257
1248
  }
1258
1249
  return returnResources;
1259
1250
  }
1260
- function parseSpatialUnit(spatialUnit, isNested = false) {
1251
+ function parseSpatialUnit(spatialUnit) {
1261
1252
  const returnSpatialUnit = {
1262
1253
  uuid: spatialUnit.uuid,
1263
1254
  category: "spatialUnit",
@@ -1277,34 +1268,22 @@ function parseSpatialUnit(spatialUnit, isNested = false) {
1277
1268
  ) : spatialUnit.observation ? [parseObservation(spatialUnit.observation)] : [],
1278
1269
  events: "events" in spatialUnit && spatialUnit.events ? parseEvents(
1279
1270
  Array.isArray(spatialUnit.events.event) ? spatialUnit.events.event : [spatialUnit.events.event]
1271
+ ) : [],
1272
+ properties: "properties" in spatialUnit && spatialUnit.properties ? parseProperties(
1273
+ Array.isArray(spatialUnit.properties.property) ? spatialUnit.properties.property : [spatialUnit.properties.property]
1280
1274
  ) : []
1281
1275
  };
1282
- if (isNested) {
1283
- const returnNestedSpatialUnit = {
1284
- ...returnSpatialUnit,
1285
- publicationDateTime: null,
1286
- license: null,
1287
- properties: "properties" in spatialUnit && spatialUnit.properties ? parseProperties(
1288
- Array.isArray(spatialUnit.properties.property) ? spatialUnit.properties.property : [spatialUnit.properties.property]
1289
- ) : []
1290
- };
1291
- delete returnNestedSpatialUnit.publicationDateTime;
1292
- delete returnNestedSpatialUnit.license;
1293
- return returnNestedSpatialUnit;
1294
- }
1295
1276
  return returnSpatialUnit;
1296
1277
  }
1297
- function parseSpatialUnits(spatialUnits, isNested = false) {
1278
+ function parseSpatialUnits(spatialUnits) {
1298
1279
  const returnSpatialUnits = [];
1299
1280
  const spatialUnitsToParse = Array.isArray(spatialUnits) ? spatialUnits : [spatialUnits];
1300
1281
  for (const spatialUnit of spatialUnitsToParse) {
1301
- returnSpatialUnits.push(
1302
- parseSpatialUnit(spatialUnit, isNested)
1303
- );
1282
+ returnSpatialUnits.push(parseSpatialUnit(spatialUnit));
1304
1283
  }
1305
1284
  return returnSpatialUnits;
1306
1285
  }
1307
- function parseConcept(concept, isNested = false) {
1286
+ function parseConcept(concept) {
1308
1287
  const returnConcept = {
1309
1288
  uuid: concept.uuid,
1310
1289
  category: "concept",
@@ -1317,17 +1296,6 @@ function parseConcept(concept, isNested = false) {
1317
1296
  Array.isArray(concept.interpretations.interpretation) ? concept.interpretations.interpretation : [concept.interpretations.interpretation]
1318
1297
  )
1319
1298
  };
1320
- if (isNested) {
1321
- const returnNestedConcept = {
1322
- ...returnConcept,
1323
- publicationDateTime: null,
1324
- context: null,
1325
- license: null
1326
- };
1327
- delete returnNestedConcept.publicationDateTime;
1328
- delete returnNestedConcept.license;
1329
- return returnNestedConcept;
1330
- }
1331
1299
  return returnConcept;
1332
1300
  }
1333
1301
  var parseWebpageResources = async (webpageResources, type) => {
@@ -1370,11 +1338,11 @@ var parseWebpageResources = async (webpageResources, type) => {
1370
1338
  }
1371
1339
  return returnElements;
1372
1340
  };
1373
- function parseConcepts(concepts, isNested = false) {
1341
+ function parseConcepts(concepts) {
1374
1342
  const returnConcepts = [];
1375
1343
  const conceptsToParse = Array.isArray(concepts) ? concepts : [concepts];
1376
1344
  for (const concept of conceptsToParse) {
1377
- returnConcepts.push(parseConcept(concept, isNested));
1345
+ returnConcepts.push(parseConcept(concept));
1378
1346
  }
1379
1347
  return returnConcepts;
1380
1348
  }
@@ -1395,11 +1363,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1395
1363
  if (document === null) {
1396
1364
  const documentLink = links.find((link) => link.type === "internalDocument");
1397
1365
  if (documentLink) {
1398
- const documentResource = await fetchResource(documentLink.uuid);
1399
- if (documentResource === null) {
1366
+ const { item, error } = await fetchItem(documentLink.uuid, "resource");
1367
+ if (error !== null) {
1400
1368
  throw new Error("Failed to fetch OCHRE data");
1401
1369
  }
1402
- document = documentResource.resource.document;
1370
+ document = item.document;
1403
1371
  }
1404
1372
  }
1405
1373
  switch (componentName) {
@@ -2440,300 +2408,144 @@ async function parseWebsite(websiteTree, projectName, website) {
2440
2408
  };
2441
2409
  }
2442
2410
 
2443
- // src/utils/fetchers/bibliography.ts
2444
- async function fetchBibliography(uuid) {
2445
- try {
2446
- const [error, dataRaw] = await fetchByUuid(uuid);
2447
- if (error !== null) {
2448
- throw new Error(error);
2449
- }
2450
- if (!("bibliography" in dataRaw.ochre)) {
2451
- throw new Error(
2452
- "Invalid OCHRE data: API response missing 'bibliography' key"
2453
- );
2454
- }
2455
- const bibliographyItem = parseBibliography(dataRaw.ochre.bibliography);
2456
- const data = {
2457
- uuid: parseFakeString(dataRaw.ochre.uuid),
2458
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2459
- belongsTo: {
2460
- uuid: dataRaw.ochre.uuidBelongsTo,
2461
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2462
- },
2463
- metadata: parseMetadata(dataRaw.ochre.metadata),
2464
- item: bibliographyItem
2465
- };
2466
- return { metadata: data.metadata, bibliography: data.item };
2467
- } catch (error) {
2468
- console.error(error);
2469
- return null;
2470
- }
2471
- }
2472
-
2473
- // src/utils/fetchers/concept.ts
2474
- async function fetchConcept(uuid) {
2475
- try {
2476
- const [error, dataRaw] = await fetchByUuid(uuid);
2477
- if (error !== null) {
2478
- throw new Error(error);
2479
- }
2480
- if (!("concept" in dataRaw.ochre)) {
2481
- throw new Error("Invalid OCHRE data: API response missing 'concept' key");
2482
- }
2483
- const conceptItem = parseConcept(dataRaw.ochre.concept);
2484
- const data = {
2485
- uuid: parseFakeString(dataRaw.ochre.uuid),
2486
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2487
- belongsTo: {
2488
- uuid: dataRaw.ochre.uuidBelongsTo,
2489
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2490
- },
2491
- metadata: parseMetadata(dataRaw.ochre.metadata),
2492
- item: conceptItem
2493
- };
2494
- return { metadata: data.metadata, concept: data.item };
2495
- } catch (error) {
2496
- console.error(error);
2497
- return null;
2498
- }
2499
- }
2500
-
2501
- // src/utils/fetchers/gallery.ts
2502
- import { z as z4 } from "zod";
2503
- var gallerySchema = z4.object({
2504
- uuid: z4.string().uuid({ message: "Invalid UUID" }),
2505
- filter: z4.string().optional(),
2506
- page: z4.number().positive({ message: "Page must be positive" }),
2507
- perPage: z4.number().positive({ message: "Per page must be positive" })
2508
- }).strict();
2509
- async function fetchGallery(uuid, filter, page, perPage) {
2411
+ // src/utils/fetchers/uuid.ts
2412
+ async function fetchByUuid(uuid) {
2510
2413
  try {
2511
- const parsed = gallerySchema.safeParse({ uuid, filter, page, perPage });
2512
- if (!parsed.success) {
2513
- throw new Error(parsed.error.message);
2514
- }
2414
+ const parsedUuid = uuidSchema.parse(uuid);
2515
2415
  const response = await fetch(
2516
- `https://ochre.lib.uchicago.edu/ochre?xquery=${encodeURIComponent(`
2517
- for $q in input()/ochre[@uuid='${uuid}']
2518
- let $filtered := $q/tree/items/resource[contains(lower-case(identification/label), lower-case('${filter}'))]
2519
- let $maxLength := count($filtered)
2520
- return <gallery maxLength='{$maxLength}'>
2521
- {$q/metadata/project}
2522
- {$q/metadata/item}
2523
- {$filtered[position() >= ${((page - 1) * perPage + 1).toString()} and position() < ${(page * perPage + 1).toString()}]}
2524
- </gallery>
2525
- `)}&format=json`
2416
+ `https://ochre.lib.uchicago.edu/ochre?uuid=${parsedUuid}&format=json&lang="*"`
2526
2417
  );
2527
2418
  if (!response.ok) {
2528
- throw new Error("Error fetching gallery items, please try again later.");
2529
- }
2530
- const data = await response.json();
2531
- if (!("gallery" in data.result)) {
2532
- throw new Error("Failed to fetch gallery");
2419
+ throw new Error("Failed to fetch OCHRE data");
2533
2420
  }
2534
- const galleryIdentification = parseIdentification(
2535
- data.result.gallery.item.identification
2536
- );
2537
- const galleryProjectIdentification = parseIdentification(
2538
- data.result.gallery.project.identification
2539
- );
2540
- const gallery = {
2541
- identification: galleryIdentification,
2542
- projectIdentification: galleryProjectIdentification,
2543
- resources: data.result.gallery.resource ? Array.isArray(data.result.gallery.resource) ? parseResources(data.result.gallery.resource) : [parseResource(data.result.gallery.resource)] : [],
2544
- maxLength: data.result.gallery.maxLength
2545
- };
2546
- return gallery;
2547
- } catch (error) {
2548
- console.error(error);
2549
- return null;
2550
- }
2551
- }
2552
-
2553
- // src/utils/fetchers/period.ts
2554
- async function fetchPeriod(uuid) {
2555
- try {
2556
- const [error, dataRaw] = await fetchByUuid(uuid);
2557
- if (error !== null) {
2558
- throw new Error(error);
2421
+ const dataRaw = await response.json();
2422
+ if (!("ochre" in dataRaw)) {
2423
+ throw new Error("Invalid OCHRE data: API response missing 'ochre' key");
2559
2424
  }
2560
- if (!("period" in dataRaw.ochre)) {
2561
- throw new Error("Invalid OCHRE data: API response missing 'period' key");
2562
- }
2563
- const periodItem = parsePeriod(dataRaw.ochre.period);
2564
- const data = {
2565
- uuid: parseFakeString(dataRaw.ochre.uuid),
2566
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2567
- belongsTo: {
2568
- uuid: dataRaw.ochre.uuidBelongsTo,
2569
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2570
- },
2571
- metadata: parseMetadata(dataRaw.ochre.metadata),
2572
- item: periodItem
2573
- };
2574
- return { metadata: data.metadata, period: data.item };
2425
+ return [null, dataRaw];
2575
2426
  } catch (error) {
2576
- console.error(error);
2577
- return null;
2427
+ return [error instanceof Error ? error.message : "Unknown error", null];
2578
2428
  }
2579
2429
  }
2580
2430
 
2581
- // src/utils/fetchers/property-value.ts
2582
- async function fetchPropertyValue(uuid) {
2431
+ // src/utils/fetchers/item.ts
2432
+ async function fetchItem(uuid, category) {
2583
2433
  try {
2584
- const [error, dataRaw] = await fetchByUuid(uuid);
2434
+ const [error, data] = await fetchByUuid(uuid);
2585
2435
  if (error !== null) {
2586
2436
  throw new Error(error);
2587
2437
  }
2588
- if (!("propertyValue" in dataRaw.ochre)) {
2589
- throw new Error(
2590
- "Invalid OCHRE data: API response missing 'propertyValue' key"
2591
- );
2592
- }
2593
- const propertyValueItem = parsePropertyValue(dataRaw.ochre.propertyValue);
2594
- const data = {
2595
- uuid: parseFakeString(dataRaw.ochre.uuid),
2596
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2597
- belongsTo: {
2598
- uuid: dataRaw.ochre.uuidBelongsTo,
2599
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2600
- },
2601
- metadata: parseMetadata(dataRaw.ochre.metadata),
2602
- item: propertyValueItem
2603
- };
2604
- return { metadata: data.metadata, propertyValue: data.item };
2605
- } catch (error) {
2606
- console.error(error);
2607
- return null;
2608
- }
2609
- }
2610
-
2611
- // src/utils/fetchers/set.ts
2612
- async function fetchSet(uuid) {
2613
- try {
2614
- const [error, dataRaw] = await fetchByUuid(uuid);
2615
- if (error !== null) {
2616
- throw new Error(error);
2438
+ const categoryKey = getItemCategory(Object.keys(data.ochre));
2439
+ let item;
2440
+ switch (categoryKey) {
2441
+ case "resource": {
2442
+ if (!("resource" in data.ochre)) {
2443
+ throw new Error(
2444
+ "Invalid OCHRE data: API response missing 'resource' key"
2445
+ );
2446
+ }
2447
+ item = parseResource(data.ochre.resource);
2448
+ break;
2449
+ }
2450
+ case "spatialUnit": {
2451
+ if (!("spatialUnit" in data.ochre)) {
2452
+ throw new Error(
2453
+ "Invalid OCHRE data: API response missing 'spatialUnit' key"
2454
+ );
2455
+ }
2456
+ item = parseSpatialUnit(data.ochre.spatialUnit);
2457
+ break;
2458
+ }
2459
+ case "concept": {
2460
+ if (!("concept" in data.ochre)) {
2461
+ throw new Error(
2462
+ "Invalid OCHRE data: API response missing 'concept' key"
2463
+ );
2464
+ }
2465
+ item = parseConcept(data.ochre.concept);
2466
+ break;
2467
+ }
2468
+ case "period": {
2469
+ if (!("period" in data.ochre)) {
2470
+ throw new Error(
2471
+ "Invalid OCHRE data: API response missing 'period' key"
2472
+ );
2473
+ }
2474
+ item = parsePeriod(data.ochre.period);
2475
+ break;
2476
+ }
2477
+ case "bibliography": {
2478
+ if (!("bibliography" in data.ochre)) {
2479
+ throw new Error(
2480
+ "Invalid OCHRE data: API response missing 'bibliography' key"
2481
+ );
2482
+ }
2483
+ item = parseBibliography(data.ochre.bibliography);
2484
+ break;
2485
+ }
2486
+ case "person": {
2487
+ if (!("person" in data.ochre)) {
2488
+ throw new Error(
2489
+ "Invalid OCHRE data: API response missing 'person' key"
2490
+ );
2491
+ }
2492
+ item = parsePerson(data.ochre.person);
2493
+ break;
2494
+ }
2495
+ case "propertyValue": {
2496
+ if (!("propertyValue" in data.ochre)) {
2497
+ throw new Error(
2498
+ "Invalid OCHRE data: API response missing 'propertyValue' key"
2499
+ );
2500
+ }
2501
+ item = parsePropertyValue(data.ochre.propertyValue);
2502
+ break;
2503
+ }
2504
+ case "set": {
2505
+ if (!("set" in data.ochre)) {
2506
+ throw new Error("Invalid OCHRE data: API response missing 'set' key");
2507
+ }
2508
+ item = parseSet(data.ochre.set);
2509
+ break;
2510
+ }
2511
+ case "tree": {
2512
+ if (!("tree" in data.ochre)) {
2513
+ throw new Error(
2514
+ "Invalid OCHRE data: API response missing 'tree' key"
2515
+ );
2516
+ }
2517
+ item = parseTree(data.ochre.tree);
2518
+ break;
2519
+ }
2520
+ default: {
2521
+ throw new Error("Invalid category");
2522
+ }
2617
2523
  }
2618
- if (!("set" in dataRaw.ochre)) {
2619
- throw new Error("Invalid OCHRE data: API response missing 'set' key");
2620
- }
2621
- const setItem = parseSet(dataRaw.ochre.set);
2622
- const data = {
2623
- uuid: parseFakeString(dataRaw.ochre.uuid),
2624
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2625
- belongsTo: {
2626
- uuid: dataRaw.ochre.uuidBelongsTo,
2627
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2628
- },
2629
- metadata: parseMetadata(dataRaw.ochre.metadata),
2630
- item: setItem
2524
+ const metadata = parseMetadata(data.ochre.metadata);
2525
+ const belongsTo = {
2526
+ uuid: data.ochre.uuidBelongsTo,
2527
+ abbreviation: parseFakeString(data.ochre.belongsTo)
2631
2528
  };
2632
- return { metadata: data.metadata, set: data.item };
2633
- } catch (error) {
2634
- console.error(error);
2635
- return null;
2636
- }
2637
- }
2638
-
2639
- // src/utils/fetchers/spatial-unit.ts
2640
- async function fetchSpatialUnit(uuid) {
2641
- try {
2642
- const [error, dataRaw] = await fetchByUuid(uuid);
2643
- if (error !== null) {
2644
- throw new Error(error);
2645
- }
2646
- if (!("spatialUnit" in dataRaw.ochre)) {
2647
- throw new Error(
2648
- "Invalid OCHRE data: API response missing 'spatialUnit' key"
2649
- );
2650
- }
2651
- const spatialUnitItem = parseSpatialUnit(dataRaw.ochre.spatialUnit);
2652
- const data = {
2653
- uuid: parseFakeString(dataRaw.ochre.uuid),
2654
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2655
- belongsTo: {
2656
- uuid: dataRaw.ochre.uuidBelongsTo,
2657
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2658
- },
2659
- metadata: parseMetadata(dataRaw.ochre.metadata),
2660
- item: spatialUnitItem
2529
+ return {
2530
+ error: null,
2531
+ metadata,
2532
+ belongsTo,
2533
+ item,
2534
+ category
2661
2535
  };
2662
- return { metadata: data.metadata, spatialUnit: data.item };
2663
2536
  } catch (error) {
2664
- console.error(error);
2665
- return null;
2666
- }
2667
- }
2668
-
2669
- // src/utils/fetchers/tree.ts
2670
- async function fetchTree(uuid) {
2671
- try {
2672
- const [error, dataRaw] = await fetchByUuid(uuid);
2673
- if (error !== null) {
2674
- throw new Error(error);
2675
- }
2676
- if (!("tree" in dataRaw.ochre)) {
2677
- throw new Error("Invalid OCHRE data: API response missing 'tree' key");
2678
- }
2679
- const tree = parseTree(dataRaw.ochre.tree);
2680
- if (!tree) {
2681
- throw new Error("Invalid OCHRE data: Could not parse tree");
2682
- }
2683
- const data = {
2684
- uuid: parseFakeString(dataRaw.ochre.uuid),
2685
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2686
- belongsTo: {
2687
- uuid: dataRaw.ochre.uuidBelongsTo,
2688
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2689
- },
2690
- metadata: parseMetadata(dataRaw.ochre.metadata),
2691
- item: tree
2537
+ return {
2538
+ error: error instanceof Error ? error.message : "Unknown error",
2539
+ metadata: void 0,
2540
+ belongsTo: void 0,
2541
+ item: void 0,
2542
+ category: void 0
2692
2543
  };
2693
- return { metadata: data.metadata, tree: data.item };
2694
- } catch (error) {
2695
- console.error(error);
2696
- return null;
2697
- }
2698
- }
2699
-
2700
- // src/utils/fetchers/website.ts
2701
- async function fetchWebsite(abbreviation) {
2702
- try {
2703
- const response = await fetch(
2704
- `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`
2705
- );
2706
- if (!response.ok) {
2707
- throw new Error("Failed to fetch website");
2708
- }
2709
- const data = await response.json();
2710
- if (!("ochre" in data.result) || !("tree" in data.result.ochre)) {
2711
- throw new Error("Failed to fetch website");
2712
- }
2713
- const projectIdentification = data.result.ochre.metadata.project?.identification ? parseIdentification(data.result.ochre.metadata.project.identification) : null;
2714
- const website = await parseWebsite(
2715
- data.result.ochre.tree,
2716
- projectIdentification?.label ?? "",
2717
- data.result.ochre.metadata.project?.identification.website ?? null
2718
- );
2719
- return website;
2720
- } catch (error) {
2721
- console.error(error);
2722
- return null;
2723
2544
  }
2724
2545
  }
2725
2546
  export {
2726
- fetchBibliography,
2727
2547
  fetchByUuid,
2728
- fetchConcept,
2729
- fetchGallery,
2730
- fetchPeriod,
2731
- fetchPropertyValue,
2732
- fetchResource,
2733
- fetchSet,
2734
- fetchSpatialUnit,
2735
- fetchTree,
2736
- fetchWebsite,
2548
+ fetchItem,
2737
2549
  filterProperties,
2738
2550
  getAllPropertyLabels,
2739
2551
  getPropertyByLabel,