@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.cjs CHANGED
@@ -20,17 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- fetchBibliography: () => fetchBibliography,
24
23
  fetchByUuid: () => fetchByUuid,
25
- fetchConcept: () => fetchConcept,
26
- fetchGallery: () => fetchGallery,
27
- fetchPeriod: () => fetchPeriod,
28
- fetchPropertyValue: () => fetchPropertyValue,
29
- fetchResource: () => fetchResource,
30
- fetchSet: () => fetchSet,
31
- fetchSpatialUnit: () => fetchSpatialUnit,
32
- fetchTree: () => fetchTree,
33
- fetchWebsite: () => fetchWebsite,
24
+ fetchItem: () => fetchItem,
34
25
  filterProperties: () => filterProperties,
35
26
  getAllPropertyLabels: () => getAllPropertyLabels,
36
27
  getPropertyByLabel: () => getPropertyByLabel,
@@ -79,55 +70,241 @@ __export(index_exports, {
79
70
  });
80
71
  module.exports = __toCommonJS(index_exports);
81
72
 
82
- // src/utils/parse.ts
83
- var import_zod3 = require("zod");
84
-
85
- // src/utils/fetchers/generic.ts
73
+ // src/schemas.ts
86
74
  var import_zod = require("zod");
87
75
  var uuidSchema = import_zod.z.string().uuid({ message: "Invalid UUID provided" });
