ochre-sdk 1.0.8 → 1.0.10

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.
Files changed (2) hide show
  1. package/dist/index.mjs +22 -128
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -621,33 +621,6 @@ function createSchemaValidationError(message, issues) {
621
621
  return new Error(message, { cause: issues });
622
622
  }
623
623
  /**
624
- * Logs Valibot validation issues to the console with detailed formatting
625
- * @param issues - The validation issues to log
626
- * @param depth - The depth of the issues for indentation
627
- * @internal
628
- */
629
- function logIssues(issues, depth = 0) {
630
- if (issues == null) return;
631
- for (const issue of issues) {
632
- const indent = " ".repeat(depth);
633
- const prefix = depth === 0 ? "❌" : "└─";
634
- const pathStr = issue.path != null && issue.path.length > 0 ? ` at ${v.getDotPath(issue)}` : "";
635
- const typeInfo = `[${issue.kind}:${issue.type}]`;
636
- console.error(`${indent}${prefix} ${typeInfo} ${issue.message}${pathStr}`);
637
- if (issue.expected != null) {
638
- console.error(`${indent} Expected: ${issue.expected}`);
639
- console.error(`${indent} Received: ${issue.received}`);
640
- }
641
- if (issue.input !== void 0 && typeof issue.input !== "object") console.error(`${indent} Input: ${JSON.stringify(issue.input)}`);
642
- if (issue.requirement !== void 0) console.error(`${indent} Requirement: ${JSON.stringify(issue.requirement)}`);
643
- if (issue.issues != null && issue.issues.length > 0) {
644
- console.error(`${indent} Nested issues:`);
645
- logIssues(issue.issues, depth + 1);
646
- }
647
- if (depth === 0) console.error("");
648
- }
649
- }
650
- /**
651
624
  * Validates a pseudo-UUID string
652
625
  * @param value - The string to validate
653
626
  * @returns True if the string is a valid pseudo-UUID, false otherwise
@@ -785,11 +758,6 @@ const whitespaceSchema = v.pipe(v.string(), v.transform((str) => str.split(" "))
785
758
  "leading"
786
759
  ])));
787
760
  /**
788
- * Schema for validating email addresses
789
- * @internal
790
- */
791
- const emailSchema = v.pipe(v.string(), v.email("Invalid email address"));
792
- /**
793
761
  * Schema for validating date data types
794
762
  * @internal
795
763
  */
@@ -983,9 +951,6 @@ const ITEM_PAGE_TOKEN = "item-page";
983
951
  const ENTRY_PAGE_TOKEN = "entry-page";
984
952
  const VARIANT_TOKEN = "variant";
985
953
  const HEADING_LEVEL_TOKEN = "heading-level";
