@digitalculture/ochre-sdk
Version:
Node.js library for working with OCHRE (Online Cultural and Historical Research Environment) data
1,316 lines (1,311 loc) • 96.8 kB
JavaScript
// src/utils/parse.ts
import { z as z3 } from "zod";
// src/utils/fetchers/generic.ts
import { z } from "zod";
var uuidSchema = z.string().uuid({ message: "Invalid UUID provided" });
async function fetchByUuid(uuid) {
try {
const result = uuidSchema.safeParse(uuid);
if (!result.success) {
throw new Error(result.error.issues[0]?.message);
}
const response = await fetch(
`https://ochre.lib.uchicago.edu/ochre?uuid=${uuid}&format=json&lang="*"`
);
if (!response.ok) {
throw new Error("Failed to fetch OCHRE data");
}
const dataRaw = await response.json();
if (!("ochre" in dataRaw)) {
throw new Error("Invalid OCHRE data: API response missing 'ochre' key");
}
return [null, dataRaw];
} catch (error) {
return [error instanceof Error ? error.message : "Unknown error", null];
}
}
// src/utils/string.ts
import { z as z2 } from "zod";
var renderOptionsSchema = z2.string().transform((str) => str.split(" ")).pipe(
z2.array(
z2.enum([
"bold",
"italic",
"underline"
])
)
);
var whitespaceSchema = z2.string().transform((str) => str.split(" ")).pipe(
z2.array(
z2.enum([
"newline",
"trailing",
"leading"
])
)
);
var emailSchema = z2.string().email({ message: "Invalid email" });
function getStringItemByLanguage(content, language) {
const stringItemToFind = content.find((item) => item.lang === language);
return stringItemToFind ?? null;
}
function parseEmail(string) {
const splitString = string.split(" ");
const returnSplitString = [];
for (const string2 of splitString) {
const cleanString = string2.replaceAll(/(?<=\s|^)[([{]+|[)\]}]+(?=\s|$)/g, "").replace(/[!),.:;?\]]$/, "");
const index = string2.indexOf(cleanString);
const before = string2.slice(0, index);
const after = string2.slice(index + cleanString.length);
const isEmail = emailSchema.safeParse(cleanString).success;
if (isEmail) {
returnSplitString.push(
before,
`${before}<ExternalLink href="mailto:${cleanString}">${cleanString}</ExternalLink>${after}`
);
continue;
}
returnSplitString.push(string2);
}
return returnSplitString.join(" ");
}
function parseRenderOptions(contentString, renderString) {
let returnString = contentString;
const result = renderOptionsSchema.safeParse(renderString);
if (!result.success) {
console.warn(`Invalid render options string provided: \u201C${renderString}\u201D`);
return contentString;
}
for (const option of result.data) {
switch (option) {
case "bold": {
returnString = `**${returnString}**`;
break;
}
case "italic": {
returnString = `*${returnString}*`;
break;
}
case "underline": {
returnString = `_${returnString}_`;
break;
}
}
}
return returnString.replaceAll("'", "'");
}
function parseWhitespace(contentString, whitespace) {
let returnString = contentString;
const result = whitespaceSchema.safeParse(whitespace);
if (!result.success) {
console.warn(`Invalid whitespace string provided: \u201C${whitespace}\u201D`);
return contentString;
}
for (const option of result.data) {
switch (option) {
case "newline": {
returnString = `<br />
${returnString}`;
break;
}
case "trailing": {
returnString = `${returnString} `;
break;
}
case "leading": {
returnString = ` ${returnString}`;
break;
}
}
}
return returnString.replaceAll("'", "'");
}
function parseFakeString(string) {
let returnString = "";
if (typeof string === "string") {
returnString = string;
} else if (typeof string === "number") {
returnString = string.toString();
} else if (typeof string === "boolean") {
returnString = string ? "Yes" : "No";
}
return returnString.replaceAll("'", "'").replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
}
function parseStringItem(item) {
let returnString = "";
switch (typeof item.string) {
case "string": {
returnString = item.string;
break;
}
case "number":
case "boolean": {
returnString = parseFakeString(item.string);
break;
}
case "object": {
const stringItems = Array.isArray(item.string) ? item.string : [item.string];
for (const stringItem of stringItems) {
if (typeof stringItem === "string" || typeof stringItem === "number" || typeof stringItem === "boolean") {
returnString += parseFakeString(stringItem);
} else {
const renderedText = stringItem.rend != null ? parseRenderOptions(
parseFakeString(stringItem.content),
stringItem.rend
) : parseFakeString(stringItem.content);
const whitespacedText = stringItem.whitespace != null ? parseWhitespace(renderedText, stringItem.whitespace) : renderedText;
returnString += whitespacedText;
}
}
break;
}
default: {
returnString = "";
break;
}
}
return returnString.replaceAll("'", "'").replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
}
function parseStringDocumentItem(item, footnotes) {
if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") {
return parseEmail(parseFakeString(item));
}
if ("whitespace" in item && !("content" in item) && !("string" in item)) {
if (item.whitespace === "newline") {
return " \n";
} else {
return "";
}
}
if ("links" in item) {
let itemString = "";
if (typeof item.string === "object") {
itemString = parseStringContent(item.string);
} else {
itemString = parseFakeString(item.string).replaceAll("<", String.raw`\<`).replaceAll("{", String.raw`\{`);
}
const itemLinks = Array.isArray(item.links) ? item.links : [item.links];
for (const link of itemLinks) {
if ("resource" in link) {
const linkResource = Array.isArray(link.resource) ? link.resource[0] : link.resource;
let linkContent = null;
if (linkResource.content != null) {
linkContent = parseFakeString(linkResource.content).replaceAll("<", String.raw`\<`).replaceAll("{", String.raw`\{`);
}
switch (linkResource.type) {
case "image": {
if (linkResource.rend === "inline") {
return `<InlineImage uuid="${linkResource.uuid}" ${linkContent !== null ? `content="${linkContent}"` : ""} height={${linkResource.height?.toString() ?? "null"}} width={${linkResource.width?.toString() ?? "null"}} />`;
} else if (linkResource.publicationDateTime != null) {
return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkResource.uuid}" type="image"${linkContent !== null ? ` content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
} else {
return `<TooltipSpan type="image" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</TooltipSpan>`;
}
}
case "internalDocument": {
const isFootnote = linkContent?.toLocaleLowerCase("en-US").includes("footnote");
if (isFootnote) {
if (footnotes) {
footnotes.push({
uuid: linkResource.uuid,
label: itemString,
content: ""
});
}
return ` <Footnote uuid="${linkResource.uuid}"${itemString ? ` label="${itemString}"` : ""}${linkContent !== null ? ` content="${linkContent}"` : ""} />`;
} else {
return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkResource.uuid}" type="internalDocument" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
}
}
case "externalDocument": {
if (linkResource.publicationDateTime != null) {
return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkResource.uuid}" type="externalDocument" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
} else {
return `<TooltipSpan type="externalDocument" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</TooltipSpan>`;
}
}
case "webpage": {
return `<ExternalLink href="${linkResource.href}" type="webpage" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
}
default: {
return "";
}
}
} else if ("concept" in link) {
const linkConcept = Array.isArray(link.concept) ? link.concept[0] : link.concept;
if (linkConcept.publicationDateTime != null) {
return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkConcept.uuid}" type="concept">${itemString}</ExternalLink>`;
} else {
return `<TooltipSpan type="concept">${itemString}</TooltipSpan>`;
}
} else if ("set" in link) {
const linkSet = Array.isArray(link.set) ? link.set[0] : link.set;
if (linkSet.publicationDateTime != null) {
return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkSet.uuid}" type="set">${itemString}</ExternalLink>`;
} else {
return `<TooltipSpan type="set">${itemString}</TooltipSpan>`;
}
} else if ("person" in link) {
const linkPerson = Array.isArray(link.person) ? link.person[0] : link.person;
const linkContent = linkPerson.identification ? ["string", "number", "boolean"].includes(
typeof linkPerson.identification.label
) ? parseFakeString(linkPerson.identification.label) : parseStringContent(
linkPerson.identification.label
) : null;
if (linkPerson.publicationDateTime != null) {
return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkPerson.uuid}" type="${linkPerson.type ?? "person"}" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</ExternalLink>`;
} else {
return `<TooltipSpan type="${linkPerson.type ?? "person"}" ${linkContent !== null ? `content="${linkContent}"` : ""}>${itemString}</TooltipSpan>`;
}
} else if ("bibliography" in link) {
const linkBibliography = Array.isArray(link.bibliography) ? link.bibliography[0] : link.bibliography;
if (linkBibliography.publicationDateTime != null) {
return `<ExternalLink href="https:\\/\\/ochre.lib.uchicago.edu/ochre?uuid=${linkBibliography.uuid}" type="${linkBibliography.type ?? "bibliography"}">${itemString}</ExternalLink>`;
} else {
return `<TooltipSpan type="bibliography">${itemString}</TooltipSpan>`;
}
}
}
}
let returnString = "";
if ("string" in item) {
const stringItems = Array.isArray(item.string) ? item.string : [item.string];
for (const stringItem of stringItems) {
returnString += parseStringDocumentItem(stringItem, footnotes);
}
if ("whitespace" in item && item.whitespace != null) {
returnString = parseWhitespace(parseEmail(returnString), item.whitespace);
}
return returnString.replaceAll("'", "'").replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
} else {
returnString = parseFakeString(item.content);
if (item.rend != null) {
returnString = parseRenderOptions(parseEmail(returnString), item.rend);
}
if (item.whitespace != null) {
returnString = parseWhitespace(parseEmail(returnString), item.whitespace);
}
}
return returnString.replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
}
function parseStringContent(content, language = "eng") {
switch (typeof content.content) {
case "string":
case "number":
case "boolean": {
return parseFakeString(content.content);
}
case "object": {
if (Array.isArray(content.content)) {
const stringItem = getStringItemByLanguage(content.content, language);
if (stringItem) {
return parseStringItem(stringItem);
} else {
const returnStringItem = content.content[0];
if (!returnStringItem) {
throw new Error(
`No string item found for language \u201C${language}\u201D in the following content:
${JSON.stringify(
content.content
)}.`
);
}
return parseStringItem(returnStringItem);
}
} else {
return parseStringItem(content.content);
}
}
default: {
return String(content.content).replaceAll(/^(\d+)\./gm, String.raw`$1\.`);
}
}
}
// src/utils/fetchers/resource.ts
async function fetchResource(uuid) {
try {
const [error, dataRaw] = await fetchByUuid(uuid);
if (error !== null) {
throw new Error(error);
}
if (!("resource" in dataRaw.ochre)) {
throw new Error(
"Invalid OCHRE data: API response missing 'resource' key"
);
}
const resourceItem = parseResource(dataRaw.ochre.resource);
const data = {
uuid: parseFakeString(dataRaw.ochre.uuid),
publicationDateTime: new Date(dataRaw.ochre.publicationDateTime),
belongsTo: {
uuid: dataRaw.ochre.uuidBelongsTo,
abbreviation: parseFakeString(dataRaw.ochre.belongsTo)
},
metadata: parseMetadata(dataRaw.ochre.metadata),
item: resourceItem
};
return { metadata: data.metadata, resource: data.item };
} catch (error) {
console.error(error);
return null;
}
}
// src/utils/getters.ts
var DEFAULT_OPTIONS = {
searchNestedProperties: false
};
function getPropertyByLabel(properties, label, options = DEFAULT_OPTIONS) {
const { searchNestedProperties } = options;
const property = properties.find((property2) => property2.label === label);
if (property) {
return property;
}
if (searchNestedProperties) {
for (const property2 of properties) {
if (property2.properties.length > 0) {
const nestedResult = getPropertyByLabel(property2.properties, label, {
searchNestedProperties
});
if (nestedResult) {
return nestedResult;
}
}
}
}
return null;
}
function getPropertyValuesByLabel(properties, label, options = DEFAULT_OPTIONS) {
const { searchNestedProperties } = options;
const property = properties.find((property2) => property2.label === label);
if (property) {
return property.values.map((value) => value.content);
}
if (searchNestedProperties) {
for (const property2 of properties) {
if (property2.properties.length > 0) {
const nestedResult = getPropertyValuesByLabel(
property2.properties,
label,
{ searchNestedProperties }
);
if (nestedResult) {
return nestedResult;
}
}
}
}
return null;
}
function getPropertyValueByLabel(properties, label, options = DEFAULT_OPTIONS) {
const { searchNestedProperties } = options;
const values = getPropertyValuesByLabel(properties, label, {
searchNestedProperties
});
if (values !== null && values.length > 0) {
return values[0];
}
if (searchNestedProperties) {
for (const property of properties) {
if (property.properties.length > 0) {
const nestedResult = getPropertyValueByLabel(
property.properties,
label,
{ searchNestedProperties }
);
if (nestedResult !== null) {
return nestedResult;
}
}
}
}
return null;
}
function getAllPropertyLabels(properties, options = DEFAULT_OPTIONS) {
const { searchNestedProperties } = options;
const labels = /* @__PURE__ */ new Set();
for (const property of properties) {
labels.add(property.label);
if (property.properties.length > 0 && searchNestedProperties) {
const nestedLabels = getAllPropertyLabels(property.properties, {
searchNestedProperties: true
});
for (const label of nestedLabels) {
labels.add(label);
}
}
}
return [...labels];
}
function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
const { searchNestedProperties } = options;
const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
let isFound = property.values.some(
(value) => value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"))
);
if (!isFound && searchNestedProperties) {
isFound = property.properties.some(
(property2) => filterProperties(property2, filter, { searchNestedProperties: true })
);
}
return isFound;
}
return false;
}
// src/utils/parse.ts
var websiteSchema = z3.object({
type: z3.enum(
[
"traditional",
"digital-collection",
"plum",
"cedar",
"elm",
"maple",
"oak",
"palm"
],
{ message: "Invalid website type" }
),
status: z3.enum(
["development", "preview", "production"],
{ message: "Invalid website status" }
),
privacy: z3.enum(
["public", "password", "private"],
{ message: "Invalid website privacy" }
)
});
var componentSchema = z3.enum(
[
"annotated-document",
"annotated-image",
"bibliography",
"blog",
"button",
"collection",
"empty-space",
"filter-categories",
"iframe",
"iiif-viewer",
"image",
"image-gallery",
"n-columns",
"n-rows",
"network-graph",
"search-bar",
"table",
"text",
"timeline",
"video"
],
{ message: "Invalid component" }
);
function parseIdentification(identification) {
try {
const returnIdentification = {
label: ["string", "number", "boolean"].includes(typeof identification.label) ? parseFakeString(identification.label) : parseStringContent(identification.label),
abbreviation: ""
};
for (const key of Object.keys(identification).filter(
(key2) => key2 !== "label"
)) {
returnIdentification[key] = parseStringContent(
identification[key]
);
}
return returnIdentification;
} catch (error) {
console.error(error);
return {
label: "",
abbreviation: ""
};
}
}
function parseLanguages(language) {
if (language == null) {
return ["eng"];
}
if (Array.isArray(language)) {
return language.map((lang) => parseStringContent(lang));
} else {
return [parseStringContent(language)];
}
}
function parseMetadata(metadata) {
let identification = {
label: "",
abbreviation: ""
};
if (metadata.item) {
if (metadata.item.label || metadata.item.abbreviation) {
let label = "";
let abbreviation = "";
if (metadata.item.label) {
label = parseStringContent(metadata.item.label);
}
if (metadata.item.abbreviation) {
abbreviation = parseStringContent(metadata.item.abbreviation);
}
identification = { label, abbreviation };
} else {
identification = parseIdentification(metadata.item.identification);
}
}
let projectIdentification = null;
const baseProjectIdentification = metadata.project?.identification ? parseIdentification(metadata.project.identification) : null;
if (baseProjectIdentification) {
projectIdentification = {
...baseProjectIdentification,
website: metadata.project?.identification.website ?? null
};
}
return {
project: projectIdentification ? { identification: projectIdentification } : null,
item: metadata.item ? {
identification,
category: metadata.item.category,
type: metadata.item.type,
maxLength: metadata.item.maxLength ?? null
} : null,
dataset: parseStringContent(metadata.dataset),
publisher: parseStringContent(metadata.publisher),
languages: parseLanguages(metadata.language),
identifier: parseStringContent(metadata.identifier),
description: parseStringContent(metadata.description)
};
}
function parseContextItem(contextItem) {
return {
uuid: contextItem.uuid,
publicationDateTime: contextItem.publicationDateTime != null ? new Date(contextItem.publicationDateTime) : null,
number: contextItem.n,
content: parseFakeString(contextItem.content)
};
}
function parseContext(context) {
const contexts = Array.isArray(context.context) ? context.context : [context.context];
const returnContexts = {
nodes: contexts.map((context2) => {
const spatialUnit = [];
if ("spatialUnit" in context2 && context2.spatialUnit) {
const contextsToParse = Array.isArray(context2.spatialUnit) ? context2.spatialUnit : [context2.spatialUnit];
for (const contextItem of contextsToParse) {
spatialUnit.push(parseContextItem(contextItem));
}
}
return {
tree: parseContextItem(context2.tree),
project: parseContextItem(context2.project),
spatialUnit
};
}),
displayPath: context.displayPath
};
return returnContexts;
}
function parseLicense(license) {
if (typeof license.license === "string") {
return null;
}
return {
content: license.license.content,
url: license.license.target
};
}
function parsePerson(person) {
return {
uuid: person.uuid,
publicationDateTime: person.publicationDateTime != null ? new Date(person.publicationDateTime) : null,
type: person.type ?? null,
date: person.date != null ? new Date(person.date) : null,
identification: person.identification ? parseIdentification(person.identification) : null,
content: person.content != null ? parseFakeString(person.content) : null
};
}
function parsePersons(persons) {
const returnPersons = [];
for (const person of persons) {
returnPersons.push(parsePerson(person));
}
return returnPersons;
}
function parseLink(linkRaw) {
const links = "resource" in linkRaw ? linkRaw.resource : "spatialUnit" in linkRaw ? linkRaw.spatialUnit : "concept" in linkRaw ? linkRaw.concept : "set" in linkRaw ? linkRaw.set : "tree" in linkRaw ? linkRaw.tree : "person" in linkRaw ? linkRaw.person : "bibliography" in linkRaw ? linkRaw.bibliography : "epigraphicUnit" in linkRaw ? linkRaw.epigraphicUnit : "propertyValue" in linkRaw ? linkRaw.propertyValue : null;
if (!links) {
throw new Error(
`Invalid link provided: ${JSON.stringify(linkRaw, null, 2)}`
);
}
const linksToParse = Array.isArray(links) ? links : [links];
const returnLinks = [];
for (const link of linksToParse) {
const returnLink = {
category: "resource" in linkRaw ? "resource" : "spatialUnit" in linkRaw ? "spatialUnit" : "concept" in linkRaw ? "concept" : "set" in linkRaw ? "set" : "person" in linkRaw ? "person" : "tree" in linkRaw ? "tree" : "bibliography" in linkRaw ? "bibliography" : "epigraphicUnit" in linkRaw ? "epigraphicUnit" : "propertyValue" in linkRaw ? "propertyValue" : null,
content: "content" in link ? link.content != null ? parseFakeString(link.content) : null : null,
href: "href" in link && link.href != null ? link.href : null,
uuid: link.uuid,
type: link.type ?? null,
identification: link.identification ? parseIdentification(link.identification) : null,
image: null,
bibliographies: "bibliography" in linkRaw ? parseBibliographies(
Array.isArray(linkRaw.bibliography) ? linkRaw.bibliography : [linkRaw.bibliography]
) : null,
publicationDateTime: link.publicationDateTime != null ? new Date(link.publicationDateTime) : null
};
if ("height" in link && link.height != null && link.width != null && link.heightPreview != null && link.widthPreview != null) {
returnLink.image = {
isInline: link.rend === "inline",
isPrimary: link.isPrimary ?? false,
heightPreview: link.heightPreview,
widthPreview: link.widthPreview,
height: link.height,
width: link.width
};
}
returnLinks.push(returnLink);
}
return returnLinks;
}
function parseLinks(links) {
const returnLinks = [];
for (const link of links) {
returnLinks.push(...parseLink(link));
}
return returnLinks;
}
function parseDocument(document, language = "eng") {
let returnString = "";
const footnotes = [];
const documentWithLanguage = Array.isArray(document) ? document.find((doc) => doc.lang === language) : document;
if (typeof documentWithLanguage.string === "string" || typeof documentWithLanguage.string === "number" || typeof documentWithLanguage.string === "boolean") {
returnString += parseEmail(parseFakeString(documentWithLanguage.string));
} else {
const documentItems = Array.isArray(documentWithLanguage.string) ? documentWithLanguage.string : [documentWithLanguage.string];
for (const item of documentItems) {
returnString += parseStringDocumentItem(item, footnotes);
}
}
return { content: returnString, footnotes };
}
function parseImage(image) {
return {
publicationDateTime: image.publicationDateTime != null ? new Date(image.publicationDateTime) : null,
identification: image.identification ? parseIdentification(image.identification) : null,
url: image.href ?? (image.htmlImgSrcPrefix == null && image.content != null ? parseFakeString(image.content) : null),
htmlPrefix: image.htmlImgSrcPrefix ?? null,
content: image.htmlImgSrcPrefix != null && image.content != null ? parseFakeString(image.content) : null,
widthPreview: image.widthPreview ?? null,
heightPreview: image.heightPreview ?? null,
width: image.width ?? null,
height: image.height ?? null
};
}
function parseNotes(notes, language = "eng") {
const returnNotes = [];
for (const note of notes) {
if (typeof note === "string") {
if (note === "") {
continue;
}
returnNotes.push({
number: -1,
title: null,
content: note
});
continue;
}
let content = "";
const notesToParse = Array.isArray(note.content) ? note.content : [note.content];
let noteWithLanguage = notesToParse.find((item) => item.lang === language);
if (!noteWithLanguage) {
noteWithLanguage = notesToParse[0];
if (!noteWithLanguage) {
throw new Error(
`Note does not have a valid content item: ${JSON.stringify(
note,
null,
2
)}`
);
}
}
if (typeof noteWithLanguage.string === "string" || typeof noteWithLanguage.string === "number" || typeof noteWithLanguage.string === "boolean") {
content = parseEmail(parseFakeString(noteWithLanguage.string));
} else {
content = parseEmail(parseDocument(noteWithLanguage).content);
}
returnNotes.push({
number: note.noteNo,
title: noteWithLanguage.title != null ? parseFakeString(noteWithLanguage.title) : null,
content
});
}
return returnNotes;
}
function parseCoordinates(coordinates) {
return {
latitude: coordinates.latitude,
longitude: coordinates.longitude,
type: coordinates.coord?.coordType ?? null,
label: coordinates.coord?.coordLabel != null ? parseFakeString(coordinates.coord.coordLabel) : null
};
}
function parseObservation(observation) {
return {
number: observation.observationNo,
date: observation.date != null ? new Date(observation.date) : null,
observers: observation.observers != null ? parseFakeString(observation.observers).split(";").map((observer) => observer.trim()) : [],
notes: observation.notes ? parseNotes(
Array.isArray(observation.notes.note) ? observation.notes.note : [observation.notes.note]
) : [],
links: observation.links ? parseLinks(
Array.isArray(observation.links) ? observation.links : [observation.links]
) : [],
properties: observation.properties ? parseProperties(
Array.isArray(observation.properties.property) ? observation.properties.property : [observation.properties.property]
) : []
};
}
function parseObservations(observations) {
const returnObservations = [];
for (const observation of observations) {
returnObservations.push(parseObservation(observation));
}
return returnObservations;
}
function parseEvents(events) {
const returnEvents = [];
for (const event of events) {
returnEvents.push({
date: event.dateTime != null ? new Date(event.dateTime) : null,
label: parseStringContent(event.label),
agent: event.agent ? {
uuid: event.agent.uuid,
content: parseFakeString(event.agent.content)
} : null
});
}
return returnEvents;
}
function parseProperties(properties, language = "eng") {
const returnProperties = [];
for (const property of properties) {
const valuesToParse = "value" in property && property.value ? Array.isArray(property.value) ? property.value : [property.value] : [];
const values = valuesToParse.map(
(value) => !["string", "number", "boolean"].includes(typeof value) && typeof value === "object" ? {
content: value.slug ? parseFakeString(value.slug) : parseStringContent(value),
type: value.type,
category: value.category !== "value" ? value.category ?? null : null,
uuid: value.uuid ?? null,
publicationDateTime: value.publicationDateTime != null ? new Date(value.publicationDateTime) : null
} : {
content: parseFakeString(value),
type: "string",
category: "value",
uuid: null,
publicationDateTime: null
}
);
returnProperties.push({
label: parseStringContent(property.label, language).replace(/\s*\.{3}$/, "").trim(),
values,
comment: property.comment != null ? parseFakeString(property.comment) : null,
properties: property.property ? parseProperties(
Array.isArray(property.property) ? property.property : [property.property]
) : []
});
}
return returnProperties;
}
function parseInterpretations(interpretations) {
const returnInterpretations = [];
for (const interpretation of interpretations) {
returnInterpretations.push({
date: new Date(interpretation.date),
number: interpretation.interpretationNo,
properties: interpretation.properties ? parseProperties(
Array.isArray(interpretation.properties.property) ? interpretation.properties.property : [interpretation.properties.property]
) : []
});
}
return returnInterpretations;
}
function parseImageMap(imageMap) {
const returnImageMap = {
area: [],
width: imageMap.width,
height: imageMap.height
};
const imageMapAreasToParse = Array.isArray(imageMap.area) ? imageMap.area : [imageMap.area];
for (const area of imageMapAreasToParse) {
returnImageMap.area.push({
uuid: area.uuid,
publicationDateTime: area.publicationDateTime != null ? new Date(area.publicationDateTime) : null,
type: area.type,
title: parseFakeString(area.title),
shape: area.shape === "rect" ? "rectangle" : "polygon",
coords: area.coords.split(",").map((coord) => Number.parseInt(coord))
});
}
return returnImageMap;
}
function parsePeriod(period) {
return {
uuid: period.uuid,
category: "period",
publicationDateTime: period.publicationDateTime != null ? new Date(period.publicationDateTime) : null,
type: period.type ?? null,
number: period.n ?? null,
identification: parseIdentification(period.identification),
description: period.description ? parseStringContent(period.description) : null
};
}
function parsePeriods(periods) {
const returnPeriods = [];
for (const period of periods) {
returnPeriods.push(parsePeriod(period));
}
return returnPeriods;
}
function parseBibliography(bibliography) {
let resource = null;
if (bibliography.source?.resource) {
resource = {
uuid: bibliography.source.resource.uuid,
publicationDateTime: bibliography.source.resource.publicationDateTime ? new Date(bibliography.source.resource.publicationDateTime) : null,
type: bibliography.source.resource.type,
identification: parseIdentification(
bibliography.source.resource.identification
)
};
}
return {
uuid: bibliography.uuid,
category: "bibliography",
publicationDateTime: bibliography.publicationDateTime != null ? new Date(bibliography.publicationDateTime) : null,
type: bibliography.type ?? null,
number: bibliography.n ?? null,
identification: bibliography.identification ? parseIdentification(bibliography.identification) : null,
projectIdentification: bibliography.project?.identification ? parseIdentification(bibliography.project.identification) : null,
context: bibliography.context ? parseContext(bibliography.context) : null,
citation: {
format: bibliography.citationFormat ?? null,
short: bibliography.citationFormatSpan ? parseFakeString(
"default:span" in bibliography.citationFormatSpan ? bibliography.citationFormatSpan["default:span"].content : bibliography.citationFormatSpan.span.content
) : null,
long: bibliography.referenceFormatDiv ? parseFakeString(
"default:div" in bibliography.referenceFormatDiv ? bibliography.referenceFormatDiv["default:div"]["default:div"].content : bibliography.referenceFormatDiv.div.div.content
) : null
},
publicationInfo: {
publishers: bibliography.publicationInfo?.publishers ? parsePersons(
Array.isArray(
bibliography.publicationInfo.publishers.publishers.person
) ? bibliography.publicationInfo.publishers.publishers.person : [bibliography.publicationInfo.publishers.publishers.person]
) : [],
startDate: bibliography.publicationInfo?.startDate ? new Date(
bibliography.publicationInfo.startDate.year,
bibliography.publicationInfo.startDate.month,
bibliography.publicationInfo.startDate.day
) : null
},
entryInfo: bibliography.entryInfo ? {
startIssue: parseFakeString(bibliography.entryInfo.startIssue),
startVolume: parseFakeString(bibliography.entryInfo.startVolume)
} : null,
source: {
resource,
documentUrl: bibliography.sourceDocument ? `https://ochre.lib.uchicago.edu/ochre?uuid=${bibliography.sourceDocument.uuid}&load` : null
},
periods: bibliography.periods ? parsePeriods(
Array.isArray(bibliography.periods.period) ? bibliography.periods.period : [bibliography.periods.period]
) : [],
authors: bibliography.authors ? parsePersons(
Array.isArray(bibliography.authors.person) ? bibliography.authors.person : [bibliography.authors.person]
) : [],
properties: bibliography.properties ? parseProperties(
Array.isArray(bibliography.properties.property) ? bibliography.properties.property : [bibliography.properties.property]
) : []
};
}
function parseBibliographies(bibliographies) {
const returnBibliographies = [];
for (const bibliography of bibliographies) {
returnBibliographies.push(parseBibliography(bibliography));
}
return returnBibliographies;
}
function parsePropertyValue(propertyValue) {
return {
uuid: propertyValue.uuid,
category: "propertyValue",
n: propertyValue.n,
publicationDateTime: propertyValue.publicationDateTime ? new Date(propertyValue.publicationDateTime) : null,
context: propertyValue.context ? parseContext(propertyValue.context) : null,
availability: propertyValue.availability ? parseLicense(propertyValue.availability) : null,
identification: parseIdentification(propertyValue.identification),
date: propertyValue.date ? new Date(propertyValue.date) : null,
creators: propertyValue.creators ? parsePersons(
Array.isArray(propertyValue.creators.creator) ? propertyValue.creators.creator : [propertyValue.creators.creator]
) : [],
description: propertyValue.description ? ["string", "number", "boolean"].includes(
typeof propertyValue.description
) ? parseFakeString(propertyValue.description) : parseStringContent(propertyValue.description) : "",
notes: propertyValue.notes ? parseNotes(
Array.isArray(propertyValue.notes.note) ? propertyValue.notes.note : [propertyValue.notes.note]
) : [],
links: propertyValue.links ? parseLinks(
Array.isArray(propertyValue.links) ? propertyValue.links : [propertyValue.links]
) : []
};
}
function parsePropertyValues(propertyValues) {
const returnPropertyValues = [];
for (const propertyValue of propertyValues) {
returnPropertyValues.push(parsePropertyValue(propertyValue));
}
return returnPropertyValues;
}
function parseTree(tree) {
let creators = [];
if (tree.creators) {
creators = parsePersons(
Array.isArray(tree.creators.creator) ? tree.creators.creator : [tree.creators.creator]
);
}
let date = null;
if (tree.date != null) {
date = new Date(tree.date);
}
let resources = [];
let spatialUnits = [];
let concepts = [];
let periods = [];
let bibliographies = [];
let persons = [];
let propertyValues = [];
if (typeof tree.items !== "string" && "resource" in tree.items) {
resources = parseResources(
Array.isArray(tree.items.resource) ? tree.items.resource : [tree.items.resource]
);
}
if (typeof tree.items !== "string" && "spatialUnit" in tree.items) {
spatialUnits = parseSpatialUnits(
Array.isArray(tree.items.spatialUnit) ? tree.items.spatialUnit : [tree.items.spatialUnit]
);
}
if (typeof tree.items !== "string" && "concept" in tree.items) {
concepts = parseConcepts(
Array.isArray(tree.items.concept) ? tree.items.concept : [tree.items.concept]
);
}
if (typeof tree.items !== "string" && "period" in tree.items) {
periods = parsePeriods(
Array.isArray(tree.items.period) ? tree.items.period : [tree.items.period]
);
}
if (typeof tree.items !== "string" && "bibliography" in tree.items) {
bibliographies = parseBibliographies(
Array.isArray(tree.items.bibliography) ? tree.items.bibliography : [tree.items.bibliography]
);
}
if (typeof tree.items !== "string" && "person" in tree.items) {
persons = parsePersons(
Array.isArray(tree.items.person) ? tree.items.person : [tree.items.person]
);
}
if (typeof tree.items !== "string" && "propertyValue" in tree.items) {
propertyValues = parsePropertyValues(
Array.isArray(tree.items.propertyValue) ? tree.items.propertyValue : [tree.items.propertyValue]
);
}
const returnTree = {
uuid: tree.uuid,
category: "tree",
publicationDateTime: new Date(tree.publicationDateTime),
identification: parseIdentification(tree.identification),
creators,
license: parseLicense(tree.availability),
date,
type: tree.type,
number: tree.n,
items: {
resources,
spatialUnits,
concepts,
periods,
bibliographies,
persons,
propertyValues
},
properties: tree.properties ? parseProperties(
Array.isArray(tree.properties.property) ? tree.properties.property : [tree.properties.property]
) : []
};
return returnTree;
}
function parseSet(set) {
let resources = [];
let spatialUnits = [];
let concepts = [];
let periods = [];
let bibliographies = [];
let persons = [];
let propertyValues = [];
if (typeof set.items !== "string" && "resource" in set.items) {
resources = parseResources(
Array.isArray(set.items.resource) ? set.items.resource : [set.items.resource],
true
);
}
if (typeof set.items !== "string" && "spatialUnit" in set.items) {
spatialUnits = parseSpatialUnits(
Array.isArray(set.items.spatialUnit) ? set.items.spatialUnit : [set.items.spatialUnit],
true
);
}
if (typeof set.items !== "string" && "concept" in set.items) {
concepts = parseConcepts(
Array.isArray(set.items.concept) ? set.items.concept : [set.items.concept],
true
);
}
if (typeof set.items !== "string" && "period" in set.items) {
periods = parsePeriods(
Array.isArray(set.items.period) ? set.items.period : [set.items.period]
);
}
if (typeof set.items !== "string" && "bibliography" in set.items) {
bibliographies = parseBibliographies(
Array.isArray(set.items.bibliography) ? set.items.bibliography : [set.items.bibliography]
);
}
if (typeof set.items !== "string" && "person" in set.items) {
persons = parsePersons(
Array.isArray(set.items.person) ? set.items.person : [set.items.person]
);
}
if (typeof set.items !== "string" && "propertyValue" in set.items) {
propertyValues = parsePropertyValues(
Array.isArray(set.items.propertyValue) ? set.items.propertyValue : [set.items.propertyValue]
);
}
return {
uuid: set.uuid,
category: "set",
publicationDateTime: set.publicationDateTime ? new Date(set.publicationDateTime) : null,
date: set.date != null ? new Date(set.date) : null,
license: parseLicense(set.availability),
identification: parseIdentification(set.identification),
isSuppressingBlanks: set.suppressBlanks ?? false,
description: set.description ? ["string", "number", "boolean"].includes(typeof set.description) ? parseFakeString(set.description) : parseStringContent(set.description) : "",
creators: set.creators ? parsePersons(
Array.isArray(set.creators.creator) ? set.creators.creator : [set.creators.creator]
) : [],
type: set.type,
number: set.n,
items: {
resources,
spatialUnits,
concepts,
periods,
bibliographies,
persons,
propertyValues
}
};
}
function parseResource(resource, isNested = false) {
const returnResource = {
uuid: resource.uuid,
category: "resource",
publicationDateTime: resource.publicationDateTime ? new Date(resource.publicationDateTime) : null,
type: resource.type,
number: resource.n,
format: resource.format ?? null,
context: "context" in resource && resource.context ? parseContext(resource.context) : null,
license: "availability" in resource && resource.availability ? parseLicense(resource.availability) : null,
copyright: "copyright" in resource && resource.copyright != null ? parseFakeString(resource.copyright) : null,
identification: parseIdentification(resource.identification),
date: resource.date != null ? new Date(resource.date) : null,
image: resource.image ? parseImage(resource.image) : null,
creators: resource.creators ? parsePersons(
Array.isArray(resource.creators.creator) ? resource.creators.creator : [resource.creators.creator]
) : [],
notes: (
// TODO: Remove this check once the { rend: "splitNotes" } issue is fixed
resource.notes && "note" in resource.notes ? parseNotes(
Array.isArray(resource.notes.note) ? resource.notes.note : [resource.notes.note]
) : []
),
description: resource.description ? ["string", "number", "boolean"].includes(typeof resource.description) ? parseFakeString(resource.description) : parseStringContent(resource.description) : "",
document: resource.document ? parseDocument(resource.document.content) : null,
href: resource.href ?? null,
imageMap: resource.imagemap ? parseImageMap(resource.imagemap) : null,
periods: resource.periods ? parsePeriods(
Array.isArray(resource.periods.period) ? resource.periods.period : [resource.periods.period]
) : [],
links: resource.links ? parseLinks(
Array.isArray(resource.links) ? resource.links : [resource.links]
) : [],
reverseLinks: resource.reverseLinks ? parseLinks(
Array.isArray(resource.reverseLinks) ? resource.reverseLinks : [resource.reverseLinks]
) : [],
properties: resource.properties ? parseProperties(
Array.isArray(resource.properties.property) ? resource.properties.property : [resource.properties.property]
) : [],
citedBibliographies: resource.citedBibliography ? parseBibliographies(
Array.isArray(resource.citedBibliography.reference) ? resource.citedBibliography.reference : [resource.citedBibliography.reference]
) : [],
resources: resource.resource ? parseResources(
Array.isArray(resource.resource) ? resource.resource : [resource.resource],
true
) : []
};
if (isNested) {
const returnNestedResource = {
...returnResource,
publicationDateTime: null,
context: null,
license: null,
copyright: null
};
delete returnNestedResource.publicationDateTime;
delete returnNestedResource.license;
delete returnNestedResource.copyright;
return returnNestedResource;
}
return returnResource;
}
function parseResources(resources, isNested = false) {
const returnResources = [];
const resourcesToParse = Array.isArray(resources) ? resources : [resources];
for (const resource of resourcesToParse) {
returnResources.push(parseResource(resource, isNested));
}
return returnResources;
}
function parseSpatialUnit(spatialUnit, isNested = false) {
const returnSpatialUnit = {
uuid: spatialUnit.uuid,
category: "spatialUnit",
publicationDateTime: spatialUnit.publicationDateTime != null ? new Date(spatialUnit.publicationDateTime) : null,
type: spatialUnit.type,
number: spatialUnit.n,
context: "context" in spatialUnit && spatialUnit.context ? parseContext(spatialUnit.context) : null,
license: "availability" in spatialUnit && spatialUnit.availability ? parseLicense(spatialUnit.availability) : null,
identification: parseIdentification(spatialUnit.identification),
image: spatialUnit.image ? parseImage(spatialUnit.image) : null,
description: spatialUnit.description ? ["string", "number", "boolean"].includes(
typeof spatialUnit.description
) ? parseFakeString(spatialUnit.description) : parseStringContent(spatialUnit.description) : "",
coordinates: spatialUnit.coordinates ? parseCoordinates(spatialUnit.coordinates) : null,
observations: "observations" in spatialUnit && spatialUnit.observations ? parseObservations(
Array.isArray(spatialUnit.observations.observation) ? spatialUnit.observations.observation : [spatialUnit.observations.observation]
) : spatialUnit.observation ? [parseObservation(spatialUnit.observation)] : [],
events: "events" in spatialUnit && spatialUnit.events ? parseEvents(
Array.isArray(spatialUnit.events.event) ? spatialUnit.events.event : [spatialUnit.events.event]
) : []
};
if (isNested) {
const returnNestedSpatialUnit = {
...returnSpatialUnit,
publicationDateTime: null,
license: null,
properties: "properties" in spatialUnit && spatialUnit.properties ? parseProperties(
Array.isArray(spatialUnit.properties.property) ? spatialUnit.properties.property : [spatialUnit.properties.property]
) : []
};
delete returnNestedSpatialUnit.publicationDateTime;
delete returnNestedSpatialUnit.license;
return returnNestedSpatialUnit;
}
return returnSpatialUnit;
}
function parseSpatialUnits(spatialUnits, isNested = false) {
const returnSpatialUnits = [];
const spatialUnitsToParse = Array.isArray(spatialUnits) ? spatialUnits : [spatialUnits];
for (const spatialUnit of spatialUnitsToParse) {
returnSpatialUnits.push(
parseSpatialUnit(spatialUnit, isNested)
);
}
return returnSpatialUnits;
}
function parseConcept(concept, isNested = false) {
const returnConcept = {
uuid: concept.uuid,
category: "concept",
publicationDateTime: concept.publicationDateTime ? new Date(concept.publicationDateTime) : null,
number: concept.n,
license: "availability" in concept && concept.availability ? parseLicense(concept.availability) : null,
context: "context" in concept && concept.context ? parseContext(concept.context) : null,
identification: parseIdentification(concept.identification),
interpretations: parseInterpretations(
Array.isArray(concept.interpretations.interpretation) ? concept.interpretations.interpretation : [concept.interpretations.interpretation]
)
};
if (isNested) {
const returnNestedConcept = {
...returnConcept,
publicationDateTime: null,
context: null,
license: null
};
delete returnNestedConcept.publicationDateTime;
delete returnNestedConcept.license;
return returnNestedConcept;
}
return returnConcept;
}
var parseWebpageResources = async (webpageResources, type) => {
const returnElements = [];
for (const resource of webpageResources) {
const resourceProperties = resource.properties ? parseProperties(
Array.isArray(resource.properties.property) ? resource.properties.property : [resource.properties.property]
) : [];
const resourceProperty = resourceProperties.find(
(property) => property.label === "presentation" && property.values[0].content === type
);
if (!resourceProperty) continue;
switch (type) {
case "element": {
const element = await parseWebElement(resource);
returnElements.push(
element
);
break;
}
case "page": {
const webpage = await parseWebpage(resource);
if (webpage) {
returnElements.push(
webpage
);
}
break;
}
case "block": {
const block = await parseBlock(resource);
if (block) {
returnElements.push(
block
);
}
break;
}
}
}
return returnElements;
};
function parseConcepts(concepts, isNested = false) {
const returnConcepts = [];
const conceptsToParse = Array.isArray(concepts) ? concepts : [concepts];
for (const concept of conceptsToParse) {
returnConcepts.push(parseConcept(concept, isNested));
}
return returnConcepts;
}
async function par