88
- async function fetchByUuid(uuid) {
89
- try {
90
- const result = uuidSchema.safeParse(uuid);
91
- if (!result.success) {
92
- throw new Error(result.error.issues[0]?.message);
93
- }
94
- const response = await fetch(
95
- `https://ochre.lib.uchicago.edu/ochre?uuid=${uuid}&format=json&lang="*"`
96
- );
97
- if (!response.ok) {
98
- throw new Error("Failed to fetch OCHRE data");
99
- }
100
- const dataRaw = await response.json();
101
- if (!("ochre" in dataRaw)) {
102
- throw new Error("Invalid OCHRE data: API response missing 'ochre' key");
103
- }
104
- return [null, dataRaw];
105
- } catch (error) {
106
- return [error instanceof Error ? error.message : "Unknown error", null];
107
- }
108
- }
109
-
110
- // src/utils/string.ts
111
- var import_zod2 = require("zod");
112
- var renderOptionsSchema = import_zod2.z.string().transform((str) => str.split(" ")).pipe(
113
- import_zod2.z.array(
114
- import_zod2.z.enum([
76
+ var websiteSchema = import_zod.z.object({
77
+ type: import_zod.z.enum(
78
+ [
79
+ "traditional",
80
+ "digital-collection",
81
+ "plum",
82
+ "cedar",
83
+ "elm",
84
+ "maple",
85
+ "oak",
86
+ "palm"
87
+ ],
88
+ { message: "Invalid website type" }
89
+ ),
90
+ status: import_zod.z.enum(
91
+ ["development", "preview", "production"],
92
+ { message: "Invalid website status" }
93
+ ),
94
+ privacy: import_zod.z.enum(
95
+ ["public", "password", "private"],
96
+ { message: "Invalid website privacy" }
97
+ )
98
+ });
99
+ var componentSchema = import_zod.z.enum(
100
+ [
101
+ "annotated-document",
102
+ "annotated-image",
103
+ "bibliography",
104
+ "blog",
105
+ "button",
106
+ "collection",
107
+ "empty-space",
108
+ "filter-categories",
109
+ "iframe",
110
+ "iiif-viewer",
111
+ "image",
112
+ "image-gallery",
113
+ "n-columns",
114
+ "n-rows",
115
+ "network-graph",
116
+ "search-bar",
117
+ "table",
118
+ "text",
119
+ "timeline",
120
+ "video"
121
+ ],
122
+ { message: "Invalid component" }
123
+ );
124
+ var categorySchema = import_zod.z.enum([
125
+ "resource",
126
+ "spatialUnit",
127
+ "concept",
128
+ "period",
129
+ "bibliography",
130
+ "person",
131
+ "propertyValue",
132
+ "set",
133
+ "tree"
134
+ ]);
135
+ var renderOptionsSchema = import_zod.z.string().transform((str) => str.split(" ")).pipe(
136
+ import_zod.z.array(
137
+ import_zod.z.enum([
115
138
  "bold",
116
139
  "italic",
117
140
  "underline"
118
141
  ])
119
142
  )
120
143
  );
121
- var whitespaceSchema = import_zod2.z.string().transform((str) => str.split(" ")).pipe(
122
- import_zod2.z.array(
123
- import_zod2.z.enum([
144
+ var whitespaceSchema = import_zod.z.string().transform((str) => str.split(" ")).pipe(
145
+ import_zod.z.array(
146
+ import_zod.z.enum([
124
147
  "newline",
125
148
  "trailing",
126
149
  "leading"
127
150
  ])
128
151
  )
129
152
  );
130
- var emailSchema = import_zod2.z.string().email({ message: "Invalid email" });
153
+ var emailSchema = import_zod.z.string().email({ message: "Invalid email" });
154
+
155
+ // src/utils/helpers.ts
156
+ function getItemCategory(keys) {
157
+ const categoryFound = keys.find(
158
+ (key) => categorySchema.safeParse(key).success
159
+ );
160
+ if (!categoryFound) {
161
+ const unknownKey = keys.find(
162
+ (key) => ![
163
+ "uuid",
164
+ "uuidBelongsTo",
165
+ "belongsTo",
166
+ "publicationDateTime",
167
+ "metadata",
168
+ "languages"
169
+ ].includes(key)
170
+ );
171
+ throw new Error(`Invalid OCHRE data; found unexpected "${unknownKey}" key`);
172
+ }
173
+ const categoryKey = categorySchema.parse(categoryFound);
174
+ return categoryKey;
175
+ }
176
+
177
+ // src/utils/getters.ts
178
+ var DEFAULT_OPTIONS = {
179
+ searchNestedProperties: false
180
+ };
181
+ function getPropertyByLabel(properties, label, options = DEFAULT_OPTIONS) {
182
+ const { searchNestedProperties } = options;
183
+ const property = properties.find((property2) => property2.label === label);
184
+ if (property) {
185
+ return property;
186
+ }
187
+ if (searchNestedProperties) {
188
+ for (const property2 of properties) {
189
+ if (property2.properties.length > 0) {
190
+ const nestedResult = getPropertyByLabel(property2.properties, label, {
191
+ searchNestedProperties
192
+ });
193
+ if (nestedResult) {
194
+ return nestedResult;
195
+ }
196
+ }
197
+ }
198
+ }
199
+ return null;
200
+ }
201
+ function getPropertyValuesByLabel(properties, label, options = DEFAULT_OPTIONS) {
202
+ const { searchNestedProperties } = options;
203
+ const property = properties.find((property2) => property2.label === label);
204
+ if (property) {
205
+ return property.values.map((value) => value.content);
206
+ }
207
+ if (searchNestedProperties) {
208
+ for (const property2 of properties) {
209
+ if (property2.properties.length > 0) {
210
+ const nestedResult = getPropertyValuesByLabel(
211
+ property2.properties,
212
+ label,
213
+ { searchNestedProperties }
214
+ );
215
+ if (nestedResult) {
216
+ return nestedResult;
217
+ }
218
+ }
219
+ }
220
+ }
221
+ return null;
222
+ }
223
+ function getPropertyValueByLabel(properties, label, options = DEFAULT_OPTIONS) {
224
+ const { searchNestedProperties } = options;
225
+ const values = getPropertyValuesByLabel(properties, label, {
226
+ searchNestedProperties
227
+ });
228
+ if (values !== null && values.length > 0) {
229
+ return values[0];
230
+ }
231
+ if (searchNestedProperties) {
232
+ for (const property of properties) {
233
+ if (property.properties.length > 0) {
234
+ const nestedResult = getPropertyValueByLabel(
235
+ property.properties,
236
+ label,
237
+ { searchNestedProperties }
238
+ );
239
+ if (nestedResult !== null) {
240
+ return nestedResult;
241
+ }
242
+ }
243
+ }
244
+ }
245
+ return null;
246
+ }
247
+ function getAllPropertyLabels(properties, options = DEFAULT_OPTIONS) {
248
+ const { searchNestedProperties } = options;
249
+ const labels = /* @__PURE__ */ new Set();
250
+ for (const property of properties) {
251
+ labels.add(property.label);
252
+ if (property.properties.length > 0 && searchNestedProperties) {
253
+ const nestedLabels = getAllPropertyLabels(property.properties, {
254
+ searchNestedProperties: true
255
+ });
256
+ for (const label of nestedLabels) {
257
+ labels.add(label);
258
+ }
259
+ }
260
+ }
261
+ return [...labels];
262
+ }
263
+ function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
264
+ const { searchNestedProperties } = options;
265
+ const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
266
+ if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
267
+ let isFound = property.values.some((value) => {
268
+ if (value.content === null) {
269
+ return false;
270
+ }
271
+ if (typeof value.content === "string") {
272
+ if (typeof filter.value !== "string") {
273
+ return false;
274
+ }
275
+ return value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"));
276
+ }
277
+ if (typeof value.content === "number") {
278
+ if (typeof filter.value !== "number") {
279
+ return false;
280
+ }
281
+ return value.content === filter.value;
282
+ }
283
+ if (typeof value.content === "boolean") {
284
+ if (typeof filter.value !== "boolean") {
285
+ return false;
286
+ }
287
+ return value.booleanValue === filter.value;
288
+ }
289
+ if (value.content instanceof Date) {
290
+ if (!(filter.value instanceof Date)) {
291
+ return false;
292
+ }
293
+ return value.content.getTime() === filter.value.getTime();
294
+ }
295
+ return false;
296
+ });
297
+ if (!isFound && searchNestedProperties) {
298
+ isFound = property.properties.some(
299
+ (property2) => filterProperties(property2, filter, { searchNestedProperties: true })
300
+ );
301
+ }
302
+ return isFound;
303
+ }
304
+ return false;
305
+ }
306
+
307
+ // src/utils/string.ts
131
308
  function getStringItemByLanguage(content, language) {
132
309
  const stringItemToFind = content.find((item) => item.lang === language);
133
310
  return stringItemToFind ?? null;
@@ -369,251 +546,43 @@ function parseStringDocumentItem(item, footnotes) {
369
546
  returnString = parseWhitespace(parseEmail(returnString), item.whitespace);
370
547
  }
371
548
  }
372
- return returnString.replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
373
- }
374
- function parseStringContent(content, language = "eng") {
375
- switch (typeof content.content) {
376
- case "string":
377
- case "number":
378
- case "boolean": {
379
- return parseFakeString(content.content);
380
- }
381
- case "object": {
382
- if (Array.isArray(content.content)) {
383
- const stringItem = getStringItemByLanguage(content.content, language);
384
- if (stringItem) {
385
- return parseStringItem(stringItem);
386
- } else {
387
- const returnStringItem = content.content[0];
388
- if (!returnStringItem) {
389
- throw new Error(
390
- `No string item found for language \u201C${language}\u201D in the following content:
391
- ${JSON.stringify(
392
- content.content
393
- )}.`
394
- );
395
- }
396
- return parseStringItem(returnStringItem);
397
- }
398
- } else {
399
- return parseStringItem(content.content);
400
- }
401
- }
402
- default: {
403
- return String(content.content).replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
404
- }
405
- }
406
- }
407
-
408
- // src/utils/fetchers/resource.ts
409
- async function fetchResource(uuid) {
410
- try {
411
- const [error, dataRaw] = await fetchByUuid(uuid);
412
- if (error !== null) {
413
- throw new Error(error);
414
- }
415
- if (!("resource" in dataRaw.ochre)) {
416
- throw new Error(
417
- "Invalid OCHRE data: API response missing 'resource' key"
418
- );
419
- }
420
- const resourceItem = parseResource(dataRaw.ochre.resource);
421
- const data = {
422
- uuid: parseFakeString(dataRaw.ochre.uuid),
423
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
424
- belongsTo: {
425
- uuid: dataRaw.ochre.uuidBelongsTo,
426
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
427
- },
428
- metadata: parseMetadata(dataRaw.ochre.metadata),
429
- item: resourceItem
430
- };
431
- return { metadata: data.metadata, resource: data.item };
432
- } catch (error) {
433
- console.error(error);
434
- return null;
435
- }
436
- }
437
-
438
- // src/utils/getters.ts
439
- var DEFAULT_OPTIONS = {
440
- searchNestedProperties: false
441
- };
442
- function getPropertyByLabel(properties, label, options = DEFAULT_OPTIONS) {
443
- const { searchNestedProperties } = options;
444
- const property = properties.find((property2) => property2.label === label);
445
- if (property) {
446
- return property;
447
- }
448
- if (searchNestedProperties) {
449
- for (const property2 of properties) {
450
- if (property2.properties.length > 0) {
451
- const nestedResult = getPropertyByLabel(property2.properties, label, {
452
- searchNestedProperties
453
- });
454
- if (nestedResult) {
455
- return nestedResult;
456
- }
457
- }
458
- }
459
- }
460
- return null;
461
- }
462
- function getPropertyValuesByLabel(properties, label, options = DEFAULT_OPTIONS) {
463
- const { searchNestedProperties } = options;
464
- const property = properties.find((property2) => property2.label === label);
465
- if (property) {
466
- return property.values.map((value) => value.content);
467
- }
468
- if (searchNestedProperties) {
469
- for (const property2 of properties) {
470
- if (property2.properties.length > 0) {
471
- const nestedResult = getPropertyValuesByLabel(
472
- property2.properties,
473
- label,
474
- { searchNestedProperties }
475
- );
476
- if (nestedResult) {
477
- return nestedResult;
478
- }
479
- }
480
- }
481
- }
482
- return null;
483
- }
484
- function getPropertyValueByLabel(properties, label, options = DEFAULT_OPTIONS) {
485
- const { searchNestedProperties } = options;
486
- const values = getPropertyValuesByLabel(properties, label, {
487
- searchNestedProperties
488
- });
489
- if (values !== null && values.length > 0) {
490
- return values[0];
491
- }
492
- if (searchNestedProperties) {
493
- for (const property of properties) {
494
- if (property.properties.length > 0) {
495
- const nestedResult = getPropertyValueByLabel(
496
- property.properties,
497
- label,
498
- { searchNestedProperties }
499
- );
500
- if (nestedResult !== null) {
501
- return nestedResult;
502
- }
503
- }
504
- }
505
- }
506
- return null;
507
- }
508
- function getAllPropertyLabels(properties, options = DEFAULT_OPTIONS) {
509
- const { searchNestedProperties } = options;
510
- const labels = /* @__PURE__ */ new Set();
511
- for (const property of properties) {
512
- labels.add(property.label);
513
- if (property.properties.length > 0 && searchNestedProperties) {
514
- const nestedLabels = getAllPropertyLabels(property.properties, {
515
- searchNestedProperties: true
516
- });
517
- for (const label of nestedLabels) {
518
- labels.add(label);
519
- }
520
- }
521
- }
522
- return [...labels];
523
- }
524
- function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
525
- const { searchNestedProperties } = options;
526
- const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
527
- if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
528
- let isFound = property.values.some((value) => {
529
- if (value.content === null) {
530
- return false;
531
- }
532
- if (typeof value.content === "string") {
533
- if (typeof filter.value !== "string") {
534
- return false;
535
- }
536
- return value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"));
537
- }
538
- if (typeof value.content === "number") {
539
- if (typeof filter.value !== "number") {
540
- return false;
541
- }
542
- return value.content === filter.value;
543
- }
544
- if (typeof value.content === "boolean") {
545
- if (typeof filter.value !== "boolean") {
546
- return false;
547
- }
548
- return value.booleanValue === filter.value;
549
- }
550
- if (value.content instanceof Date) {
551
- if (!(filter.value instanceof Date)) {
552
- return false;
553
- }
554
- return value.content.getTime() === filter.value.getTime();
555
- }
556
- return false;
557
- });
558
- if (!isFound && searchNestedProperties) {
559
- isFound = property.properties.some(
560
- (property2) => filterProperties(property2, filter, { searchNestedProperties: true })
561
- );
562
- }
563
- return isFound;
564
- }
565
- return false;
566
- }
567
-
568
- // src/utils/parse.ts
569
- var websiteSchema = import_zod3.z.object({
570
- type: import_zod3.z.enum(
571
- [
572
- "traditional",
573
- "digital-collection",
574
- "plum",
575
- "cedar",
576
- "elm",
577
- "maple",
578
- "oak",
579
- "palm"
580
- ],
581
- { message: "Invalid website type" }
582
- ),
583
- status: import_zod3.z.enum(
584
- ["development", "preview", "production"],
585
- { message: "Invalid website status" }
586
- ),
587
- privacy: import_zod3.z.enum(
588
- ["public", "password", "private"],
589
- { message: "Invalid website privacy" }
590
- )
591
- });
592
- var componentSchema = import_zod3.z.enum(
593
- [
594
- "annotated-document",
595
- "annotated-image",
596
- "bibliography",
597
- "blog",
598
- "button",
599
- "collection",
600
- "empty-space",
601
- "filter-categories",
602
- "iframe",
603
- "iiif-viewer",
604
- "image",
605
- "image-gallery",
606
- "n-columns",
607
- "n-rows",
608
- "network-graph",
609
- "search-bar",
610
- "table",
611
- "text",
612
- "timeline",
613
- "video"
614
- ],
615
- { message: "Invalid component" }
616
- );
549
+ return returnString.replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
550
+ }
551
+ function parseStringContent(content, language = "eng") {
552
+ switch (typeof content.content) {
553
+ case "string":
554
+ case "number":
555
+ case "boolean": {
556
+ return parseFakeString(content.content);
557
+ }
558
+ case "object": {
559
+ if (Array.isArray(content.content)) {
560
+ const stringItem = getStringItemByLanguage(content.content, language);
561
+ if (stringItem) {
562
+ return parseStringItem(stringItem);
563
+ } else {
564
+ const returnStringItem = content.content[0];
565
+ if (!returnStringItem) {
566
+ throw new Error(
567
+ `No string item found for language \u201C${language}\u201D in the following content:
568
+ ${JSON.stringify(
569
+ content.content
570
+ )}.`
571
+ );
572
+ }
573
+ return parseStringItem(returnStringItem);
574
+ }
575
+ } else {
576
+ return parseStringItem(content.content);
577
+ }
578
+ }
579
+ default: {
580
+ return String(content.content).replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
581
+ }
582
+ }
583
+ }
584
+
585
+ // src/utils/parse.ts
617
586
  function parseIdentification(identification) {
618
587
  try {
619
588
  const returnIdentification = {
@@ -1198,54 +1167,83 @@ function parseTree(tree) {
1198
1167
  return returnTree;
1199
1168
  }
1200
1169
  function parseSet(set) {
1201
- let resources = [];
1202
- let spatialUnits = [];
1203
- let concepts = [];
1204
- let periods = [];
1205
- let bibliographies = [];
1206
- let persons = [];
1207
- let propertyValues = [];
1208
- if (typeof set.items !== "string" && "resource" in set.items) {
1209
- resources = parseResources(
1210
- Array.isArray(set.items.resource) ? set.items.resource : [set.items.resource],
1211
- true
1212
- );
1213
- }
1214
- if (typeof set.items !== "string" && "spatialUnit" in set.items) {
1215
- spatialUnits = parseSpatialUnits(
1216
- Array.isArray(set.items.spatialUnit) ? set.items.spatialUnit : [set.items.spatialUnit],
1217
- true
1218
- );
1219
- }
1220
- if (typeof set.items !== "string" && "concept" in set.items) {
1221
- concepts = parseConcepts(
1222
- Array.isArray(set.items.concept) ? set.items.concept : [set.items.concept],
1223
- true
1224
- );
1225
- }
1226
- if (typeof set.items !== "string" && "period" in set.items) {
1227
- periods = parsePeriods(
1228
- Array.isArray(set.items.period) ? set.items.period : [set.items.period]
1229
- );
1230
- }
1231
- if (typeof set.items !== "string" && "bibliography" in set.items) {
1232
- bibliographies = parseBibliographies(
1233
- Array.isArray(set.items.bibliography) ? set.items.bibliography : [set.items.bibliography]
1234
- );
1235
- }
1236
- if (typeof set.items !== "string" && "person" in set.items) {
1237
- persons = parsePersons(
1238
- Array.isArray(set.items.person) ? set.items.person : [set.items.person]
1239
- );
1240
- }
1241
- if (typeof set.items !== "string" && "propertyValue" in set.items) {
1242
- propertyValues = parsePropertyValues(
1243
- Array.isArray(set.items.propertyValue) ? set.items.propertyValue : [set.items.propertyValue]
1244
- );
1170
+ if (typeof set.items === "string") {
1171
+ throw new TypeError("Invalid OCHRE data: Set has no items");
1172
+ }
1173
+ const itemCategory = getItemCategory(Object.keys(set.items));
1174
+ let items = [];
1175
+ switch (itemCategory) {
1176
+ case "resource": {
1177
+ if (!("resource" in set.items)) {
1178
+ throw new Error("Invalid OCHRE data: Set has no resources");
1179
+ }
1180
+ items = parseResources(
1181
+ Array.isArray(set.items.resource) ? set.items.resource : [set.items.resource]
1182
+ );
1183
+ break;
1184
+ }
1185
+ case "spatialUnit": {
1186
+ if (!("spatialUnit" in set.items)) {
1187
+ throw new Error("Invalid OCHRE data: Set has no spatial units");
1188
+ }
1189
+ items = parseSpatialUnits(
1190
+ Array.isArray(set.items.spatialUnit) ? set.items.spatialUnit : [set.items.spatialUnit]
1191
+ );
1192
+ break;
1193
+ }
1194
+ case "concept": {
1195
+ if (!("concept" in set.items)) {
1196
+ throw new Error("Invalid OCHRE data: Set has no concepts");
1197
+ }
1198
+ items = parseConcepts(
1199
+ Array.isArray(set.items.concept) ? set.items.concept : [set.items.concept]
1200
+ );
1201
+ break;
1202
+ }
1203
+ case "period": {
1204
+ if (!("period" in set.items)) {
1205
+ throw new Error("Invalid OCHRE data: Set has no periods");
1206
+ }
1207
+ items = parsePeriods(
1208
+ Array.isArray(set.items.period) ? set.items.period : [set.items.period]
1209
+ );
1210
+ break;
1211
+ }
1212
+ case "bibliography": {
1213
+ if (!("bibliography" in set.items)) {
1214
+ throw new Error("Invalid OCHRE data: Set has no bibliographies");
1215
+ }
1216
+ items = parseBibliographies(
1217
+ Array.isArray(set.items.bibliography) ? set.items.bibliography : [set.items.bibliography]
1218
+ );
1219
+ break;
1220
+ }
1221
+ case "person": {
1222
+ if (!("person" in set.items)) {
1223
+ throw new Error("Invalid OCHRE data: Set has no persons");
1224
+ }
1225
+ items = parsePersons(
1226
+ Array.isArray(set.items.person) ? set.items.person : [set.items.person]
1227
+ );
1228
+ break;
1229
+ }
1230
+ case "propertyValue": {
1231
+ if (!("propertyValue" in set.items)) {
1232
+ throw new Error("Invalid OCHRE data: Set has no property values");
1233
+ }
1234
+ items = parsePropertyValues(
1235
+ Array.isArray(set.items.propertyValue) ? set.items.propertyValue : [set.items.propertyValue]
1236
+ );
1237
+ break;
1238
+ }
1239
+ default: {
1240
+ throw new Error("Invalid OCHRE data: Set has no items or is malformed");
1241
+ }
1245
1242
  }
1246
1243
  return {
1247
1244
  uuid: set.uuid,
1248
1245
  category: "set",
1246
+ itemCategory,
1249
1247
  publicationDateTime: set.publicationDateTime ? new Date(set.publicationDateTime) : null,
1250
1248
  date: set.date != null ? new Date(set.date) : null,
1251
1249
  license: parseLicense(set.availability),
@@ -1257,18 +1255,10 @@ function parseSet(set) {
1257
1255
  ) : [],
1258
1256
  type: set.type,
1259
1257
  number: set.n,
1260
- items: {
1261
- resources,
1262
- spatialUnits,
1263
- concepts,
1264
- periods,
1265
- bibliographies,
1266
- persons,
1267
- propertyValues
1268
- }
1258
+ items
1269
1259
  };
1270
1260
  }
1271
- function parseResource(resource, isNested = false) {
1261
+ function parseResource(resource) {
1272
1262
  const returnResource = {
1273
1263
  uuid: resource.uuid,
1274
1264
  category: "resource",
@@ -1311,34 +1301,20 @@ function parseResource(resource, isNested = false) {
1311
1301
  Array.isArray(resource.citedBibliography.reference) ? resource.citedBibliography.reference : [resource.citedBibliography.reference]
1312
1302
  ) : [],
1313
1303
  resources: resource.resource ? parseResources(
1314
- Array.isArray(resource.resource) ? resource.resource : [resource.resource],
1315
- true
1304
+ Array.isArray(resource.resource) ? resource.resource : [resource.resource]
1316
1305
  ) : []
1317
1306
  };
1318
- if (isNested) {
1319
- const returnNestedResource = {
1320
- ...returnResource,
1321
- publicationDateTime: null,
1322
- context: null,
1323
- license: null,
1324
- copyright: null
1325
- };
1326
- delete returnNestedResource.publicationDateTime;
1327
- delete returnNestedResource.license;
1328
- delete returnNestedResource.copyright;
1329
- return returnNestedResource;
1330
- }
1331
1307
  return returnResource;
1332
1308
  }
1333
- function parseResources(resources, isNested = false) {
1309
+ function parseResources(resources) {
1334
1310
  const returnResources = [];
1335
1311
  const resourcesToParse = Array.isArray(resources) ? resources : [resources];
1336
1312
  for (const resource of resourcesToParse) {
1337
- returnResources.push(parseResource(resource, isNested));
1313
+ returnResources.push(parseResource(resource));
1338
1314
  }
1339
1315
  return returnResources;
1340
1316
  }
1341
- function parseSpatialUnit(spatialUnit, isNested = false) {
1317
+ function parseSpatialUnit(spatialUnit) {
1342
1318
  const returnSpatialUnit = {
1343
1319
  uuid: spatialUnit.uuid,
1344
1320
  category: "spatialUnit",
@@ -1358,34 +1334,22 @@ function parseSpatialUnit(spatialUnit, isNested = false) {
1358
1334
  ) : spatialUnit.observation ? [parseObservation(spatialUnit.observation)] : [],
1359
1335
  events: "events" in spatialUnit && spatialUnit.events ? parseEvents(
1360
1336
  Array.isArray(spatialUnit.events.event) ? spatialUnit.events.event : [spatialUnit.events.event]
1337
+ ) : [],
1338
+ properties: "properties" in spatialUnit && spatialUnit.properties ? parseProperties(
1339
+ Array.isArray(spatialUnit.properties.property) ? spatialUnit.properties.property : [spatialUnit.properties.property]
1361
1340
  ) : []
1362
1341
  };
1363
- if (isNested) {
1364
- const returnNestedSpatialUnit = {
1365
- ...returnSpatialUnit,
1366
- publicationDateTime: null,
1367
- license: null,
1368
- properties: "properties" in spatialUnit && spatialUnit.properties ? parseProperties(
1369
- Array.isArray(spatialUnit.properties.property) ? spatialUnit.properties.property : [spatialUnit.properties.property]
1370
- ) : []
1371
- };
1372
- delete returnNestedSpatialUnit.publicationDateTime;
1373
- delete returnNestedSpatialUnit.license;
1374
- return returnNestedSpatialUnit;
1375
- }
1376
1342
  return returnSpatialUnit;
1377
1343
  }
1378
- function parseSpatialUnits(spatialUnits, isNested = false) {
1344
+ function parseSpatialUnits(spatialUnits) {
1379
1345
  const returnSpatialUnits = [];
1380
1346
  const spatialUnitsToParse = Array.isArray(spatialUnits) ? spatialUnits : [spatialUnits];
1381
1347
  for (const spatialUnit of spatialUnitsToParse) {
1382
- returnSpatialUnits.push(
1383
- parseSpatialUnit(spatialUnit, isNested)
1384
- );
1348
+ returnSpatialUnits.push(parseSpatialUnit(spatialUnit));
1385
1349
  }
1386
1350
  return returnSpatialUnits;
1387
1351
  }
1388
- function parseConcept(concept, isNested = false) {
1352
+ function parseConcept(concept) {
1389
1353
  const returnConcept = {
1390
1354
  uuid: concept.uuid,
1391
1355
  category: "concept",
@@ -1398,17 +1362,6 @@ function parseConcept(concept, isNested = false) {
1398
1362
  Array.isArray(concept.interpretations.interpretation) ? concept.interpretations.interpretation : [concept.interpretations.interpretation]
1399
1363
  )
1400
1364
  };
1401
- if (isNested) {
1402
- const returnNestedConcept = {
1403
- ...returnConcept,
1404
- publicationDateTime: null,
1405
- context: null,
1406
- license: null
1407
- };
1408
- delete returnNestedConcept.publicationDateTime;
1409
- delete returnNestedConcept.license;
1410
- return returnNestedConcept;
1411
- }
1412
1365
  return returnConcept;
1413
1366
  }
1414
1367
  var parseWebpageResources = async (webpageResources, type) => {
@@ -1451,11 +1404,11 @@ var parseWebpageResources = async (webpageResources, type) => {
1451
1404
  }
1452
1405
  return returnElements;
1453
1406
  };
1454
- function parseConcepts(concepts, isNested = false) {
1407
+ function parseConcepts(concepts) {
1455
1408
  const returnConcepts = [];
1456
1409
  const conceptsToParse = Array.isArray(concepts) ? concepts : [concepts];
1457
1410
  for (const concept of conceptsToParse) {
1458
- returnConcepts.push(parseConcept(concept, isNested));
1411
+ returnConcepts.push(parseConcept(concept));
1459
1412
  }
1460
1413
  return returnConcepts;
1461
1414
  }
@@ -1476,11 +1429,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1476
1429
  if (document === null) {
1477
1430
  const documentLink = links.find((link) => link.type === "internalDocument");
1478
1431
  if (documentLink) {
1479
- const documentResource = await fetchResource(documentLink.uuid);
1480
- if (documentResource === null) {
1432
+ const { item, error } = await fetchItem(documentLink.uuid, "resource");
1433
+ if (error !== null) {
1481
1434
  throw new Error("Failed to fetch OCHRE data");
1482
1435
  }
1483
- document = documentResource.resource.document;
1436
+ document = item.document;
1484
1437
  }
1485
1438
  }
1486
1439
  switch (componentName) {
@@ -2521,301 +2474,145 @@ async function parseWebsite(websiteTree, projectName, website) {
2521
2474
  };
2522
2475
  }
2523
2476
 
2524
- // src/utils/fetchers/bibliography.ts
2525
- async function fetchBibliography(uuid) {
2526
- try {
2527
- const [error, dataRaw] = await fetchByUuid(uuid);
2528
- if (error !== null) {
2529
- throw new Error(error);
2530
- }
2531
- if (!("bibliography" in dataRaw.ochre)) {
2532
- throw new Error(
2533
- "Invalid OCHRE data: API response missing 'bibliography' key"
2534
- );
2535
- }
2536
- const bibliographyItem = parseBibliography(dataRaw.ochre.bibliography);
2537
- const data = {
2538
- uuid: parseFakeString(dataRaw.ochre.uuid),
2539
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2540
- belongsTo: {
2541
- uuid: dataRaw.ochre.uuidBelongsTo,
2542
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2543
- },
2544
- metadata: parseMetadata(dataRaw.ochre.metadata),
2545
- item: bibliographyItem
2546
- };
2547
- return { metadata: data.metadata, bibliography: data.item };
2548
- } catch (error) {
2549
- console.error(error);
2550
- return null;
2551
- }
2552
- }
2553
-
2554
- // src/utils/fetchers/concept.ts
2555
- async function fetchConcept(uuid) {
2556
- try {
2557
- const [error, dataRaw] = await fetchByUuid(uuid);
2558
- if (error !== null) {
2559
- throw new Error(error);
2560
- }
2561
- if (!("concept" in dataRaw.ochre)) {
2562
- throw new Error("Invalid OCHRE data: API response missing 'concept' key");
2563
- }
2564
- const conceptItem = parseConcept(dataRaw.ochre.concept);
2565
- const data = {
2566
- uuid: parseFakeString(dataRaw.ochre.uuid),
2567
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2568
- belongsTo: {
2569
- uuid: dataRaw.ochre.uuidBelongsTo,
2570
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2571
- },
2572
- metadata: parseMetadata(dataRaw.ochre.metadata),
2573
- item: conceptItem
2574
- };
2575
- return { metadata: data.metadata, concept: data.item };
2576
- } catch (error) {
2577
- console.error(error);
2578
- return null;
2579
- }
2580
- }
2581
-
2582
- // src/utils/fetchers/gallery.ts
2583
- var import_zod4 = require("zod");
2584
- var gallerySchema = import_zod4.z.object({
2585
- uuid: import_zod4.z.string().uuid({ message: "Invalid UUID" }),
2586
- filter: import_zod4.z.string().optional(),
2587
- page: import_zod4.z.number().positive({ message: "Page must be positive" }),
2588
- perPage: import_zod4.z.number().positive({ message: "Per page must be positive" })
2589
- }).strict();
2590
- async function fetchGallery(uuid, filter, page, perPage) {
2477
+ // src/utils/fetchers/uuid.ts
2478
+ async function fetchByUuid(uuid) {
2591
2479
  try {
2592
- const parsed = gallerySchema.safeParse({ uuid, filter, page, perPage });
2593
- if (!parsed.success) {
2594
- throw new Error(parsed.error.message);
2595
- }
2480
+ const parsedUuid = uuidSchema.parse(uuid);
2596
2481
  const response = await fetch(
2597
- `https://ochre.lib.uchicago.edu/ochre?xquery=${encodeURIComponent(`
2598
- for $q in input()/ochre[@uuid='${uuid}']
2599
- let $filtered := $q/tree/items/resource[contains(lower-case(identification/label), lower-case('${filter}'))]
2600
- let $maxLength := count($filtered)
2601
- return <gallery maxLength='{$maxLength}'>
2602
- {$q/metadata/project}
2603
- {$q/metadata/item}
2604
- {$filtered[position() >= ${((page - 1) * perPage + 1).toString()} and position() < ${(page * perPage + 1).toString()}]}
2605
- </gallery>
2606
- `)}&format=json`
2482
+ `https://ochre.lib.uchicago.edu/ochre?uuid=${parsedUuid}&format=json&lang="*"`
2607
2483
  );
2608
2484
  if (!response.ok) {
2609
- throw new Error("Error fetching gallery items, please try again later.");
2610
- }
2611
- const data = await response.json();
2612
- if (!("gallery" in data.result)) {
2613
- throw new Error("Failed to fetch gallery");
2485
+ throw new Error("Failed to fetch OCHRE data");
2614
2486
  }
2615
- const galleryIdentification = parseIdentification(
2616
- data.result.gallery.item.identification
2617
- );
2618
- const galleryProjectIdentification = parseIdentification(
2619
- data.result.gallery.project.identification
2620
- );
2621
- const gallery = {
2622
- identification: galleryIdentification,
2623
- projectIdentification: galleryProjectIdentification,
2624
- resources: data.result.gallery.resource ? Array.isArray(data.result.gallery.resource) ? parseResources(data.result.gallery.resource) : [parseResource(data.result.gallery.resource)] : [],
2625
- maxLength: data.result.gallery.maxLength
2626
- };
2627
- return gallery;
2628
- } catch (error) {
2629
- console.error(error);
2630
- return null;
2631
- }
2632
- }
2633
-
2634
- // src/utils/fetchers/period.ts
2635
- async function fetchPeriod(uuid) {
2636
- try {
2637
- const [error, dataRaw] = await fetchByUuid(uuid);
2638
- if (error !== null) {
2639
- throw new Error(error);
2487
+ const dataRaw = await response.json();
2488
+ if (!("ochre" in dataRaw)) {
2489
+ throw new Error("Invalid OCHRE data: API response missing 'ochre' key");
2640
2490
  }
2641
- if (!("period" in dataRaw.ochre)) {
2642
- throw new Error("Invalid OCHRE data: API response missing 'period' key");
2643
- }
2644
- const periodItem = parsePeriod(dataRaw.ochre.period);
2645
- const data = {
2646
- uuid: parseFakeString(dataRaw.ochre.uuid),
2647
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2648
- belongsTo: {
2649
- uuid: dataRaw.ochre.uuidBelongsTo,
2650
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2651
- },
2652
- metadata: parseMetadata(dataRaw.ochre.metadata),
2653
- item: periodItem
2654
- };
2655
- return { metadata: data.metadata, period: data.item };
2491
+ return [null, dataRaw];
2656
2492
  } catch (error) {
2657
- console.error(error);
2658
- return null;
2493
+ return [error instanceof Error ? error.message : "Unknown error", null];
2659
2494
  }
2660
2495
  }
2661
2496
 
2662
- // src/utils/fetchers/property-value.ts
2663
- async function fetchPropertyValue(uuid) {
2497
+ // src/utils/fetchers/item.ts
2498
+ async function fetchItem(uuid, category) {
2664
2499
  try {
2665
- const [error, dataRaw] = await fetchByUuid(uuid);
2500
+ const [error, data] = await fetchByUuid(uuid);
2666
2501
  if (error !== null) {
2667
2502
  throw new Error(error);
2668
2503
  }
2669
- if (!("propertyValue" in dataRaw.ochre)) {
2670
- throw new Error(
2671
- "Invalid OCHRE data: API response missing 'propertyValue' key"
2672
- );
2673
- }
2674
- const propertyValueItem = parsePropertyValue(dataRaw.ochre.propertyValue);
2675
- const data = {
2676
- uuid: parseFakeString(dataRaw.ochre.uuid),
2677
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2678
- belongsTo: {
2679
- uuid: dataRaw.ochre.uuidBelongsTo,
2680
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2681
- },
2682
- metadata: parseMetadata(dataRaw.ochre.metadata),
2683
- item: propertyValueItem
2684
- };
2685
- return { metadata: data.metadata, propertyValue: data.item };
2686
- } catch (error) {
2687
- console.error(error);
2688
- return null;
2689
- }
2690
- }
2691
-
2692
- // src/utils/fetchers/set.ts
2693
- async function fetchSet(uuid) {
2694
- try {
2695
- const [error, dataRaw] = await fetchByUuid(uuid);
2696
- if (error !== null) {
2697
- throw new Error(error);
2504
+ const categoryKey = getItemCategory(Object.keys(data.ochre));
2505
+ let item;
2506
+ switch (categoryKey) {
2507
+ case "resource": {
2508
+ if (!("resource" in data.ochre)) {
2509
+ throw new Error(
2510
+ "Invalid OCHRE data: API response missing 'resource' key"
2511
+ );
2512
+ }
2513
+ item = parseResource(data.ochre.resource);
2514
+ break;
2515
+ }
2516
+ case "spatialUnit": {
2517
+ if (!("spatialUnit" in data.ochre)) {
2518
+ throw new Error(
2519
+ "Invalid OCHRE data: API response missing 'spatialUnit' key"
2520
+ );
2521
+ }
2522
+ item = parseSpatialUnit(data.ochre.spatialUnit);
2523
+ break;
2524
+ }
2525
+ case "concept": {
2526
+ if (!("concept" in data.ochre)) {
2527
+ throw new Error(
2528
+ "Invalid OCHRE data: API response missing 'concept' key"
2529
+ );
2530
+ }
2531
+ item = parseConcept(data.ochre.concept);
2532
+ break;
2533
+ }
2534
+ case "period": {
2535
+ if (!("period" in data.ochre)) {
2536
+ throw new Error(
2537
+ "Invalid OCHRE data: API response missing 'period' key"
2538
+ );
2539
+ }
2540
+ item = parsePeriod(data.ochre.period);
2541
+ break;
2542
+ }
2543
+ case "bibliography": {
2544
+ if (!("bibliography" in data.ochre)) {
2545
+ throw new Error(
2546
+ "Invalid OCHRE data: API response missing 'bibliography' key"
2547
+ );
2548
+ }
2549
+ item = parseBibliography(data.ochre.bibliography);
2550
+ break;
2551
+ }
2552
+ case "person": {
2553
+ if (!("person" in data.ochre)) {
2554
+ throw new Error(
2555
+ "Invalid OCHRE data: API response missing 'person' key"
2556
+ );
2557
+ }
2558
+ item = parsePerson(data.ochre.person);
2559
+ break;
2560
+ }
2561
+ case "propertyValue": {
2562
+ if (!("propertyValue" in data.ochre)) {
2563
+ throw new Error(
2564
+ "Invalid OCHRE data: API response missing 'propertyValue' key"
2565
+ );
2566
+ }
2567
+ item = parsePropertyValue(data.ochre.propertyValue);
2568
+ break;
2569
+ }
2570
+ case "set": {
2571
+ if (!("set" in data.ochre)) {
2572
+ throw new Error("Invalid OCHRE data: API response missing 'set' key");
2573
+ }
2574
+ item = parseSet(data.ochre.set);
2575
+ break;
2576
+ }
2577
+ case "tree": {
2578
+ if (!("tree" in data.ochre)) {
2579
+ throw new Error(
2580
+ "Invalid OCHRE data: API response missing 'tree' key"
2581
+ );
2582
+ }
2583
+ item = parseTree(data.ochre.tree);
2584
+ break;
2585
+ }
2586
+ default: {
2587
+ throw new Error("Invalid category");
2588
+ }
2698
2589
  }
2699
- if (!("set" in dataRaw.ochre)) {
2700
- throw new Error("Invalid OCHRE data: API response missing 'set' key");
2701
- }
2702
- const setItem = parseSet(dataRaw.ochre.set);
2703
- const data = {
2704
- uuid: parseFakeString(dataRaw.ochre.uuid),
2705
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2706
- belongsTo: {
2707
- uuid: dataRaw.ochre.uuidBelongsTo,
2708
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2709
- },
2710
- metadata: parseMetadata(dataRaw.ochre.metadata),
2711
- item: setItem
2590
+ const metadata = parseMetadata(data.ochre.metadata);
2591
+ const belongsTo = {
2592
+ uuid: data.ochre.uuidBelongsTo,
2593
+ abbreviation: parseFakeString(data.ochre.belongsTo)
2712
2594
  };
2713
- return { metadata: data.metadata, set: data.item };
2714
- } catch (error) {
2715
- console.error(error);
2716
- return null;
2717
- }
2718
- }
2719
-
2720
- // src/utils/fetchers/spatial-unit.ts
2721
- async function fetchSpatialUnit(uuid) {
2722
- try {
2723
- const [error, dataRaw] = await fetchByUuid(uuid);
2724
- if (error !== null) {
2725
- throw new Error(error);
2726
- }
2727
- if (!("spatialUnit" in dataRaw.ochre)) {
2728
- throw new Error(
2729
- "Invalid OCHRE data: API response missing 'spatialUnit' key"
2730
- );
2731
- }
2732
- const spatialUnitItem = parseSpatialUnit(dataRaw.ochre.spatialUnit);
2733
- const data = {
2734
- uuid: parseFakeString(dataRaw.ochre.uuid),
2735
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2736
- belongsTo: {
2737
- uuid: dataRaw.ochre.uuidBelongsTo,
2738
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2739
- },
2740
- metadata: parseMetadata(dataRaw.ochre.metadata),
2741
- item: spatialUnitItem
2595
+ return {
2596
+ error: null,
2597
+ metadata,
2598
+ belongsTo,
2599
+ item,
2600
+ category
2742
2601
  };
2743
- return { metadata: data.metadata, spatialUnit: data.item };
2744
2602
  } catch (error) {
2745
- console.error(error);
2746
- return null;
2747
- }
2748
- }
2749
-
2750
- // src/utils/fetchers/tree.ts
2751
- async function fetchTree(uuid) {
2752
- try {
2753
- const [error, dataRaw] = await fetchByUuid(uuid);
2754
- if (error !== null) {
2755
- throw new Error(error);
2756
- }
2757
- if (!("tree" in dataRaw.ochre)) {
2758
- throw new Error("Invalid OCHRE data: API response missing 'tree' key");
2759
- }
2760
- const tree = parseTree(dataRaw.ochre.tree);
2761
- if (!tree) {
2762
- throw new Error("Invalid OCHRE data: Could not parse tree");
2763
- }
2764
- const data = {
2765
- uuid: parseFakeString(dataRaw.ochre.uuid),
2766
- publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
2767
- belongsTo: {
2768
- uuid: dataRaw.ochre.uuidBelongsTo,
2769
- abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
2770
- },
2771
- metadata: parseMetadata(dataRaw.ochre.metadata),
2772
- item: tree
2603
+ return {
2604
+ error: error instanceof Error ? error.message : "Unknown error",
2605
+ metadata: void 0,
2606
+ belongsTo: void 0,
2607
+ item: void 0,
2608
+ category: void 0
2773
2609
  };
2774
- return { metadata: data.metadata, tree: data.item };
2775
- } catch (error) {
2776
- console.error(error);
2777
- return null;
2778
- }
2779
- }
2780
-
2781
- // src/utils/fetchers/website.ts
2782
- async function fetchWebsite(abbreviation) {
2783
- try {
2784
- const response = await fetch(
2785
- `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`
2786
- );
2787
- if (!response.ok) {
2788
- throw new Error("Failed to fetch website");
2789
- }
2790
- const data = await response.json();
2791
- if (!("ochre" in data.result) || !("tree" in data.result.ochre)) {
2792
- throw new Error("Failed to fetch website");
2793
- }
2794
- const projectIdentification = data.result.ochre.metadata.project?.identification ? parseIdentification(data.result.ochre.metadata.project.identification) : null;
2795
- const website = await parseWebsite(
2796
- data.result.ochre.tree,
2797
- projectIdentification?.label ?? "",
2798
- data.result.ochre.metadata.project?.identification.website ?? null
2799
- );
2800
- return website;
2801
- } catch (error) {
2802
- console.error(error);
2803
- return null;
2804
2610
  }
2805
2611
  }
2806
2612
  // Annotate the CommonJS export names for ESM import in node:
2807
2613
  0 && (module.exports = {
2808
- fetchBibliography,
2809
2614
  fetchByUuid,
2810
- fetchConcept,
2811
- fetchGallery,
2812
- fetchPeriod,
2813
- fetchPropertyValue,
2814
- fetchResource,
2815
- fetchSet,
2816
- fetchSpatialUnit,
2817
- fetchTree,
2818
- fetchWebsite,
2615
+ fetchItem,
2819
2616
  filterProperties,
2820
2617
  getAllPropertyLabels,
2821
2618
  getPropertyByLabel,