986
- const EMAIL_BRACKET_CLEANUP_REGEX = /(?<=\s|^)[([{]+|[)\]}]+(?=\s|$)/g;
987
- const EMAIL_PUNCTUATION_CLEANUP_REGEX = /[!),:;?\]]/g;
988
- const EMAIL_TRAILING_PERIOD_REGEX = /\.$/;
989
954
  const MDX_QUOTED_ATTRIBUTE_ESCAPE_REGEX = /[\n\r"]/;
990
955
  const MDX_RENDER_ELEMENTS = {
991
956
  bold: "strong",
@@ -1007,31 +972,6 @@ function transformPermanentIdentificationUrl(url) {
1007
972
  return url.replace("https://pi.lib.uchicago.edu/1001/org/ochre/", "https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?uuid=");
1008
973
  }
1009
974
  /**
1010
- * Parses email addresses in a string into HTML links
1011
- *
1012
- * @param string - Input string to parse
1013
- * @returns String with emails converted to HTML links
1014
- *
1015
- * @internal
1016
- */
1017
- function parseEmail(string) {
1018
- const splitString = string.split(" ");
1019
- const returnSplitString = [];
1020
- for (const string of splitString) {
1021
- const cleanString = transformPermanentIdentificationUrl(string).replaceAll(EMAIL_BRACKET_CLEANUP_REGEX, "").replaceAll(EMAIL_PUNCTUATION_CLEANUP_REGEX, "").replace(EMAIL_TRAILING_PERIOD_REGEX, "");
1022
- const index = string.indexOf(cleanString);
1023
- const { success } = v.safeParse(emailSchema, cleanString);
1024
- if (success) {
1025
- const before = index === -1 ? "" : string.slice(0, index);
1026
- const after = index === -1 ? "" : string.slice(index + cleanString.length);
1027
- returnSplitString.push(`${before}<ExternalLink href="mailto:${cleanString}">${cleanString}</ExternalLink>${after}`);
1028
- continue;
1029
- }
1030
- returnSplitString.push(string);
1031
- }
1032
- return returnSplitString.join(" ");
1033
- }
1034
- /**
1035
975
  * Applies text rendering options (bold, italic, underline) to a string
1036
976
  *
1037
977
  * @param contentString - The string content to render
@@ -1096,7 +1036,6 @@ function parseWhitespace(contentString, whitespace, rendering) {
1096
1036
  * @param string - XML string to parse
1097
1037
  * @param options - Options for parsing
1098
1038
  * @param options.rendering - Which text rendering to produce
1099
- * @param options.parseEmail - Whether to parse email addresses
1100
1039
  * @returns Formatted string with whitespace and rendering options
1101
1040
  *
1102
1041
  * @internal
@@ -1108,19 +1047,12 @@ function parseXMLStringVariant(string, options) {
1108
1047
  return returnString;
1109
1048
  }
1110
1049
  function parseXMLStringPayload(string, options) {
1111
- const returnString = (string.payload ?? "").replaceAll("<", options.rendering === "rich" ? String.raw`\<` : "<").replaceAll("{", String.raw`\{`).replaceAll("}", String.raw`\}`);
1112
- return options.parseEmail ? parseEmail(returnString) : returnString;
1050
+ return (string.payload ?? "").replaceAll("<", options.rendering === "rich" ? String.raw`\<` : "<").replaceAll("{", String.raw`\{`).replaceAll("}", String.raw`\}`);
1113
1051
  }
1114
- function parseXMLString(string, options) {
1052
+ function parseXMLString(string) {
1115
1053
  return {
1116
- text: parseXMLStringVariant(string, {
1117
- rendering: "plain",
1118
- parseEmail: false
1119
- }),
1120
- richText: parseXMLStringVariant(string, {
1121
- rendering: "rich",
1122
- parseEmail: options.parseEmail
1123
- })
1054
+ text: parseXMLStringVariant(string, { rendering: "plain" }),
1055
+ richText: parseXMLStringVariant(string, { rendering: "rich" })
1124
1056
  };
1125
1057
  }
1126
1058
  /**
@@ -1185,7 +1117,7 @@ function getFirstPropertyMetadata(item) {
1185
1117
  }
1186
1118
  function parseContentLikeForLanguage(value, options) {
1187
1119
  if (value == null) return "";
1188
- if (!("content" in value)) return parseXMLString(value, { parseEmail: false }).text;
1120
+ if (!("content" in value)) return parseXMLString(value).text;
1189
1121
  const contentItem = value.content.find((item) => item.lang === options.language) ?? value.content[0];
1190
1122
  if (contentItem == null) return "";
1191
1123
  const languages = [contentItem.lang];
@@ -1272,21 +1204,12 @@ function hasRichTextEnvelope(item) {
1272
1204
  function parseXMLStringItem(item, contentItem, options) {
1273
1205
  if (!(item.payload != null || item.string != null) && getXMLRichTextLinks(item).length === 0) return item.whitespace == null ? "" : parseWhitespace("", item.whitespace, options.rendering);
1274
1206
  if (hasRichTextEnvelope(item)) {
1275
- let linkString = item.payload != null ? parseXMLStringPayload(item, {
1276
- rendering: options.rendering,
1277
- parseEmail: false
1278
- }) : parseNestedStringItems(item.string ?? [], contentItem, {
1279
- ...options,
1280
- parseEmail: false
1281
- });
1207
+ let linkString = item.payload != null ? parseXMLStringPayload(item, { rendering: options.rendering }) : parseNestedStringItems(item.string ?? [], contentItem, { ...options });
1282
1208
  if (item.rend != null) linkString = parseRenderOptions(linkString, item.rend, options.rendering);
1283
1209
  if (options.rendering === "plain") return applyWhitespaceToResult(linkString, item.whitespace, options.rendering);
1284
1210
  return renderRichTextItem(item, linkString, contentItem, options);
1285
1211
  }
1286
- if (item.payload != null) return parseXMLStringVariant(item, {
1287
- rendering: options.rendering,
1288
- parseEmail: options.parseEmail
1289
- });
1212
+ if (item.payload != null) return parseXMLStringVariant(item, { rendering: options.rendering });
1290
1213
  let result = parseNestedStringItems(item.string ?? [], contentItem, options);
1291
1214
  if (item.rend != null) result = parseRenderOptions(result, item.rend, options.rendering);
1292
1215
  return applyWhitespaceToResult(result, item.whitespace, options.rendering);
@@ -1342,7 +1265,7 @@ function renderRichTextItem(item, linkString, contentItem, options) {
1342
1265
  if (links.length === 0) return applyWhitespaceToResult(wrapWithTextStyling(linkString, annotationMetadata.textStyling), item.whitespace, rendering);
1343
1266
  let result = "";
1344
1267
  for (const link of links) {
1345
- const linkContent = link.identification != null ? "content" in link.identification.label ? parseXMLContent(link.identification.label, { languages }) : MultilingualString.create(contentItem.lang, parseXMLString(link.identification.label, { parseEmail: false }), languages) : MultilingualString.create(contentItem.lang, "", languages);
1268
+ const linkContent = link.identification != null ? "content" in link.identification.label ? parseXMLContent(link.identification.label, { languages }) : MultilingualString.create(contentItem.lang, parseXMLString(link.identification.label), languages) : MultilingualString.create(contentItem.lang, "", languages);
1346
1269
  const contentText = (rendering === "rich" ? linkContent.getExactRichText(contentItem.lang) : linkContent.getExactText(contentItem.lang)) ?? "";
1347
1270
  if ("type" in link && link.type != null) switch (link.type) {
1348
1271
  case "IIIF":
@@ -1463,13 +1386,11 @@ function parseXMLContentItem(contentItem, options) {
1463
1386
  return {
1464
1387
  text: parseNestedStringItems(contentItem.string, contentItem, {
1465
1388
  ...options,
1466
- rendering: "plain",
1467
- parseEmail: false
1389
+ rendering: "plain"
1468
1390
  }),
1469
1391
  richText: parseNestedStringItems(contentItem.string, contentItem, {
1470
1392
  ...options,
1471
- rendering: "rich",
1472
- parseEmail: true
1393
+ rendering: "rich"
1473
1394
  })
1474
1395
  };
1475
1396
  }
@@ -1508,10 +1429,10 @@ function parseLicense(availability) {
1508
1429
  target: availability.license.target ?? null
1509
1430
  };
1510
1431
  }
1511
- function parseStringLike(value, options = {}) {
1432
+ function parseStringLike(value) {
1512
1433
  if (value == null) return null;
1513
1434
  if (typeof value === "string") return value;
1514
- return parseXMLString(value, { parseEmail: options.parseEmail ?? false }).text;
1435
+ return parseXMLString(value).text;
1515
1436
  }
1516
1437
  function isXMLContent(value) {
1517
1438
  return "content" in value;
@@ -1524,7 +1445,7 @@ function multilingualFromText(text, options) {
1524
1445
  function parseContentLike(value, options) {
1525
1446
  if (value == null) return null;
1526
1447
  if (typeof value === "string") return multilingualFromText(value, options);
1527
- if (!isXMLContent(value)) return multilingualFromText(parseXMLString(value, { parseEmail: true }), options);
1448
+ if (!isXMLContent(value)) return multilingualFromText(parseXMLString(value), options);
1528
1449
  return parseXMLContent(value, { languages: options.languages });
1529
1450
  }
1530
1451
  function parseRequiredContentLike(value, options) {
@@ -1537,7 +1458,7 @@ function parseStringContent(value, options = FALLBACK_PARSER_OPTIONS) {
1537
1458
  if (value == null) return "";
1538
1459
  if (typeof value === "string") return value;
1539
1460
  if (isXMLContent(value)) return parseXMLContent(value, { languages: options.languages }).getText();
1540
- return parseXMLString(value, { parseEmail: true }).text;
1461
+ return parseXMLString(value).text;
1541
1462
  }
1542
1463
  //#endregion
1543
1464
  //#region src/parsers/index.ts
@@ -1970,7 +1891,7 @@ function parseImageMap(rawImageMap) {
1970
1891
  function parseNote(rawNote, options) {
1971
1892
  const authors = [];
1972
1893
  for (const author of rawNote.authors?.author ?? []) authors.push(parsePerson(author, options));
1973
- const content = rawNote.content == null ? multilingualFromText(parseXMLString(rawNote, { parseEmail: true }), options) : parseRequiredContentLike(rawNote, options);
1894
+ const content = rawNote.content == null ? multilingualFromText(parseXMLString(rawNote), options) : parseRequiredContentLike(rawNote, options);
1974
1895
  return {
1975
1896
  number: rawNote.noteNo ?? 0,
1976
1897
  title: parseNoteTitle(rawNote, options),
@@ -3766,10 +3687,7 @@ async function fetchGallery(params, options) {
3766
3687
  const dataRaw = await response.text();
3767
3688
  const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
3768
3689
  const { success, issues, output } = v.safeParse(XMLGalleryData, data);
3769
- if (!success) {
3770
- logIssues(issues);
3771
- throw createSchemaValidationError("Failed to parse gallery XML", issues);
3772
- }
3690
+ if (!success) throw createSchemaValidationError("Failed to parse gallery XML", issues);
3773
3691
  restoreXMLMetadata(output, data);
3774
3692
  return {
3775
3693
  gallery: parseGallery(output, { languages: resolveGalleryLanguages(output, requestedLanguages) }),
@@ -3777,7 +3695,6 @@ async function fetchGallery(params, options) {
3777
3695
  detailedError: null
3778
3696
  };
3779
3697
  } catch (error) {
3780
- console.error(error);
3781
3698
  return {
3782
3699
  gallery: null,
3783
3700
  ...getErrorOutput(error, "Failed to fetch gallery")
@@ -3877,10 +3794,7 @@ async function fetchItemLinks(uuid, options) {
3877
3794
  const dataRaw = await response.text();
3878
3795
  const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
3879
3796
  const { success, issues, output } = v.safeParse(XMLItemLinksData, data);
3880
- if (!success) {
3881
- logIssues(issues);
3882
- throw createSchemaValidationError("Failed to parse OCHRE item links", issues);
3883
- }
3797
+ if (!success) throw createSchemaValidationError("Failed to parse OCHRE item links", issues);
3884
3798
  restoreXMLMetadata(output, data);
3885
3799
  const languages = resolveItemLinksLanguages(output, requestedLanguages);
3886
3800
  return {
@@ -3892,7 +3806,6 @@ async function fetchItemLinks(uuid, options) {
3892
3806
  detailedError: null
3893
3807
  };
3894
3808
  } catch (error) {
3895
- console.error(error);
3896
3809
  return {
3897
3810
  items: null,
3898
3811
  ...getErrorOutput(error, "Unknown error")
@@ -3979,10 +3892,7 @@ async function fetchItem(uuid, options) {
3979
3892
  const dataRaw = await response.text();
3980
3893
  const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
3981
3894
  const { success, issues, output } = v.safeParse(XMLData, data);
3982
- if (!success) {
3983
- logIssues(issues);
3984
- throw createSchemaValidationError("Failed to parse OCHRE data", issues);
3985
- }
3895
+ if (!success) throw createSchemaValidationError("Failed to parse OCHRE data", issues);
3986
3896
  restoreXMLMetadata(output, data);
3987
3897
  const category = options?.category ?? inferFetchItemCategory(output.result.ochre);
3988
3898
  assertItemCategoryAllowed(category, options?.containedItemCategory);
@@ -3996,7 +3906,6 @@ async function fetchItem(uuid, options) {
3996
3906
  detailedError: null
3997
3907
  };
3998
3908
  } catch (error) {
3999
- console.error(error);
4000
3909
  return {
4001
3910
  item: null,
4002
3911
  ...getErrorOutput(error, "Unknown error")
@@ -5054,10 +4963,7 @@ async function fetchSetItems(params, containedItemCategories, options) {
5054
4963
  const dataRaw = await response.text();
5055
4964
  const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
5056
4965
  const { success, issues, output } = v.safeParse(XMLSetItemsData, data);
5057
- if (!success) {
5058
- logIssues(issues);
5059
- throw createSchemaValidationError("Failed to parse OCHRE Set items", issues);
5060
- }
4966
+ if (!success) throw createSchemaValidationError("Failed to parse OCHRE Set items", issues);
5061
4967
  restoreXMLMetadata(output, data);
5062
4968
  if (containedItemCategories != null) {
5063
4969
  const missingCategories = containedItemCategories.filter((category) => !hasSetItemsCategory(output.result.ochre.items, category));
@@ -5080,7 +4986,6 @@ async function fetchSetItems(params, containedItemCategories, options) {
5080
4986
  detailedError: null
5081
4987
  };
5082
4988
  } catch (error) {
5083
- console.error(error);
5084
4989
  return {
5085
4990
  totalCount: null,
5086
4991
  page: null,
@@ -5533,10 +5438,7 @@ async function fetchSetPropertyValues(params, options) {
5533
5438
  const dataRaw = await response.text();
5534
5439
  const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
5535
5440
  const { success, issues, output } = v.safeParse(responseSchema, data);
5536
- if (!success) {
5537
- logIssues(issues);
5538
- throw createSchemaValidationError("Failed to parse OCHRE Set property values", issues);
5539
- }
5441
+ if (!success) throw createSchemaValidationError("Failed to parse OCHRE Set property values", issues);
5540
5442
  const parsedPropertyValues = [];
5541
5443
  const parsedAttributeValues = [];
5542
5444
  if (output.result.ochre.propertyValue != null) parsedPropertyValues.push(...Array.isArray(output.result.ochre.propertyValue) ? output.result.ochre.propertyValue : [output.result.ochre.propertyValue]);
@@ -5590,7 +5492,6 @@ async function fetchSetPropertyValues(params, options) {
5590
5492
  detailedError: null
5591
5493
  };
5592
5494
  } catch (error) {
5593
- console.error(error);
5594
5495
  return {
5595
5496
  propertyValues: null,
5596
5497
  propertyValuesByPropertyVariableUuid: null,
@@ -6677,11 +6578,8 @@ function parseWebElementProperties(componentProperty, elementResource, options)
6677
6578
  };
6678
6579
  break;
6679
6580
  }
6680
- default:
6681
- console.warn(`Invalid or non-implemented component name “${unparsedComponentName.toString()}” for the following element: “${parseStringContent(elementResource.identification.label, options)}”`);
6682
- break;
6581
+ default: throw new Error(`Invalid or non-implemented component name “${unparsedComponentName.toString()}” for the following element: “${parseStringContent(elementResource.identification.label, options)}”`);
6683
6582
  }
6684
- if (properties === null) throw new Error(formatComponentError("Properties not found", componentName, elementResource), { cause: componentProperty });
6685
6583
  return properties;
6686
6584
  }
6687
6585
  function parseWebTitle(properties, identification, overrides) {
@@ -7262,10 +7160,7 @@ async function fetchWebsite(abbreviation, options) {
7262
7160
  const dataRaw = await response.text();
7263
7161
  const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
7264
7162
  const { success, issues, output } = v.safeParse(XMLWebsiteData, data);
7265
- if (!success) {
7266
- logIssues(issues);
7267
- throw createSchemaValidationError("Failed to parse website XML", issues);
7268
- }
7163
+ if (!success) throw createSchemaValidationError("Failed to parse website XML", issues);
7269
7164
  restoreXMLMetadata(output, data);
7270
7165
  return {
7271
7166
  website: parseWebsite(output, { languages: options?.languages }),
@@ -7273,7 +7168,6 @@ async function fetchWebsite(abbreviation, options) {
7273
7168
  detailedError: null
7274
7169
  };
7275
7170
  } catch (error) {
7276
- console.error(error);
7277
7171
  return {
7278
7172
  website: null,
7279
7173
  ...getErrorOutput(error, "Unknown error")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Node.js library for working with OCHRE (Online Cultural and Historical Research Environment) data",
@@ -52,7 +52,7 @@
52
52
  "@antfu/eslint-config": "^9.0.0",
53
53
  "@types/node": "^24.12.4",
54
54
  "bumpp": "^11.1.0",
55
- "eslint": "^10.3.0",
55
+ "eslint": "^10.4.0",
56
56
  "prettier": "^3.8.3",
57
57
  "tsdown": "^0.22.0",
58
58
  "typescript": "^6.0.3",