ochre-sdk 0.20.21 → 0.20.23
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.d.mts +8 -0
- package/dist/index.mjs +212 -80
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -706,6 +706,14 @@ type Query = {
|
|
|
706
706
|
language: string;
|
|
707
707
|
operator?: "AND" | "OR";
|
|
708
708
|
isNegated?: boolean;
|
|
709
|
+
} | {
|
|
710
|
+
target: "string";
|
|
711
|
+
value: string;
|
|
712
|
+
matchMode: "includes" | "exact";
|
|
713
|
+
isCaseSensitive: boolean;
|
|
714
|
+
language: string;
|
|
715
|
+
operator?: "AND" | "OR";
|
|
716
|
+
isNegated?: boolean;
|
|
709
717
|
} | {
|
|
710
718
|
target: "title" | "description" | "image" | "periods" | "bibliography";
|
|
711
719
|
value: string;
|
package/dist/index.mjs
CHANGED
|
@@ -2,18 +2,13 @@ import * as z from "zod";
|
|
|
2
2
|
import { parseISO, set } from "date-fns";
|
|
3
3
|
import { UTCDate } from "@date-fns/utc";
|
|
4
4
|
import { deepEqual } from "fast-equals";
|
|
5
|
-
|
|
6
5
|
//#region src/constants.ts
|
|
7
6
|
const BELONGS_TO_COLLECTION_UUID = "30054cb2-909a-4f34-8db9-8fe7369d691d";
|
|
8
|
-
const PRESENTATION_ITEM_UUID = "f1c131b6-1498-48a4-95bf-a9edae9fd518";
|
|
9
|
-
const TEXT_ANNOTATION_UUID = "b9ca2732-78f4-416e-b77f-dae7647e68a9";
|
|
10
7
|
const TEXT_ANNOTATION_HOVER_CARD_UUID = "c7f6a08a-f07b-49b6-bcb1-af485da3c58f";
|
|
11
8
|
const TEXT_ANNOTATION_ITEM_PAGE_VARIANT_UUID = "bf4476ab-6bc8-40d0-a001-1446213c72ce";
|
|
12
9
|
const TEXT_ANNOTATION_ENTRY_PAGE_VARIANT_UUID = "9d52db95-a9cf-45f7-a0bf-fc9ba9f0aae0";
|
|
13
|
-
const TEXT_ANNOTATION_TEXT_STYLING_UUID = "3e6f86ab-df81-45ae-8257-e2867357df56";
|
|
14
10
|
const TEXT_ANNOTATION_TEXT_STYLING_VARIANT_UUID = "e1647bef-d801-4100-bdde-d081c422f763";
|
|
15
11
|
const TEXT_ANNOTATION_TEXT_STYLING_HEADING_LEVEL_UUID = "d4266f0b-3f8d-4b32-8c15-4b229c8bb11e";
|
|
16
|
-
|
|
17
12
|
//#endregion
|
|
18
13
|
//#region src/utils/string.ts
|
|
19
14
|
const EMAIL_BRACKET_CLEANUP_REGEX = /(?<=\s|^)[([{]+|[)\]}]+(?=\s|$)/g;
|
|
@@ -180,7 +175,7 @@ function extractAnnotationMetadata(item) {
|
|
|
180
175
|
if (itemProperty == null) return result;
|
|
181
176
|
const itemPropertyLabelUuid = itemProperty.label.uuid;
|
|
182
177
|
const itemPropertyValueUuid = typeof itemProperty.value === "object" && "uuid" in itemProperty.value && itemProperty.value.uuid != null ? itemProperty.value.uuid : null;
|
|
183
|
-
if (itemPropertyLabelUuid !==
|
|
178
|
+
if (itemPropertyLabelUuid !== "f1c131b6-1498-48a4-95bf-a9edae9fd518" || itemPropertyValueUuid !== "b9ca2732-78f4-416e-b77f-dae7647e68a9") return result;
|
|
184
179
|
const textAnnotationProperties = itemProperty.property != null ? Array.isArray(itemProperty.property) ? itemProperty.property : [itemProperty.property] : [];
|
|
185
180
|
for (const textAnnotationProperty of textAnnotationProperties) {
|
|
186
181
|
const textAnnotationPropertyValueUuid = typeof textAnnotationProperty.value === "object" && "uuid" in textAnnotationProperty.value && textAnnotationProperty.value.uuid != null ? textAnnotationProperty.value.uuid : null;
|
|
@@ -194,7 +189,7 @@ function extractAnnotationMetadata(item) {
|
|
|
194
189
|
case TEXT_ANNOTATION_ENTRY_PAGE_VARIANT_UUID:
|
|
195
190
|
result.linkVariant = "entry-page";
|
|
196
191
|
break;
|
|
197
|
-
default: if (textAnnotationPropertyValueUuid ===
|
|
192
|
+
default: if (textAnnotationPropertyValueUuid === "3e6f86ab-df81-45ae-8257-e2867357df56" && textAnnotationProperty.property != null) {
|
|
198
193
|
let textStylingVariant = "block";
|
|
199
194
|
let textStylingSize = "md";
|
|
200
195
|
let textStylingHeadingLevel = null;
|
|
@@ -211,7 +206,7 @@ function extractAnnotationMetadata(item) {
|
|
|
211
206
|
}
|
|
212
207
|
const textStylingHeadingLevelProperty = textStylingProperties.find((property) => property.label.uuid === TEXT_ANNOTATION_TEXT_STYLING_HEADING_LEVEL_UUID);
|
|
213
208
|
if (textStylingHeadingLevelProperty != null) textStylingHeadingLevel = parseFakeString(textStylingHeadingLevelProperty.value.content);
|
|
214
|
-
const textStylingCssProperties = textStylingProperties.filter((property) => property.label.uuid !==
|
|
209
|
+
const textStylingCssProperties = textStylingProperties.filter((property) => property.label.uuid !== "e1647bef-d801-4100-bdde-d081c422f763" && property.label.uuid !== "d4266f0b-3f8d-4b32-8c15-4b229c8bb11e");
|
|
215
210
|
if (textStylingCssProperties.length > 0) textStylingCss = textStylingCssProperties.map((property) => ({
|
|
216
211
|
label: parseFakeString(property.label.content),
|
|
217
212
|
value: parseFakeString(property.value.content)
|
|
@@ -371,10 +366,10 @@ function parseStringDocumentItem(item) {
|
|
|
371
366
|
if (itemProperty != null) {
|
|
372
367
|
const itemPropertyLabelUuid = itemProperty.label.uuid;
|
|
373
368
|
const itemPropertyValueUuid = typeof itemProperty.value === "object" && "uuid" in itemProperty.value && itemProperty.value.uuid != null ? itemProperty.value.uuid : null;
|
|
374
|
-
if (itemPropertyLabelUuid ===
|
|
369
|
+
if (itemPropertyLabelUuid === "f1c131b6-1498-48a4-95bf-a9edae9fd518" && itemPropertyValueUuid === "b9ca2732-78f4-416e-b77f-dae7647e68a9") {
|
|
375
370
|
const textAnnotationProperty = itemProperty.property != null ? Array.isArray(itemProperty.property) ? itemProperty.property[0] : itemProperty.property : null;
|
|
376
371
|
if (textAnnotationProperty != null) {
|
|
377
|
-
if ((typeof textAnnotationProperty.value === "object" && "uuid" in textAnnotationProperty.value && textAnnotationProperty.value.uuid != null ? textAnnotationProperty.value.uuid : null) ===
|
|
372
|
+
if ((typeof textAnnotationProperty.value === "object" && "uuid" in textAnnotationProperty.value && textAnnotationProperty.value.uuid != null ? textAnnotationProperty.value.uuid : null) === "3e6f86ab-df81-45ae-8257-e2867357df56" && textAnnotationProperty.property != null) {
|
|
378
373
|
const textStylingType = "text-styling";
|
|
379
374
|
let textStylingVariant = "block";
|
|
380
375
|
let textStylingSize = "md";
|
|
@@ -391,7 +386,7 @@ function parseStringDocumentItem(item) {
|
|
|
391
386
|
}
|
|
392
387
|
const textStylingHeadingLevelProperty = textStylingProperties.find((property) => property.label.uuid === TEXT_ANNOTATION_TEXT_STYLING_HEADING_LEVEL_UUID);
|
|
393
388
|
if (textStylingHeadingLevelProperty != null) textStylingHeadingLevel = parseFakeString(textStylingHeadingLevelProperty.value.content);
|
|
394
|
-
const textStylingCssProperties = textStylingProperties.filter((property) => property.label.uuid !==
|
|
389
|
+
const textStylingCssProperties = textStylingProperties.filter((property) => property.label.uuid !== "e1647bef-d801-4100-bdde-d081c422f763" && property.label.uuid !== "d4266f0b-3f8d-4b32-8c15-4b229c8bb11e");
|
|
395
390
|
if (textStylingCssProperties.length > 0) textStylingCss = textStylingCssProperties.map((property) => ({
|
|
396
391
|
label: parseFakeString(property.label.content),
|
|
397
392
|
value: parseFakeString(property.value.content)
|
|
@@ -442,7 +437,6 @@ function parseStringContent(content, language = "eng") {
|
|
|
442
437
|
default: return String(content.content);
|
|
443
438
|
}
|
|
444
439
|
}
|
|
445
|
-
|
|
446
440
|
//#endregion
|
|
447
441
|
//#region src/utils/internal.ts
|
|
448
442
|
const PSEUDO_UUID_REGEX = /^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/i;
|
|
@@ -572,7 +566,6 @@ function cleanObject(object) {
|
|
|
572
566
|
function stringLiteral(value) {
|
|
573
567
|
return `"${value.replaceAll("\"", "\"\"")}"`;
|
|
574
568
|
}
|
|
575
|
-
|
|
576
569
|
//#endregion
|
|
577
570
|
//#region src/utils/helpers.ts
|
|
578
571
|
/**
|
|
@@ -606,7 +599,6 @@ function flattenItemProperties(item) {
|
|
|
606
599
|
properties: flattenProperties(allProperties)
|
|
607
600
|
};
|
|
608
601
|
}
|
|
609
|
-
|
|
610
602
|
//#endregion
|
|
611
603
|
//#region src/schemas.ts
|
|
612
604
|
/**
|
|
@@ -636,25 +628,13 @@ const richTextStringSchema = z.object({
|
|
|
636
628
|
]),
|
|
637
629
|
lang: z.string().optional()
|
|
638
630
|
});
|
|
639
|
-
|
|
640
|
-
* Schema for validating identification
|
|
641
|
-
* @internal
|
|
642
|
-
*/
|
|
643
|
-
const identificationSchema = z.object({
|
|
631
|
+
z.object({
|
|
644
632
|
label: z.object({ content: z.union([richTextStringSchema, z.array(richTextStringSchema)]) }),
|
|
645
633
|
abbreviation: z.object({ content: z.union([richTextStringSchema, z.array(richTextStringSchema)]).optional() }),
|
|
646
634
|
code: z.string().optional()
|
|
647
635
|
});
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
* @internal
|
|
651
|
-
*/
|
|
652
|
-
const filterSchema = z.string().optional();
|
|
653
|
-
/**
|
|
654
|
-
* Schema for validating data options
|
|
655
|
-
* @internal
|
|
656
|
-
*/
|
|
657
|
-
const dataOptionsSchema = z.object({
|
|
636
|
+
z.string().optional();
|
|
637
|
+
z.object({
|
|
658
638
|
filter: z.string().optional().default(""),
|
|
659
639
|
start: z.number().positive({ error: "Start must be positive" }).optional().default(1),
|
|
660
640
|
limit: z.number().positive({ error: "Limit must be positive" }).optional().default(40)
|
|
@@ -818,6 +798,15 @@ const setQuerySchema = z.union([
|
|
|
818
798
|
operator: z.enum(["AND", "OR"]).optional(),
|
|
819
799
|
isNegated: z.boolean().optional().default(false)
|
|
820
800
|
}).strict(),
|
|
801
|
+
z.object({
|
|
802
|
+
target: z.literal("string"),
|
|
803
|
+
value: z.string(),
|
|
804
|
+
matchMode: z.enum(["includes", "exact"]),
|
|
805
|
+
isCaseSensitive: z.boolean(),
|
|
806
|
+
language: z.string().default("eng"),
|
|
807
|
+
operator: z.enum(["AND", "OR"]).optional(),
|
|
808
|
+
isNegated: z.boolean().optional().default(false)
|
|
809
|
+
}).strict(),
|
|
821
810
|
z.object({
|
|
822
811
|
target: z.enum([
|
|
823
812
|
"title",
|
|
@@ -897,11 +886,10 @@ const setItemsParamsSchema = z.object({
|
|
|
897
886
|
queries: setQueriesSchema,
|
|
898
887
|
sort: setItemsSortSchema,
|
|
899
888
|
page: z.number().min(1, "Page must be positive").default(1),
|
|
900
|
-
pageSize: z.number().min(1, "Page size must be positive").default(
|
|
889
|
+
pageSize: z.number().min(1, "Page size must be positive").default(48)
|
|
901
890
|
}).superRefine((value, ctx) => {
|
|
902
891
|
validateSetQueriesOperators(value.queries, ctx);
|
|
903
892
|
});
|
|
904
|
-
|
|
905
893
|
//#endregion
|
|
906
894
|
//#region src/utils/parse/index.ts
|
|
907
895
|
const TRAILING_ELLIPSIS_REGEX = /\s*\.{3}$/;
|
|
@@ -1977,7 +1965,6 @@ function parseConcept(concept, metadata, persistentUrl, belongsTo) {
|
|
|
1977
1965
|
function parseConcepts(concepts) {
|
|
1978
1966
|
return concepts.map((concept) => parseConcept(concept));
|
|
1979
1967
|
}
|
|
1980
|
-
|
|
1981
1968
|
//#endregion
|
|
1982
1969
|
//#region src/utils/fetchers/gallery.ts
|
|
1983
1970
|
/**
|
|
@@ -2004,7 +1991,7 @@ const galleryParamsSchema = z.object({
|
|
|
2004
1991
|
*/
|
|
2005
1992
|
async function fetchGallery(params, options) {
|
|
2006
1993
|
try {
|
|
2007
|
-
const version = options?.version ??
|
|
1994
|
+
const version = options?.version ?? 2;
|
|
2008
1995
|
const { uuid, filter, page, pageSize } = galleryParamsSchema.parse(params);
|
|
2009
1996
|
const response = await (options?.fetch ?? fetch)(`${version === 2 ? "https://ochre.lib.uchicago.edu/ochre/v2/ochre.php" : "https://ochre.lib.uchicago.edu/ochre"}?xquery=${encodeURIComponent(`<ochre>{
|
|
2010
1997
|
for $q in ${version === 2 ? "doc()" : "input()"}/ochre[@uuid='${uuid}']
|
|
@@ -2036,7 +2023,6 @@ async function fetchGallery(params, options) {
|
|
|
2036
2023
|
};
|
|
2037
2024
|
}
|
|
2038
2025
|
}
|
|
2039
|
-
|
|
2040
2026
|
//#endregion
|
|
2041
2027
|
//#region src/utils/fetchers/uuid.ts
|
|
2042
2028
|
/**
|
|
@@ -2048,7 +2034,7 @@ async function fetchGallery(params, options) {
|
|
|
2048
2034
|
*/
|
|
2049
2035
|
async function fetchByUuid(uuid, options) {
|
|
2050
2036
|
try {
|
|
2051
|
-
const version = options?.version ??
|
|
2037
|
+
const version = options?.version ?? 2;
|
|
2052
2038
|
const parsedUuid = uuidSchema.parse(uuid);
|
|
2053
2039
|
const response = await (options?.fetch ?? fetch)(version === 2 ? `https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?uuid=${parsedUuid}&format=json&lang="*"` : `https://ochre.lib.uchicago.edu/ochre?uuid=${parsedUuid}&format=json&lang="*"`);
|
|
2054
2040
|
if (!response.ok) throw new Error("Failed to fetch OCHRE data");
|
|
@@ -2059,7 +2045,6 @@ async function fetchByUuid(uuid, options) {
|
|
|
2059
2045
|
return [error instanceof Error ? error.message : "Unknown error", null];
|
|
2060
2046
|
}
|
|
2061
2047
|
}
|
|
2062
|
-
|
|
2063
2048
|
//#endregion
|
|
2064
2049
|
//#region src/utils/fetchers/item.ts
|
|
2065
2050
|
/**
|
|
@@ -2070,7 +2055,7 @@ async function fetchByUuid(uuid, options) {
|
|
|
2070
2055
|
*/
|
|
2071
2056
|
async function fetchItem(uuid, category, itemCategories, options) {
|
|
2072
2057
|
try {
|
|
2073
|
-
const version = options?.version ??
|
|
2058
|
+
const version = options?.version ?? 2;
|
|
2074
2059
|
const [error, data] = await fetchByUuid(uuid, {
|
|
2075
2060
|
fetch,
|
|
2076
2061
|
version
|
|
@@ -2144,15 +2129,16 @@ async function fetchItem(uuid, category, itemCategories, options) {
|
|
|
2144
2129
|
};
|
|
2145
2130
|
}
|
|
2146
2131
|
}
|
|
2147
|
-
|
|
2148
2132
|
//#endregion
|
|
2149
2133
|
//#region src/utils/fetchers/set/query-helpers.ts
|
|
2150
2134
|
const CTS_INCLUDES_STOP_WORDS = [
|
|
2151
|
-
"of",
|
|
2152
|
-
"the",
|
|
2153
2135
|
"and",
|
|
2136
|
+
"at",
|
|
2154
2137
|
"in",
|
|
2155
|
-
"it"
|
|
2138
|
+
"it",
|
|
2139
|
+
"of",
|
|
2140
|
+
"the",
|
|
2141
|
+
"to"
|
|
2156
2142
|
];
|
|
2157
2143
|
const CTS_INCLUDES_STOP_WORDS_VAR = "$ctsIncludesStopWords";
|
|
2158
2144
|
/**
|
|
@@ -2166,53 +2152,188 @@ function buildRawStringMatchPredicate(params) {
|
|
|
2166
2152
|
return `${comparedPath} = ${comparedValueLiteral}`;
|
|
2167
2153
|
}
|
|
2168
2154
|
/**
|
|
2155
|
+
* Build a combined raw string match predicate for multiple paths.
|
|
2156
|
+
*/
|
|
2157
|
+
function buildCombinedRawStringMatchPredicate(params) {
|
|
2158
|
+
const { paths, value, matchMode, isCaseSensitive } = params;
|
|
2159
|
+
const predicates = [];
|
|
2160
|
+
for (const path of paths) predicates.push(buildRawStringMatchPredicate({
|
|
2161
|
+
path,
|
|
2162
|
+
value,
|
|
2163
|
+
matchMode,
|
|
2164
|
+
isCaseSensitive
|
|
2165
|
+
}));
|
|
2166
|
+
if (predicates.length === 1) return predicates[0] ?? "false()";
|
|
2167
|
+
return `(${predicates.join(" or ")})`;
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2169
2170
|
* Build CTS word-query options for API v2 includes search.
|
|
2170
2171
|
*/
|
|
2171
2172
|
function buildCtsQueryOptionsExpression(isCaseSensitive) {
|
|
2172
2173
|
return `(${[
|
|
2173
2174
|
isCaseSensitive ? "case-sensitive" : "case-insensitive",
|
|
2174
2175
|
"diacritic-insensitive",
|
|
2175
|
-
"punctuation-insensitive"
|
|
2176
|
-
"whitespace-insensitive",
|
|
2177
|
-
"stemmed"
|
|
2176
|
+
"punctuation-insensitive"
|
|
2178
2177
|
].map((option) => stringLiteral(option)).join(", ")})`;
|
|
2179
2178
|
}
|
|
2180
2179
|
/**
|
|
2181
|
-
* Build a CTS-
|
|
2180
|
+
* Build a CTS word-query expression for an XQuery term.
|
|
2182
2181
|
*/
|
|
2183
|
-
function
|
|
2184
|
-
const {
|
|
2182
|
+
function buildCtsWordQueryExpression(params) {
|
|
2183
|
+
const { termExpression, isCaseSensitive } = params;
|
|
2184
|
+
return `cts:word-query(${termExpression}, ${buildCtsQueryOptionsExpression(isCaseSensitive)})`;
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Build tokenized search declarations for CTS-backed queries.
|
|
2188
|
+
*/
|
|
2189
|
+
function buildTokenizedSearchDeclarations(params) {
|
|
2190
|
+
const { value, isCaseSensitive, queryIndex } = params;
|
|
2185
2191
|
const searchStringVar = `$query${queryIndex}SearchString`;
|
|
2186
2192
|
const rawTermsVar = `$query${queryIndex}RawTerms`;
|
|
2187
2193
|
const termsVar = `$query${queryIndex}Terms`;
|
|
2194
|
+
const tokenSourceExpression = isCaseSensitive ? searchStringVar : `fn:lower-case(${searchStringVar})`;
|
|
2195
|
+
return {
|
|
2196
|
+
declarations: [
|
|
2197
|
+
`let ${searchStringVar} := ${stringLiteral(value)}`,
|
|
2198
|
+
String.raw`let ${rawTermsVar} := fn:tokenize(${tokenSourceExpression}, "\W+")`,
|
|
2199
|
+
`let ${termsVar} :=
|
|
2200
|
+
for $term in ${rawTermsVar}
|
|
2201
|
+
let $normalizedTerm := fn:lower-case($term)
|
|
2202
|
+
where $normalizedTerm ne "" and not($normalizedTerm = ${CTS_INCLUDES_STOP_WORDS_VAR})
|
|
2203
|
+
return $term`
|
|
2204
|
+
],
|
|
2205
|
+
termsVar
|
|
2206
|
+
};
|
|
2207
|
+
}
|
|
2208
|
+
/**
|
|
2209
|
+
* Build a CTS-backed field includes predicate for an XQuery string.
|
|
2210
|
+
*/
|
|
2211
|
+
function buildCtsFieldIncludesPredicate(params) {
|
|
2212
|
+
const { path, value, isCaseSensitive, queryIndex } = params;
|
|
2213
|
+
const tokenizedSearchDeclarations = buildTokenizedSearchDeclarations({
|
|
2214
|
+
value,
|
|
2215
|
+
isCaseSensitive,
|
|
2216
|
+
queryIndex
|
|
2217
|
+
});
|
|
2188
2218
|
const ctsQueryVar = `$query${queryIndex}CtsQuery`;
|
|
2189
|
-
const ctsOptionsExpression = buildCtsQueryOptionsExpression(isCaseSensitive);
|
|
2190
2219
|
const fallbackPredicate = buildRawStringMatchPredicate({
|
|
2191
2220
|
path,
|
|
2192
2221
|
value,
|
|
2193
2222
|
matchMode: "includes",
|
|
2194
2223
|
isCaseSensitive
|
|
2195
2224
|
});
|
|
2225
|
+
return {
|
|
2226
|
+
declarations: [...tokenizedSearchDeclarations.declarations, `let ${ctsQueryVar} :=
|
|
2227
|
+
if (count(${tokenizedSearchDeclarations.termsVar}) = 1)
|
|
2228
|
+
then ${buildCtsWordQueryExpression({
|
|
2229
|
+
termExpression: `${tokenizedSearchDeclarations.termsVar}[1]`,
|
|
2230
|
+
isCaseSensitive
|
|
2231
|
+
})}
|
|
2232
|
+
else if (count(${tokenizedSearchDeclarations.termsVar}) gt 1)
|
|
2233
|
+
then cts:and-query((
|
|
2234
|
+
for $term in ${tokenizedSearchDeclarations.termsVar}
|
|
2235
|
+
return ${buildCtsWordQueryExpression({
|
|
2236
|
+
termExpression: "$term",
|
|
2237
|
+
isCaseSensitive
|
|
2238
|
+
})}
|
|
2239
|
+
))
|
|
2240
|
+
else ()`],
|
|
2241
|
+
predicate: `(if (exists(${ctsQueryVar})) then cts:contains(${path}, ${ctsQueryVar}) else ${fallbackPredicate})`
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Build the raw search paths for item-level string search.
|
|
2246
|
+
*/
|
|
2247
|
+
function buildItemStringSearchPaths(language) {
|
|
2248
|
+
return [`string-join(identification/label/content[@xml:lang="${language}"]/string, "")`, `string-join(properties//property/value[not(@inherited="true")]/content[@xml:lang="${language}"]/string, "")`];
|
|
2249
|
+
}
|
|
2250
|
+
/**
|
|
2251
|
+
* Build the identification branch for an item-level CTS string search.
|
|
2252
|
+
*/
|
|
2253
|
+
function buildItemStringIdentificationBranch(params) {
|
|
2254
|
+
const { termExpression, isCaseSensitive, language } = params;
|
|
2255
|
+
return `cts:element-query(xs:QName("identification"),
|
|
2256
|
+
cts:and-query((
|
|
2257
|
+
cts:element-attribute-value-query(xs:QName("content"), xs:QName("xml:lang"), ${stringLiteral(language)}),
|
|
2258
|
+
${buildCtsWordQueryExpression({
|
|
2259
|
+
termExpression,
|
|
2260
|
+
isCaseSensitive
|
|
2261
|
+
})}
|
|
2262
|
+
))
|
|
2263
|
+
)`;
|
|
2264
|
+
}
|
|
2265
|
+
/**
|
|
2266
|
+
* Build the property value branch for an item-level CTS string search.
|
|
2267
|
+
*/
|
|
2268
|
+
function buildItemStringPropertyValueBranch(params) {
|
|
2269
|
+
const { termExpression, isCaseSensitive, language } = params;
|
|
2270
|
+
return `cts:element-query(xs:QName("properties"),
|
|
2271
|
+
cts:element-query(xs:QName("property"),
|
|
2272
|
+
cts:element-query(xs:QName("value"),
|
|
2273
|
+
cts:and-query((
|
|
2274
|
+
cts:not-query(cts:element-attribute-value-query(xs:QName("value"), xs:QName("inherited"), "true")),
|
|
2275
|
+
cts:element-query(xs:QName("content"),
|
|
2276
|
+
cts:and-query((
|
|
2277
|
+
cts:element-attribute-value-query(xs:QName("content"), xs:QName("xml:lang"), ${stringLiteral(language)}),
|
|
2278
|
+
${buildCtsWordQueryExpression({
|
|
2279
|
+
termExpression,
|
|
2280
|
+
isCaseSensitive
|
|
2281
|
+
})}
|
|
2282
|
+
))
|
|
2283
|
+
)
|
|
2284
|
+
))
|
|
2285
|
+
)
|
|
2286
|
+
)
|
|
2287
|
+
)`;
|
|
2288
|
+
}
|
|
2289
|
+
/**
|
|
2290
|
+
* Build an item-level CTS string search predicate.
|
|
2291
|
+
*/
|
|
2292
|
+
function buildItemStringSearchPredicate(params) {
|
|
2293
|
+
const { query, version, queryIndex } = params;
|
|
2294
|
+
const fallbackPredicate = buildCombinedRawStringMatchPredicate({
|
|
2295
|
+
paths: buildItemStringSearchPaths(query.language),
|
|
2296
|
+
value: query.value,
|
|
2297
|
+
matchMode: query.matchMode,
|
|
2298
|
+
isCaseSensitive: query.isCaseSensitive
|
|
2299
|
+
});
|
|
2300
|
+
if (query.matchMode !== "includes" || version !== 2) return {
|
|
2301
|
+
declarations: [],
|
|
2302
|
+
predicate: fallbackPredicate
|
|
2303
|
+
};
|
|
2304
|
+
const tokenizedSearchDeclarations = buildTokenizedSearchDeclarations({
|
|
2305
|
+
value: query.value,
|
|
2306
|
+
isCaseSensitive: query.isCaseSensitive,
|
|
2307
|
+
queryIndex
|
|
2308
|
+
});
|
|
2309
|
+
const termQueriesVar = `$query${queryIndex}TermQueries`;
|
|
2310
|
+
const ctsQueryVar = `$query${queryIndex}CtsQuery`;
|
|
2196
2311
|
return {
|
|
2197
2312
|
declarations: [
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2313
|
+
...tokenizedSearchDeclarations.declarations,
|
|
2314
|
+
`let ${termQueriesVar} :=
|
|
2315
|
+
for $term in ${tokenizedSearchDeclarations.termsVar}
|
|
2316
|
+
return
|
|
2317
|
+
cts:or-query((
|
|
2318
|
+
${buildItemStringIdentificationBranch({
|
|
2319
|
+
termExpression: "$term",
|
|
2320
|
+
isCaseSensitive: query.isCaseSensitive,
|
|
2321
|
+
language: query.language
|
|
2322
|
+
})},
|
|
2323
|
+
${buildItemStringPropertyValueBranch({
|
|
2324
|
+
termExpression: "$term",
|
|
2325
|
+
isCaseSensitive: query.isCaseSensitive,
|
|
2326
|
+
language: query.language
|
|
2327
|
+
})}
|
|
2328
|
+
))`,
|
|
2205
2329
|
`let ${ctsQueryVar} :=
|
|
2206
|
-
if (count(${termsVar}) = 1)
|
|
2207
|
-
then
|
|
2208
|
-
else if (count(${termsVar}) gt 1)
|
|
2209
|
-
then cts:
|
|
2210
|
-
for $term in ${termsVar}
|
|
2211
|
-
return cts:word-query($term, ${ctsOptionsExpression})
|
|
2212
|
-
), 5, ("unordered"))
|
|
2330
|
+
if (count(${tokenizedSearchDeclarations.termsVar}) = 1)
|
|
2331
|
+
then ${termQueriesVar}[1]
|
|
2332
|
+
else if (count(${tokenizedSearchDeclarations.termsVar}) gt 1)
|
|
2333
|
+
then cts:and-query(${termQueriesVar})
|
|
2213
2334
|
else ()`
|
|
2214
2335
|
],
|
|
2215
|
-
predicate: `(if (exists(${ctsQueryVar})) then cts:contains(
|
|
2336
|
+
predicate: `(if (exists(${ctsQueryVar})) then cts:contains(., ${ctsQueryVar}) else ${fallbackPredicate})`
|
|
2216
2337
|
};
|
|
2217
2338
|
}
|
|
2218
2339
|
/**
|
|
@@ -2220,7 +2341,7 @@ function buildCtsIncludesPredicate(params) {
|
|
|
2220
2341
|
*/
|
|
2221
2342
|
function buildStringMatchPredicate(params) {
|
|
2222
2343
|
const { path, value, matchMode, isCaseSensitive, version, queryIndex } = params;
|
|
2223
|
-
if (matchMode === "includes" && version === 2) return
|
|
2344
|
+
if (matchMode === "includes" && version === 2) return buildCtsFieldIncludesPredicate({
|
|
2224
2345
|
path,
|
|
2225
2346
|
value,
|
|
2226
2347
|
isCaseSensitive,
|
|
@@ -2267,7 +2388,7 @@ function buildPropertyValuePredicate(params) {
|
|
|
2267
2388
|
predicate: `.//properties//property[value[@rawValue=${stringLiteral(query.value)}]]`
|
|
2268
2389
|
};
|
|
2269
2390
|
const compiledStringPredicate = buildStringMatchPredicate({
|
|
2270
|
-
path: `string-join(value/content[@xml:lang="${query.language}"]/string, "")`,
|
|
2391
|
+
path: query.matchMode === "includes" && version === 2 ? `string-join(value[not(@inherited="true")]/content[@xml:lang="${query.language}"]/string, "")` : `string-join(value/content[@xml:lang="${query.language}"]/string, "")`,
|
|
2271
2392
|
value: query.value,
|
|
2272
2393
|
matchMode: query.matchMode,
|
|
2273
2394
|
isCaseSensitive: query.isCaseSensitive,
|
|
@@ -2285,6 +2406,11 @@ function buildPropertyValuePredicate(params) {
|
|
|
2285
2406
|
function buildQueryPredicate(params) {
|
|
2286
2407
|
const { query, version, queryIndex } = params;
|
|
2287
2408
|
switch (query.target) {
|
|
2409
|
+
case "string": return buildItemStringSearchPredicate({
|
|
2410
|
+
query,
|
|
2411
|
+
version,
|
|
2412
|
+
queryIndex
|
|
2413
|
+
});
|
|
2288
2414
|
case "title": return buildStringMatchPredicate({
|
|
2289
2415
|
path: `string-join(identification/label/content[@xml:lang="${query.language}"]/string, "")`,
|
|
2290
2416
|
value: query.value,
|
|
@@ -2378,7 +2504,6 @@ function buildQueryFilters(params) {
|
|
|
2378
2504
|
predicate: predicateParts.join(" ")
|
|
2379
2505
|
};
|
|
2380
2506
|
}
|
|
2381
|
-
|
|
2382
2507
|
//#endregion
|
|
2383
2508
|
//#region src/utils/fetchers/set/items.ts
|
|
2384
2509
|
function mapSortDirectionToXQuery(direction) {
|
|
@@ -2467,7 +2592,7 @@ function buildOrderedItemsClause(sort) {
|
|
|
2467
2592
|
* @returns An XQuery string
|
|
2468
2593
|
*/
|
|
2469
2594
|
function buildXQuery$1(params, options) {
|
|
2470
|
-
const version = options?.version ??
|
|
2595
|
+
const version = options?.version ?? 2;
|
|
2471
2596
|
const { propertyVariableUuids, queries, sort, setScopeUuids, belongsToCollectionScopeUuids, page, pageSize } = params;
|
|
2472
2597
|
const startPosition = (page - 1) * pageSize + 1;
|
|
2473
2598
|
const endPosition = page * pageSize;
|
|
@@ -2522,7 +2647,7 @@ function buildXQuery$1(params, options) {
|
|
|
2522
2647
|
*/
|
|
2523
2648
|
async function fetchSetItems(params, itemCategories, options) {
|
|
2524
2649
|
try {
|
|
2525
|
-
const version = options?.version ??
|
|
2650
|
+
const version = options?.version ?? 2;
|
|
2526
2651
|
const { setScopeUuids, belongsToCollectionScopeUuids, propertyVariableUuids, queries, sort, page, pageSize } = setItemsParamsSchema.parse(params);
|
|
2527
2652
|
const xquery = buildXQuery$1({
|
|
2528
2653
|
setScopeUuids,
|
|
@@ -2533,7 +2658,13 @@ async function fetchSetItems(params, itemCategories, options) {
|
|
|
2533
2658
|
page,
|
|
2534
2659
|
pageSize
|
|
2535
2660
|
}, { version });
|
|
2536
|
-
|
|
2661
|
+
let response;
|
|
2662
|
+
if (version === 2) response = await (options?.fetch ?? fetch)("https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?xquery&format=json", {
|
|
2663
|
+
method: "POST",
|
|
2664
|
+
body: xquery,
|
|
2665
|
+
headers: { "Content-Type": "application/xquery" }
|
|
2666
|
+
});
|
|
2667
|
+
else response = await (options?.fetch ?? fetch)(`https://ochre.lib.uchicago.edu/ochre?xquery=${encodeURIComponent(xquery)}&format=json&lang="*"`);
|
|
2537
2668
|
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`);
|
|
2538
2669
|
const data = await response.json();
|
|
2539
2670
|
if (Array.isArray(data.result) || Object.keys(data.result).length === 0) throw new Error("No items found");
|
|
@@ -2611,7 +2742,6 @@ async function fetchSetItems(params, itemCategories, options) {
|
|
|
2611
2742
|
};
|
|
2612
2743
|
}
|
|
2613
2744
|
}
|
|
2614
|
-
|
|
2615
2745
|
//#endregion
|
|
2616
2746
|
//#region src/utils/fetchers/set/property-values-by-property-variables.ts
|
|
2617
2747
|
function parsePropertyValueLabel(content) {
|
|
@@ -2764,7 +2894,7 @@ const responseSchema = z.object({ result: z.union([z.object({ ochre: z.object({
|
|
|
2764
2894
|
* @returns An XQuery string
|
|
2765
2895
|
*/
|
|
2766
2896
|
function buildXQuery(params, options) {
|
|
2767
|
-
const version = options?.version ??
|
|
2897
|
+
const version = options?.version ?? 2;
|
|
2768
2898
|
const { setScopeUuids, belongsToCollectionScopeUuids, propertyVariableUuids, queries, attributes, isLimitedToLeafPropertyValues } = params;
|
|
2769
2899
|
let setScopeFilter = "/set/items/*";
|
|
2770
2900
|
if (setScopeUuids.length > 0) setScopeFilter = `/set[(${setScopeUuids.map((uuid) => `@uuid="${uuid}"`).join(" or ")})]/items/*`;
|
|
@@ -2837,7 +2967,7 @@ return (${returnedSequences.join(", ")})`}}</ochre>`;
|
|
|
2837
2967
|
*/
|
|
2838
2968
|
async function fetchSetPropertyValuesByPropertyVariables(params, options) {
|
|
2839
2969
|
try {
|
|
2840
|
-
const version = options?.version ??
|
|
2970
|
+
const version = options?.version ?? 2;
|
|
2841
2971
|
const { setScopeUuids, belongsToCollectionScopeUuids, propertyVariableUuids, queries, attributes, isLimitedToLeafPropertyValues } = setPropertyValuesByPropertyVariablesParamsSchema.parse(params);
|
|
2842
2972
|
const xquery = buildXQuery({
|
|
2843
2973
|
setScopeUuids,
|
|
@@ -2847,7 +2977,13 @@ async function fetchSetPropertyValuesByPropertyVariables(params, options) {
|
|
|
2847
2977
|
attributes,
|
|
2848
2978
|
isLimitedToLeafPropertyValues
|
|
2849
2979
|
}, { version });
|
|
2850
|
-
|
|
2980
|
+
let response;
|
|
2981
|
+
if (version === 2) response = await (options?.fetch ?? fetch)("https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?xquery&format=json", {
|
|
2982
|
+
method: "POST",
|
|
2983
|
+
body: xquery,
|
|
2984
|
+
headers: { "Content-Type": "application/xquery" }
|
|
2985
|
+
});
|
|
2986
|
+
else response = await (options?.fetch ?? fetch)(`https://ochre.lib.uchicago.edu/ochre?xquery=${encodeURIComponent(xquery)}&format=json&lang="*"`);
|
|
2851
2987
|
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`);
|
|
2852
2988
|
const data = await response.json();
|
|
2853
2989
|
const parsedResultRaw = responseSchema.parse(data);
|
|
@@ -2899,7 +3035,6 @@ async function fetchSetPropertyValuesByPropertyVariables(params, options) {
|
|
|
2899
3035
|
};
|
|
2900
3036
|
}
|
|
2901
3037
|
}
|
|
2902
|
-
|
|
2903
3038
|
//#endregion
|
|
2904
3039
|
//#region src/utils/getters.ts
|
|
2905
3040
|
const DEFAULT_OPTIONS = { includeNestedProperties: false };
|
|
@@ -3153,7 +3288,6 @@ function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
|
|
|
3153
3288
|
}
|
|
3154
3289
|
return false;
|
|
3155
3290
|
}
|
|
3156
|
-
|
|
3157
3291
|
//#endregion
|
|
3158
3292
|
//#region src/utils/parse/website.ts
|
|
3159
3293
|
const SEGMENT_UNIQUE_SLUG_PREFIX_REGEX = /^\$[^-]*-/;
|
|
@@ -4404,7 +4538,7 @@ function parseContexts(contexts) {
|
|
|
4404
4538
|
}
|
|
4405
4539
|
return contextsParsed;
|
|
4406
4540
|
}
|
|
4407
|
-
function parseWebsite(websiteTree, metadata, belongsTo, { version =
|
|
4541
|
+
function parseWebsite(websiteTree, metadata, belongsTo, { version = 2 } = {}) {
|
|
4408
4542
|
if (!websiteTree.properties) throw new Error("Website properties not found");
|
|
4409
4543
|
if (typeof websiteTree.items === "string" || !("resource" in websiteTree.items)) throw new Error("Website pages not found");
|
|
4410
4544
|
const resources = ensureArray(websiteTree.items.resource);
|
|
@@ -4424,7 +4558,6 @@ function parseWebsite(websiteTree, metadata, belongsTo, { version = DEFAULT_API_
|
|
|
4424
4558
|
properties
|
|
4425
4559
|
};
|
|
4426
4560
|
}
|
|
4427
|
-
|
|
4428
4561
|
//#endregion
|
|
4429
4562
|
//#region src/utils/fetchers/website.ts
|
|
4430
4563
|
const API_VERSION_SUFFIX_REGEX = /-v\d+$/;
|
|
@@ -4437,7 +4570,7 @@ const API_VERSION_SUFFIX_REGEX = /-v\d+$/;
|
|
|
4437
4570
|
function parseApiVersionSuffix(abbreviation) {
|
|
4438
4571
|
if (!API_VERSION_SUFFIX_REGEX.test(abbreviation)) return {
|
|
4439
4572
|
abbreviation,
|
|
4440
|
-
version:
|
|
4573
|
+
version: 2
|
|
4441
4574
|
};
|
|
4442
4575
|
const result = apiVersionSuffixSchema.safeParse(abbreviation.slice(-3));
|
|
4443
4576
|
if (!result.success) throw new Error("Invalid API version suffix");
|
|
@@ -4497,6 +4630,5 @@ async function fetchWebsite(abbreviation, options) {
|
|
|
4497
4630
|
};
|
|
4498
4631
|
}
|
|
4499
4632
|
}
|
|
4500
|
-
|
|
4501
4633
|
//#endregion
|
|
4502
|
-
export { DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValuesByPropertyVariables, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
|
|
4634
|
+
export { DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValuesByPropertyVariables, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ochre-sdk",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.23",
|
|
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",
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"zod": "^4.3.6"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@antfu/eslint-config": "^7.7.
|
|
49
|
+
"@antfu/eslint-config": "^7.7.3",
|
|
50
50
|
"@types/node": "^24.12.0",
|
|
51
|
-
"bumpp": "^
|
|
52
|
-
"eslint": "^10.0.
|
|
51
|
+
"bumpp": "^11.0.1",
|
|
52
|
+
"eslint": "^10.0.3",
|
|
53
53
|
"prettier": "^3.8.1",
|
|
54
|
-
"tsdown": "^0.
|
|
54
|
+
"tsdown": "^0.21.4",
|
|
55
55
|
"typescript": "^5.9.3"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|