@digitalculture/ochre-sdk 0.5.19 → 0.6.0

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,238 @@
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 renderOptionsSchema = z.string().transform((str) => str.split(" ")).pipe(
64
+ z.array(
65
+ z.enum([
34
66
  "bold",
35
67
  "italic",
36
68
  "underline"
37
69
  ])
38
70
  )
39
71
  );
40
- var whitespaceSchema = z2.string().transform((str) => str.split(" ")).pipe(
41
- z2.array(
42
- z2.enum([
72
+ var whitespaceSchema = z.string().transform((str) => str.split(" ")).pipe(
73
+ z.array(
74
+ z.enum([
43
75
  "newline",
44
76
  "trailing",
45
77
  "leading"
46
78
  ])
47
79
  )
48
80
  );
49
- var emailSchema = z2.string().email({ message: "Invalid email" });
81
+ var emailSchema = z.string().email({ message: "Invalid email" });
82
+
83
+ // src/utils/helpers.ts
84
+ function getItemCategory(keys) {
85
+ const categoryFound = keys.find(
86
+ (key) => categorySchema.safeParse(key).success
87
+ );
88
+ if (!categoryFound) {
89
+ const unknownKey = keys.find(
90
+ (key) => ![
91
+ "uuid",
92
+ "uuidBelongsTo",
93
+ "belongsTo",
94
+ "publicationDateTime",
95
+ "metadata",
96
+ "languages"
97
+ ].includes(key)
98
+ );
99
+ throw new Error(`Invalid OCHRE data; found unexpected "${unknownKey}" key`);
100
+ }
101
+ const categoryKey = categorySchema.parse(categoryFound);
102
+ return categoryKey;
103
+ }
104
+
105
+ // src/utils/getters.ts
106
+ var DEFAULT_OPTIONS = {
107
+ searchNestedProperties: false
108
+ };
109
+ function getPropertyByLabel(properties, label, options = DEFAULT_OPTIONS) {
110
+ const { searchNestedProperties } = options;
111
+ const property = properties.find((property2) => property2.label === label);
112
+ if (property) {
113
+ return property;
114
+ }
115
+ if (searchNestedProperties) {
116
+ for (const property2 of properties) {
117
+ if (property2.properties.length > 0) {
118
+ const nestedResult = getPropertyByLabel(property2.properties, label, {
119
+ searchNestedProperties
120
+ });
121
+ if (nestedResult) {
122
+ return nestedResult;
123
+ }
124
+ }
125
+ }
126
+ }
127
+ return null;
128
+ }
129
+ function getPropertyValuesByLabel(properties, label, options = DEFAULT_OPTIONS) {
130
+ const { searchNestedProperties } = options;
131
+ const property = properties.find((property2) => property2.label === label);
132
+ if (property) {
133
+ return property.values.map((value) => value.content);
134
+ }
135
+ if (searchNestedProperties) {
136
+ for (const property2 of properties) {
137
+ if (property2.properties.length > 0) {
138
+ const nestedResult = getPropertyValuesByLabel(
139
+ property2.properties,
140
+ label,
141
+ { searchNestedProperties }
142
+ );
143
+ if (nestedResult) {
144
+ return nestedResult;
145
+ }
146
+ }
147
+ }
148
+ }
149
+ return null;
150
+ }
151
+ function getPropertyValueByLabel(properties, label, options = DEFAULT_OPTIONS) {
152
+ const { searchNestedProperties } = options;
153
+ const values = getPropertyValuesByLabel(properties, label, {
154
+ searchNestedProperties
155
+ });
156
+ if (values !== null && values.length > 0) {
157
+ return values[0];
158
+ }
159
+ if (searchNestedProperties) {
160
+ for (const property of properties) {
161
+ if (property.properties.length > 0) {
162
+ const nestedResult = getPropertyValueByLabel(
163
+ property.properties,
164
+ label,
165
+ { searchNestedProperties }
166
+ );
167
+ if (nestedResult !== null) {
168
+ return nestedResult;
169
+ }
170
+ }
171
+ }
172
+ }
173
+ return null;
174
+ }
175
+ function getAllPropertyLabels(properties, options = DEFAULT_OPTIONS) {
176
+ const { searchNestedProperties } = options;
177
+ const labels = /* @__PURE__ */ new Set();
178
+ for (const property of properties) {
179
+ labels.add(property.label);
180
+ if (property.properties.length > 0 && searchNestedProperties) {
181
+ const nestedLabels = getAllPropertyLabels(property.properties, {
182
+ searchNestedProperties: true
183
+ });
184
+ for (const label of nestedLabels) {
185
+ labels.add(label);
186
+ }
187
+ }
188
+ }
189
+ return [...labels];
190
+ }
191
+ function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
192
+ const { searchNestedProperties } = options;
193
+ const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
194
+ if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
195
+ let isFound = property.values.some((value) => {
196
+ if (value.content === null) {
197
+ return false;
198
+ }
199
+ if (typeof value.content === "string") {
200
+ if (typeof filter.value !== "string") {
201
+ return false;
202
+ }
203
+ return value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"));
204
+ }
205
+ if (typeof value.content === "number") {
206
+ if (typeof filter.value !== "number") {
207
+ return false;
208
+ }
209
+ return value.content === filter.value;
210
+ }
211
+ if (typeof value.content === "boolean") {
212
+ if (typeof filter.value !== "boolean") {
213
+ return false;
214
+ }
215
+ return value.booleanValue === filter.value;
216
+ }
217
+ if (value.content instanceof Date) {
218
+ if (!(filter.value instanceof Date)) {
219
+ return false;
220
+ }
221
+ return value.content.getTime() === filter.value.getTime();
222
+ }
223
+ return false;
224
+ });
225
+ if (!isFound && searchNestedProperties) {
226
+ isFound = property.properties.some(
227
+ (property2) => filterProperties(property2, filter, { searchNestedProperties: true })
228
+ );
229
+ }
230
+ return isFound;
231
+ }
232
+ return false;
233
+ }
234
+
235
+ // src/utils/string.ts
50
236
  function getStringItemByLanguage(content, language) {
51
237
  const stringItemToFind = content.find((item) => item.lang === language);
52
238
  return stringItemToFind ?? null;
@@ -288,251 +474,43 @@ function parseStringDocumentItem(item, footnotes) {
288
474
  returnString = parseWhitespace(parseEmail(returnString), item.whitespace);
289
475
  }
290
476
  }
291
- 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
- );
477
+ return returnString.replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
478
+ }
479
+ function parseStringContent(content, language = "eng") {
480
+ switch (typeof content.content) {
481
+ case "string":
482
+ case "number":
483
+ case "boolean": {
484
+ return parseFakeString(content.content);
485
+ }
486
+ case "object": {
487
+ if (Array.isArray(content.content)) {
488
+ const stringItem = getStringItemByLanguage(content.content, language);
489
+ if (stringItem) {
490
+ return parseStringItem(stringItem);
491
+ } else {
492
+ const returnStringItem = content.content[0];
493
+ if (!returnStringItem) {
494
+ throw new Error(
495
+ `No string item found for language \u201C${language}\u201D in the following content:
496
+ ${JSON.stringify(
497
+ content.content
498
+ )}.`
499
+ );
500
+ }
501
+ return parseStringItem(returnStringItem);
502
+ }
503
+ } else {
504
+ return parseStringItem(content.content);
505
+ }
506
+ }
507
+ default: {
508
+ return String(content.content).replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
509
+ }
510
+ }
511
+ }
512
+
513
+ // src/utils/parse.ts
536
514
  function parseIdentification(identification) {
537
515
  try {
538
516
  const returnIdentification = {
@@ -1117,54 +1095,83 @@ function parseTree(tree) {
1117
1095
  return returnTree;
1118
1096
  }
1119
1097
  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
- );
1098
+ if (typeof set.items === "string") {
1099
+ throw new TypeError("Invalid OCHRE data: Set has no items");
1100
+ }
1101
+ const itemCategory = getItemCategory(Object.keys(set.items));
1102
+ let items = [];
1103
+ switch (itemCategory) {
1104
+ case "resource": {
1105
+ if (!("resource" in set.items)) {
1106
+ throw new Error("Invalid OCHRE data: Set has no resources");
1107
+ }
1108
+ items = parseResources(
1109
+ Array.isArray(set.items.resource) ? set.items.resource : [set.items.resource]
1110
+ );
1111
+ break;
1112
+ }
1113
+ case "spatialUnit": {
1114
+ if (!("spatialUnit" in set.items)) {
1115
+ throw new Error("Invalid OCHRE data: Set has no spatial units");
1116
+ }
1117
+ items = parseSpatialUnits(
1118
+ Array.isArray(set.items.spatialUnit) ? set.items.spatialUnit : [set.items.spatialUnit]
1119
+ );
1120
+ break;
1121
+ }
1122
+ case "concept": {
1123
+ if (!("concept" in set.items)) {
1124
+ throw new Error("Invalid OCHRE data: Set has no concepts");
1125
+ }
1126
+ items = parseConcepts(
1127
+ Array.isArray(set.items.concept) ? set.items.concept : [set.items.concept]
1128
+ );
1129
+ break;
1130
+ }
1131
+ case "period": {
1132
+ if (!("period" in set.items)) {
1133
+ throw new Error("Invalid OCHRE data: Set has no periods");
1134
+ }
1135
+ items = parsePeriods(
1136
+ Array.isArray(set.items.period) ? set.items.period : [set.items.period]
1137
+ );
1138
+ break;
1139
+ }
1140
+ case "bibliography": {
1141
+ if (!("bibliography" in set.items)) {
1142
+ throw new Error("Invalid OCHRE data: Set has no bibliographies");
1143
+ }
1144
+ items = parseBibliographies(
1145
+ Array.isArray(set.items.bibliography) ? set.items.bibliography : [set.items.bibliography]
1146
+ );
1147
+ break;
1148
+ }
1149
+ case "person": {
1150
+ if (!("person" in set.items)) {
1151
+ throw new Error("Invalid OCHRE data: Set has no persons");
1152
+ }
1153
+ items = parsePersons(
1154
+ Array.isArray(set.items.person) ? set.items.person : [set.items.person]
1155
+ );
1156
+ break;
1157
+ }
1158
+ case "propertyValue": {
1159
+ if (!("propertyValue" in set.items)) {
1160
+ throw new Error("Invalid OCHRE data: Set has no property values");
1161
+ }
1162
+ items = parsePropertyValues(
1163
+ Array.isArray(set.items.propertyValue) ? set.items.propertyValue : [set.items.propertyValue]
1164
+ );
1165
+ break;
1166
+ }
1167
+ default: {
1168
+ throw new Error("Invalid OCHRE data: Set has no items or is malformed");
1169
+ }
1164
1170
  }
1165
1171
  return {
1166
1172
  uuid: set.uuid,
1167
1173
  category: "set",
1174
+ itemCategory,
1168
1175
  publicationDateTime: set.publicationDateTime ? new Date(set.publicationDateTime) : null,
1169
1176
  date: set.date != null ? new Date(set.date) : null,
1170
1177
  license: parseLicense(set.availability),
@@ -1176,18 +1183,10 @@ function parseSet(set) {
1176
1183
  ) : [],
1177
1184
  type: set.type,
1178
1185
  number: set.n,
1179
- items: {
1180
- resources,
1181
- spatialUnits,
1182
- concepts,
1183
- periods,
1184
- bibliographies,
1185
- persons,
1186
- propertyValues
1187
- }
1186
+ items
1188
1187
  };
1189
1188
  }
1190
- function parseResource(resource, isNested = false) {
1189
+ function parseResource(resource) {
1191
1190
  const returnResource = {
1192
1191
  uuid: resource.uuid,
1193
1192
  category: "resource",
@@ -1230,34 +1229,20 @@ function parseResource(resource, isNested = false) {
1230
1229
  Array.isArray(resource.citedBibliography.reference) ? resource.citedBibliography.reference : [resource.citedBibliography.reference]
1231
1230
  ) : [],
1232
1231
  resources: resource.resource ? parseResources(
1233
- Array.isArray(resource.resource) ? resource.resource : [resource.resource],
1234
- true
1232
+ Array.isArray(resource.resource) ? resource.resource : [resource.resource]
1235
1233
  ) : []
1236
1234
  };
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
1235
  return returnResource;
1251
1236
  }
1252
- function parseResources(resources, isNested = false) {
1237
+ function parseResources(resources) {
1253
1238
  const returnResources = [];
1254
1239
  const resourcesToParse = Array.isArray(resources) ? resources : [resources];
1255
1240
  for (const resource of resourcesToParse) {
1256
- returnResources.push(parseResource(resource, isNested));
1241
+ returnResources.push(parseResource(resource));
1257
1242
  }
1258
1243
  return returnResources;
1259
1244
  }
1260
- function parseSpatialUnit(spatialUnit, isNested = false) {
1245
+ function parseSpatialUnit(spatialUnit) {
1261
1246
  const returnSpatialUnit = {
1262
1247
  uuid: spatialUnit.uuid,
1263
1248
  category: "spatialUnit",
@@ -1277,34 +1262,22 @@ function parseSpatialUnit(spatialUnit, isNested = false) {
1277
1262
  ) : spatialUnit.observation ? [parseObservation(spatialUnit.observation)] : [],
1278
1263
  events: "events" in spatialUnit && spatialUnit.events ? parseEvents(
1279
1264
  Array.isArray(spatialUnit.events.event) ? spatialUnit.events.event : [spatialUnit.events.event]
1265
+ ) : [],
1266
+ properties: "properties" in spatialUnit && spatialUnit.properties ? parseProperties(
1267
+ Array.isArray(spatialUnit.properties.property) ? spatialUnit.properties.property : [spatialUnit.properties.property]
1280
1268
  ) : []
1281
1269
  };
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
1270
  return returnSpatialUnit;
1296
1271
  }
1297
- function parseSpatialUnits(spatialUnits, isNested = false) {
1272
+ function parseSpatialUnits(spatialUnits) {
1298
1273
  const returnSpatialUnits = [];
1299
1274
  const spatialUnitsToParse = Array.isArray(spatialUnits) ? spatialUnits : [spatialUnits];
1300
1275
  for (const spatialUnit of spatialUnitsToParse) {
1301
- returnSpatialUnits.push(
1302
- parseSpatialUnit(spatialUnit, isNested)
1303
- );
1276
+ returnSpatialUnits.push(parseSpatialUnit(spatialUnit));
1304
1277
  }
1305
1278
  return returnSpatialUnits;
1306
1279
  }
1307
- function parseConcept(concept, isNested = false) {
1280
+ function parseConcept(concept) {
1308
1281
  const returnConcept = {
1309
1282
  uuid: concept.uuid,
1310
1283
  category: "concept",
@@ -1317,17 +1290,6 @@ function parseConcept(concept, isNested = false) {
1317
1290
  Array.isArray(concept.interpretations.interpretation) ? concept.interpretations.interpretation : [concept.interpretations.interpretation]
1318
1291
  )
1319
1292
  };
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
1293
  return returnConcept;
1332
1294
  }
1333
1295
  var parseWebpageResources = async (webpageResources, type) => {
@@ -1370,11 +1332,11 @@ var parseWebpageResources = async (webpageResources, type) => {
1370
1332
  }
1371
1333
  return returnElements;
1372
1334
  };
1373
- function parseConcepts(concepts, isNested = false) {
1335
+ function parseConcepts(concepts) {
1374
1336
  const returnConcepts = [];
1375
1337
  const conceptsToParse = Array.isArray(concepts) ? concepts : [concepts];
1376
1338
  for (const concept of conceptsToParse) {
1377
- returnConcepts.push(parseConcept(concept, isNested));
1339
+ returnConcepts.push(parseConcept(concept));
1378
1340
  }
1379
1341
  return returnConcepts;
1380
1342
  }
@@ -1395,11 +1357,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1395
1357
  if (document === null) {
1396
1358
  const documentLink = links.find((link) => link.type === "internalDocument");
1397
1359
  if (documentLink) {
1398
- const documentResource = await fetchResource(documentLink.uuid);
1399
- if (documentResource === null) {
1360
+ const { item, error } = await fetchItem(documentLink.uuid, "resource");
1361
+ if (error !== null) {
1400
1362
  throw new Error("Failed to fetch OCHRE data");
1401
1363
  }
1402
- document = documentResource.resource.document;
1364
+ document = item.document;
1403
1365
  }
1404
1366
  }
1405
1367
  switch (componentName) {
@@ -2440,300 +2402,144 @@ async function parseWebsite(websiteTree, projectName, website) {
2440
2402
  };
2441
2403
  }
2442
2404
 
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) {
2405
+ // src/utils/fetchers/uuid.ts
2406
+ async function fetchByUuid(uuid) {
2510
2407
  try {
2511
- const parsed = gallerySchema.safeParse({ uuid, filter, page, perPage });
2512
- if (!parsed.success) {
2513
- throw new Error(parsed.error.message);
2514
- }
2408
+ const parsedUuid = uuidSchema.parse(uuid);
2515
2409
  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`
2410
+ `https://ochre.lib.uchicago.edu/ochre?uuid=${parsedUuid}&format=json&lang="*"`
2526
2411
  );
2527
2412
  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");
2413
+ throw new Error("Failed to fetch OCHRE data");
2533
2414
  }
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);
2415
+ const dataRaw = await response.json();
2416
+ if (!("ochre" in dataRaw)) {
2417
+ throw new Error("Invalid OCHRE data: API response missing 'ochre' key");
2559
2418
  }
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 };
2419
+ return [null, dataRaw];
2575
2420
  } catch (error) {
2576
- console.error(error);
2577
- return null;
2421
+ return [error instanceof Error ? error.message : "Unknown error", null];
2578
2422
  }
2579
2423
  }
2580
2424
 
2581
- // src/utils/fetchers/property-value.ts
2582
- async function fetchPropertyValue(uuid) {
2425
+ // src/utils/fetchers/item.ts
2426
+ async function fetchItem(uuid, category) {
2583
2427
  try {
2584
- const [error, dataRaw] = await fetchByUuid(uuid);
2428
+ const [error, data] = await fetchByUuid(uuid);
2585
2429
  if (error !== null) {
2586
2430
  throw new Error(error);
2587
2431
  }
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);
2432
+ const categoryKey = getItemCategory(Object.keys(data.ochre));
2433
+ let item;
2434
+ switch (categoryKey) {
2435
+ case "resource": {
2436
+ if (!("resource" in data.ochre)) {
2437
+ throw new Error(
2438
+ "Invalid OCHRE data: API response missing 'resource' key"
2439
+ );
2440
+ }
2441
+ item = parseResource(data.ochre.resource);
2442
+ break;
2443
+ }
2444
+ case "spatialUnit": {
2445
+ if (!("spatialUnit" in data.ochre)) {
2446
+ throw new Error(
2447
+ "Invalid OCHRE data: API response missing 'spatialUnit' key"
2448
+ );
2449
+ }
2450
+ item = parseSpatialUnit(data.ochre.spatialUnit);
2451
+ break;
2452
+ }
2453
+ case "concept": {
2454
+ if (!("concept" in data.ochre)) {
2455
+ throw new Error(
2456
+ "Invalid OCHRE data: API response missing 'concept' key"
2457
+ );
2458
+ }
2459
+ item = parseConcept(data.ochre.concept);
2460
+ break;
2461
+ }
2462
+ case "period": {
2463
+ if (!("period" in data.ochre)) {
2464
+ throw new Error(
2465
+ "Invalid OCHRE data: API response missing 'period' key"
2466
+ );
2467
+ }
2468
+ item = parsePeriod(data.ochre.period);
2469
+ break;
2470
+ }
2471
+ case "bibliography": {
2472
+ if (!("bibliography" in data.ochre)) {
2473
+ throw new Error(
2474
+ "Invalid OCHRE data: API response missing 'bibliography' key"
2475
+ );
2476
+ }
2477
+ item = parseBibliography(data.ochre.bibliography);
2478
+ break;
2479
+ }
2480
+ case "person": {
2481
+ if (!("person" in data.ochre)) {
2482
+ throw new Error(
2483
+ "Invalid OCHRE data: API response missing 'person' key"
2484
+ );
2485
+ }
2486
+ item = parsePerson(data.ochre.person);
2487
+ break;
2488
+ }
2489
+ case "propertyValue": {
2490
+ if (!("propertyValue" in data.ochre)) {
2491
+ throw new Error(
2492
+ "Invalid OCHRE data: API response missing 'propertyValue' key"
2493
+ );
2494
+ }
2495
+ item = parsePropertyValue(data.ochre.propertyValue);
2496
+ break;
2497
+ }
2498
+ case "set": {
2499
+ if (!("set" in data.ochre)) {
2500
+ throw new Error("Invalid OCHRE data: API response missing 'set' key");
2501
+ }
2502
+ item = parseSet(data.ochre.set);
2503
+ break;
2504
+ }
2505
+ case "tree": {
2506
+ if (!("tree" in data.ochre)) {
2507
+ throw new Error(
2508
+ "Invalid OCHRE data: API response missing 'tree' key"
2509
+ );
2510
+ }
2511
+ item = parseTree(data.ochre.tree);
2512
+ break;
2513
+ }
2514
+ default: {
2515
+ throw new Error("Invalid category");
2516
+ }
2617
2517
  }
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
2518
+ const metadata = parseMetadata(data.ochre.metadata);
2519
+ const belongsTo = {
2520
+ uuid: data.ochre.uuidBelongsTo,
2521
+ abbreviation: parseFakeString(data.ochre.belongsTo)
2631
2522
  };
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
2523
+ return {
2524
+ error: null,
2525
+ metadata,
2526
+ belongsTo,
2527
+ item,
2528
+ category
2661
2529
  };
2662
- return { metadata: data.metadata, spatialUnit: data.item };
2663
2530
  } 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
2531
+ return {
2532
+ error: error instanceof Error ? error.message : "Unknown error",
2533
+ metadata: void 0,
2534
+ belongsTo: void 0,
2535
+ item: void 0,
2536
+ category: void 0
2692
2537
  };
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
2538
  }
2724
2539
  }
2725
2540
  export {
2726
- fetchBibliography,
2727
2541
  fetchByUuid,
2728
- fetchConcept,
2729
- fetchGallery,
2730
- fetchPeriod,
2731
- fetchPropertyValue,
2732
- fetchResource,
2733
- fetchSet,
2734
- fetchSpatialUnit,
2735
- fetchTree,
2736
- fetchWebsite,
2542
+ fetchItem,
2737
2543
  filterProperties,
2738
2544
  getAllPropertyLabels,
2739
2545
  getPropertyByLabel,