ochre-sdk 1.0.72 → 1.0.73
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/README.md +22 -0
- package/dist/constants.mjs +0 -5
- package/dist/fetchers/gallery.mjs +11 -5
- package/dist/fetchers/item-children.mjs +4 -2
- package/dist/fetchers/item-links.mjs +10 -5
- package/dist/fetchers/item-ocr-data.d.mts +37 -0
- package/dist/fetchers/item-ocr-data.mjs +166 -0
- package/dist/fetchers/item.mjs +43 -58
- package/dist/fetchers/set/items.mjs +26 -12
- package/dist/fetchers/set/property-values.mjs +24 -14
- package/dist/fetchers/website-metadata.mjs +7 -3
- package/dist/fetchers/website.mjs +20 -3
- package/dist/helpers.d.mts +1 -5
- package/dist/helpers.mjs +1 -5
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +3 -3
- package/dist/parsers/index.d.mts +3 -10
- package/dist/parsers/index.mjs +1 -75
- package/dist/query.d.mts +19 -28
- package/dist/query.mjs +104 -86
- package/dist/schemas.d.mts +7 -8
- package/dist/schemas.mjs +8 -10
- package/dist/types/index.d.mts +27 -57
- package/dist/utilities.d.mts +25 -1
- package/dist/utilities.mjs +41 -1
- package/dist/xml/schemas.d.mts +2 -7
- package/dist/xml/schemas.mjs +1 -39
- package/dist/xml/types.d.mts +1 -44
- package/package.json +2 -2
- package/dist/fetchers/ocr-matches.d.mts +0 -44
- package/dist/fetchers/ocr-matches.mjs +0 -134
package/dist/schemas.d.mts
CHANGED
|
@@ -38,7 +38,7 @@ declare const renderOptionsSchema: v.SchemaWithPipe<readonly [v.StringSchema<und
|
|
|
38
38
|
declare const setPropertyValuesParametersSchema: v.ObjectSchema<{
|
|
39
39
|
readonly setScopeUuids: v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, v.MinLengthAction<string[], 1, "At least one set scope UUID is required">]>;
|
|
40
40
|
readonly belongsToCollectionScopeUuids: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, readonly []>;
|
|
41
|
-
readonly queries: v.OptionalSchema<v.NullableSchema<v.
|
|
41
|
+
readonly queries: v.OptionalSchema<v.NullableSchema<v.GenericSchema<unknown, Query>, undefined>, null>;
|
|
42
42
|
readonly attributes: v.OptionalSchema<v.ObjectSchema<{
|
|
43
43
|
readonly bibliographies: v.GenericSchema<unknown, boolean>;
|
|
44
44
|
readonly periods: v.GenericSchema<unknown, boolean>;
|
|
@@ -49,15 +49,14 @@ declare const setPropertyValuesParametersSchema: v.ObjectSchema<{
|
|
|
49
49
|
readonly isLimitedToLeafPropertyValues: v.GenericSchema<unknown, boolean>;
|
|
50
50
|
}, undefined>;
|
|
51
51
|
/**
|
|
52
|
-
* Schema for validating OCR
|
|
52
|
+
* Schema for validating the parameters for the item OCR data fetching function
|
|
53
53
|
* @internal
|
|
54
54
|
*/
|
|
55
|
-
declare const
|
|
56
|
-
readonly
|
|
57
|
-
readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.
|
|
55
|
+
declare const itemOcrDataParametersSchema: v.ObjectSchema<{
|
|
56
|
+
readonly uuid: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>;
|
|
57
|
+
readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "A search value is required">]>;
|
|
58
58
|
readonly matchMode: v.OptionalSchema<v.PicklistSchema<["includes", "exact"], undefined>, "includes">;
|
|
59
59
|
readonly isCaseSensitive: v.GenericSchema<unknown, boolean>;
|
|
60
|
-
readonly maxMatchesPerItem: v.OptionalSchema<v.GenericSchema<unknown, number>, 50>;
|
|
61
60
|
}, undefined>;
|
|
62
61
|
/**
|
|
63
62
|
* Schema for validating Set items parameters
|
|
@@ -66,7 +65,7 @@ declare const ocrMatchesParametersSchema: v.ObjectSchema<{
|
|
|
66
65
|
declare const setItemsParametersSchema: v.ObjectSchema<{
|
|
67
66
|
readonly setScopeUuids: v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, v.MinLengthAction<string[], 1, "At least one set scope UUID is required">]>;
|
|
68
67
|
readonly belongsToCollectionScopeUuids: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, readonly []>;
|
|
69
|
-
readonly queries: v.OptionalSchema<v.NullableSchema<v.
|
|
68
|
+
readonly queries: v.OptionalSchema<v.NullableSchema<v.GenericSchema<unknown, Query>, undefined>, null>;
|
|
70
69
|
readonly sort: v.OptionalSchema<v.VariantSchema<"target", [v.StrictObjectSchema<{
|
|
71
70
|
readonly target: v.LiteralSchema<"none", undefined>;
|
|
72
71
|
}, undefined>, v.StrictObjectSchema<{
|
|
@@ -86,4 +85,4 @@ declare const setItemsParametersSchema: v.ObjectSchema<{
|
|
|
86
85
|
readonly pageSize: v.OptionalSchema<v.GenericSchema<unknown, number>, 48>;
|
|
87
86
|
}, undefined>;
|
|
88
87
|
//#endregion
|
|
89
|
-
export { componentSchema, gallerySchema, iso639_3Schema,
|
|
88
|
+
export { componentSchema, gallerySchema, iso639_3Schema, itemOcrDataParametersSchema, renderOptionsSchema, setItemsParametersSchema, setPropertyValuesParametersSchema, uuidSchema };
|
package/dist/schemas.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { isPseudoUuid } from "./utilities.mjs";
|
|
2
2
|
import "./helpers.mjs";
|
|
3
|
-
import { OCR_DISJUNCTION_ERROR_MESSAGE, hasOcrQueryInDisjunction } from "./query.mjs";
|
|
4
3
|
import * as v from "valibot";
|
|
5
4
|
//#region src/schemas.ts
|
|
6
5
|
const positiveNumber = (message) => v.pipe(v.number(), v.minValue(1, message));
|
|
@@ -143,7 +142,7 @@ const setQueryLeafSchema = v.union([
|
|
|
143
142
|
...standardQueryFields
|
|
144
143
|
}),
|
|
145
144
|
v.strictObject({
|
|
146
|
-
target: v.literal("
|
|
145
|
+
target: v.literal("ocrText"),
|
|
147
146
|
value: v.string(),
|
|
148
147
|
matchMode: standardQueryFields.matchMode,
|
|
149
148
|
isCaseSensitive: standardQueryFields.isCaseSensitive,
|
|
@@ -175,7 +174,7 @@ const setQuerySchema = v.lazy(() => v.union([
|
|
|
175
174
|
* Schema for validating Set queries
|
|
176
175
|
* @internal
|
|
177
176
|
*/
|
|
178
|
-
const setQueriesSchema = v.optional(v.nullable(
|
|
177
|
+
const setQueriesSchema = v.optional(v.nullable(setQuerySchema), null);
|
|
179
178
|
/**
|
|
180
179
|
* Schema for validating Set items sort
|
|
181
180
|
* @internal
|
|
@@ -222,15 +221,14 @@ const setPropertyValuesParametersSchema = v.object({
|
|
|
222
221
|
isLimitedToLeafPropertyValues: defaultBoolean(false)
|
|
223
222
|
});
|
|
224
223
|
/**
|
|
225
|
-
* Schema for validating OCR
|
|
224
|
+
* Schema for validating the parameters for the item OCR data fetching function
|
|
226
225
|
* @internal
|
|
227
226
|
*/
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
value: v.pipe(v.string(), v.
|
|
227
|
+
const itemOcrDataParametersSchema = v.object({
|
|
228
|
+
uuid: uuidSchema,
|
|
229
|
+
value: v.pipe(v.string(), v.check((value) => value.trim() !== "", "A search value is required")),
|
|
231
230
|
matchMode: v.optional(v.picklist(["includes", "exact"]), "includes"),
|
|
232
|
-
isCaseSensitive: defaultBoolean(false)
|
|
233
|
-
maxMatchesPerItem: v.optional(positiveNumber("Max matches per item must be positive"), 50)
|
|
231
|
+
isCaseSensitive: defaultBoolean(false)
|
|
234
232
|
});
|
|
235
233
|
/**
|
|
236
234
|
* Schema for validating Set items parameters
|
|
@@ -245,4 +243,4 @@ const setItemsParametersSchema = v.object({
|
|
|
245
243
|
pageSize: v.optional(positiveNumber("Page size must be positive"), 48)
|
|
246
244
|
});
|
|
247
245
|
//#endregion
|
|
248
|
-
export { componentSchema, gallerySchema, iso639_3Schema,
|
|
246
|
+
export { componentSchema, gallerySchema, iso639_3Schema, itemOcrDataParametersSchema, renderOptionsSchema, setItemsParametersSchema, setPropertyValuesParametersSchema, uuidSchema };
|
package/dist/types/index.d.mts
CHANGED
|
@@ -263,58 +263,29 @@ type ImageMap = {
|
|
|
263
263
|
height: number;
|
|
264
264
|
};
|
|
265
265
|
/**
|
|
266
|
-
*
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
y
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
*
|
|
274
|
-
*/
|
|
275
|
-
type OcrWord = {
|
|
276
|
-
content: string;
|
|
277
|
-
x: number;
|
|
278
|
-
y: number;
|
|
279
|
-
width: number;
|
|
280
|
-
height: number;
|
|
281
|
-
vertices: Array<OcrPoint>;
|
|
282
|
-
};
|
|
283
|
-
/**
|
|
284
|
-
* Text line of an OCR text block in OCHRE
|
|
285
|
-
*/
|
|
286
|
-
type OcrTextLine = {
|
|
287
|
-
content: string;
|
|
288
|
-
words: Array<OcrWord>;
|
|
289
|
-
};
|
|
290
|
-
/**
|
|
291
|
-
* Text block of an OCR page in OCHRE
|
|
292
|
-
*/
|
|
293
|
-
type OcrTextBlock = {
|
|
294
|
-
lines: Array<OcrTextLine>;
|
|
295
|
-
};
|
|
296
|
-
/**
|
|
297
|
-
* OCR page of a resource in OCHRE
|
|
298
|
-
*/
|
|
299
|
-
type OcrPage = {
|
|
300
|
-
number: number | null;
|
|
301
|
-
fileName: string | null;
|
|
302
|
-
width: number | null;
|
|
303
|
-
height: number | null;
|
|
304
|
-
blocks: Array<OcrTextBlock>;
|
|
305
|
-
};
|
|
306
|
-
/**
|
|
307
|
-
* A run of adjacent OCR words matching a search value in OCHRE
|
|
266
|
+
* Positioned OCR string in OCHRE
|
|
267
|
+
*
|
|
268
|
+
* OCHRE gives no guarantee about the node hierarchy inside a Resource's
|
|
269
|
+
* `<ocr>` layer, so only `<string>` nodes are parsed, at whatever depth they
|
|
270
|
+
* occur. `x` and `y` come from `HPOS` and `VPOS` and locate the top-left
|
|
271
|
+
* corner of the string's box, while `vertices` is its full bounding polygon,
|
|
272
|
+
* which is not necessarily rectangular. Every geometry attribute is optional
|
|
273
|
+
* in the source, so each one is null when absent or unparseable.
|
|
308
274
|
*
|
|
309
|
-
* `
|
|
310
|
-
*
|
|
275
|
+
* `resourceUuid` is the Resource that owns the OCR layer, which differs from
|
|
276
|
+
* the requested item when the OCR lives on a child Resource.
|
|
311
277
|
*/
|
|
312
|
-
type
|
|
313
|
-
uuid: string;
|
|
278
|
+
type OcrString = {
|
|
314
279
|
resourceUuid: string | null;
|
|
315
|
-
page: Omit<OcrPage, "blocks">;
|
|
316
280
|
content: string;
|
|
317
|
-
|
|
281
|
+
x: number | null;
|
|
282
|
+
y: number | null;
|
|
283
|
+
width: number | null;
|
|
284
|
+
height: number | null;
|
|
285
|
+
vertices: Array<{
|
|
286
|
+
x: number;
|
|
287
|
+
y: number;
|
|
288
|
+
}>;
|
|
318
289
|
};
|
|
319
290
|
/**
|
|
320
291
|
* Note in OCHRE
|
|
@@ -734,7 +705,6 @@ type Resource<T extends LanguageCodes = LanguageCodes, U extends ItemPayloadKind
|
|
|
734
705
|
image: Image<T> | null;
|
|
735
706
|
document: MultilingualString<T> | null;
|
|
736
707
|
imageMap: ImageMap | null;
|
|
737
|
-
ocr: Array<OcrPage>;
|
|
738
708
|
coordinates: Array<Coordinates<T>>;
|
|
739
709
|
periods: Array<Period<T, "embedded">>;
|
|
740
710
|
links: ItemLinks<T>;
|
|
@@ -845,12 +815,12 @@ type SetItemsSort = {
|
|
|
845
815
|
/**
|
|
846
816
|
* Represents a leaf query for Set items
|
|
847
817
|
*
|
|
848
|
-
* The `
|
|
849
|
-
*
|
|
850
|
-
* than a CTS term,
|
|
851
|
-
*
|
|
852
|
-
*
|
|
853
|
-
*
|
|
818
|
+
* The `ocrText` target matches the OCR text layer of Resource items. Because
|
|
819
|
+
* Set item projections do not carry `<ocrText>`, it is resolved by a document
|
|
820
|
+
* join rather than a CTS term, so it composes with `and`, `or`, and `isNegated`
|
|
821
|
+
* at the cost of one extra search branch per distinct OCR text value in a
|
|
822
|
+
* disjunction. OCR text carries no language, so `ocrText` leaves take no
|
|
823
|
+
* `language`.
|
|
854
824
|
*/
|
|
855
825
|
type QueryLeaf = {
|
|
856
826
|
target: "property";
|
|
@@ -918,7 +888,7 @@ type QueryLeaf = {
|
|
|
918
888
|
language: string;
|
|
919
889
|
isNegated?: boolean;
|
|
920
890
|
} | {
|
|
921
|
-
target: "
|
|
891
|
+
target: "ocrText";
|
|
922
892
|
value: string;
|
|
923
893
|
matchMode: "includes" | "exact";
|
|
924
894
|
isCaseSensitive: boolean;
|
|
@@ -944,4 +914,4 @@ type QueryGroup = {
|
|
|
944
914
|
*/
|
|
945
915
|
type Query = QueryLeaf | QueryGroup;
|
|
946
916
|
//#endregion
|
|
947
|
-
export { AnyBibliography, AnyConcept, AnyItem, AnyPeriod, AnyPerson, AnyPropertyValue, AnyPropertyVariable, AnyResource, AnySet, AnySpatialUnit, AnyText, AnyTree, BaseItem, BaseItemLink, BelongsTo, Bibliography, BibliographyEntryInfo, BibliographyItemLink, BibliographySourceDocument, Concept, ConceptItemLink, ContainedItemCategory, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Context, ContextItem, ContextItemCategory, ContextNode, Coordinates, CoordinatesSource, DictionaryUnitItemLink, EmbeddedBibliography, EmbeddedConcept, EmbeddedItem, EmbeddedPeriod, EmbeddedPerson, EmbeddedPropertyValue, EmbeddedPropertyVariable, EmbeddedResource, EmbeddedSet, EmbeddedSpatialUnit, EmbeddedText, EmbeddedTree, Event, Gallery, Heading, HeadingItemCategory, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemCategoryWithEmbeddedItems, ItemContainerCategory, ItemLink, ItemLinkCategory, ItemLinks, ItemPayloadKind, ItemProperty, ItemWithoutEmbeddedItems, LanguageCodes, License, Metadata, Note, Observation,
|
|
917
|
+
export { AnyBibliography, AnyConcept, AnyItem, AnyPeriod, AnyPerson, AnyPropertyValue, AnyPropertyVariable, AnyResource, AnySet, AnySpatialUnit, AnyText, AnyTree, BaseItem, BaseItemLink, BelongsTo, Bibliography, BibliographyEntryInfo, BibliographyItemLink, BibliographySourceDocument, Concept, ConceptItemLink, ContainedItemCategory, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Context, ContextItem, ContextItemCategory, ContextNode, Coordinates, CoordinatesSource, DictionaryUnitItemLink, EmbeddedBibliography, EmbeddedConcept, EmbeddedItem, EmbeddedPeriod, EmbeddedPerson, EmbeddedPropertyValue, EmbeddedPropertyVariable, EmbeddedResource, EmbeddedSet, EmbeddedSpatialUnit, EmbeddedText, EmbeddedTree, Event, Gallery, Heading, HeadingItemCategory, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemCategoryWithEmbeddedItems, ItemContainerCategory, ItemLink, ItemLinkCategory, ItemLinks, ItemPayloadKind, ItemProperty, ItemWithoutEmbeddedItems, LanguageCodes, License, Metadata, Note, Observation, OcrString, Period, PeriodItemLink, Person, PersonItemLink, Prettify, Property, PropertyLike, PropertyRelation, PropertyValue, PropertyValueContent, PropertyValueDataType, PropertyValueItemLink, PropertyValueQueryItem, PropertyVariable, PropertyVariableItemLink, Query, QueryGroup, QueryLeaf, QueryablePropertyValueDataType, RecursiveItemCategory, Resource, ResourceItemLink, Section, Set, SetAttributeValueQueryItem, SetBibliography, SetConcept, SetItem, SetItemCategory, SetItemLink, SetItemProperty, SetItemSimplifiedProperty, SetItemsSort, SetItemsSortDirection, SetPeriod, SetResource, SetSpatialUnit, SetTree, SimplifiedProperty, SpatialUnit, SpatialUnitItemLink, Text, TextItemLink, TopLevelItem, Tree, TreeItemCategory, TreeItemLink };
|
package/dist/utilities.d.mts
CHANGED
|
@@ -20,6 +20,30 @@ declare function isPseudoUuid(value: string): boolean;
|
|
|
20
20
|
* @returns The escaped string literal
|
|
21
21
|
*/
|
|
22
22
|
declare function stringLiteral(value: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* XQuery prolog declaring `local:omit-supplemental`, which drops every element
|
|
25
|
+
* carrying `supplemental="true"` from a node sequence, at any depth.
|
|
26
|
+
*
|
|
27
|
+
* Subtrees without a supplemental descendant are returned by reference, so
|
|
28
|
+
* nodes are only copied along the path leading to an omitted element. The
|
|
29
|
+
* lookahead walks the attribute axis (`//@supplemental`) rather than testing
|
|
30
|
+
* every element, which measures around three times faster on large documents.
|
|
31
|
+
*
|
|
32
|
+
* Must be declared before any query body that calls {@link omitSupplemental}.
|
|
33
|
+
*/
|
|
34
|
+
declare const SUPPLEMENTAL_XQUERY_PROLOG = "declare function local:omit-supplemental($nodes as node()*) as node()* {\n for $node in $nodes\n return\n if ($node instance of element())\n then\n if ($node/@supplemental = \"true\")\n then ()\n else if (empty($node//@supplemental[. = \"true\"]))\n then $node\n else element { node-name($node) } {\n $node/@*,\n local:omit-supplemental($node/node())\n }\n else $node\n};";
|
|
35
|
+
/**
|
|
36
|
+
* Wrap an XQuery node expression so supplemental nodes are omitted from it
|
|
37
|
+
* @param expression - The XQuery expression returning the nodes to filter
|
|
38
|
+
* @returns The wrapped XQuery expression
|
|
39
|
+
*/
|
|
40
|
+
declare function omitSupplemental(expression: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* XQuery predicate keeping only nodes that are neither supplemental themselves
|
|
43
|
+
* nor nested inside a supplemental node. Use it when aggregating over nodes
|
|
44
|
+
* instead of returning them.
|
|
45
|
+
*/
|
|
46
|
+
declare const NOT_SUPPLEMENTAL_PREDICATE = "[not(ancestor-or-self::*[@supplemental = \"true\"])]";
|
|
23
47
|
/**
|
|
24
48
|
* Flatten a properties array
|
|
25
49
|
* @param properties - The properties to flatten
|
|
@@ -28,4 +52,4 @@ declare function stringLiteral(value: string): string;
|
|
|
28
52
|
*/
|
|
29
53
|
declare function flattenProperties<T extends LanguageCodes = LanguageCodes>(properties: ReadonlyArray<Property<T> | SetItemProperty<T>>): Array<SetItemProperty<T>>;
|
|
30
54
|
//#endregion
|
|
31
|
-
export { createSchemaValidationError, flattenProperties, getErrorOutput, isPseudoUuid, stringLiteral };
|
|
55
|
+
export { NOT_SUPPLEMENTAL_PREDICATE, SUPPLEMENTAL_XQUERY_PROLOG, createSchemaValidationError, flattenProperties, getErrorOutput, isPseudoUuid, omitSupplemental, stringLiteral };
|
package/dist/utilities.mjs
CHANGED
|
@@ -151,6 +151,46 @@ function stringLiteral(value) {
|
|
|
151
151
|
return `"${value.replaceAll("\"", "\"\"")}"`;
|
|
152
152
|
}
|
|
153
153
|
/**
|
|
154
|
+
* XQuery prolog declaring `local:omit-supplemental`, which drops every element
|
|
155
|
+
* carrying `supplemental="true"` from a node sequence, at any depth.
|
|
156
|
+
*
|
|
157
|
+
* Subtrees without a supplemental descendant are returned by reference, so
|
|
158
|
+
* nodes are only copied along the path leading to an omitted element. The
|
|
159
|
+
* lookahead walks the attribute axis (`//@supplemental`) rather than testing
|
|
160
|
+
* every element, which measures around three times faster on large documents.
|
|
161
|
+
*
|
|
162
|
+
* Must be declared before any query body that calls {@link omitSupplemental}.
|
|
163
|
+
*/
|
|
164
|
+
const SUPPLEMENTAL_XQUERY_PROLOG = `declare function local:omit-supplemental($nodes as node()*) as node()* {
|
|
165
|
+
for $node in $nodes
|
|
166
|
+
return
|
|
167
|
+
if ($node instance of element())
|
|
168
|
+
then
|
|
169
|
+
if ($node/@supplemental = "true")
|
|
170
|
+
then ()
|
|
171
|
+
else if (empty($node//@supplemental[. = "true"]))
|
|
172
|
+
then $node
|
|
173
|
+
else element { node-name($node) } {
|
|
174
|
+
$node/@*,
|
|
175
|
+
local:omit-supplemental($node/node())
|
|
176
|
+
}
|
|
177
|
+
else $node
|
|
178
|
+
};`;
|
|
179
|
+
/**
|
|
180
|
+
* Wrap an XQuery node expression so supplemental nodes are omitted from it
|
|
181
|
+
* @param expression - The XQuery expression returning the nodes to filter
|
|
182
|
+
* @returns The wrapped XQuery expression
|
|
183
|
+
*/
|
|
184
|
+
function omitSupplemental(expression) {
|
|
185
|
+
return `local:omit-supplemental(${expression})`;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* XQuery predicate keeping only nodes that are neither supplemental themselves
|
|
189
|
+
* nor nested inside a supplemental node. Use it when aggregating over nodes
|
|
190
|
+
* instead of returning them.
|
|
191
|
+
*/
|
|
192
|
+
const NOT_SUPPLEMENTAL_PREDICATE = "[not(ancestor-or-self::*[@supplemental = \"true\"])]";
|
|
193
|
+
/**
|
|
154
194
|
* Flatten a properties array
|
|
155
195
|
* @param properties - The properties to flatten
|
|
156
196
|
* @returns The flattened properties
|
|
@@ -169,4 +209,4 @@ function flattenProperties(properties) {
|
|
|
169
209
|
return result;
|
|
170
210
|
}
|
|
171
211
|
//#endregion
|
|
172
|
-
export { createSchemaValidationError, flattenProperties, getErrorOutput, isPseudoUuid, stringLiteral };
|
|
212
|
+
export { NOT_SUPPLEMENTAL_PREDICATE, SUPPLEMENTAL_XQUERY_PROLOG, createSchemaValidationError, flattenProperties, getErrorOutput, isPseudoUuid, omitSupplemental, stringLiteral };
|
package/dist/xml/schemas.d.mts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { XMLData as XMLData$1, XMLDataItem as XMLDataItem$1, XMLGalleryData as XMLGalleryData$1, XMLItemLinksData as XMLItemLinksData$1, XMLLink as XMLLink$1,
|
|
1
|
+
import { XMLData as XMLData$1, XMLDataItem as XMLDataItem$1, XMLGalleryData as XMLGalleryData$1, XMLItemLinksData as XMLItemLinksData$1, XMLLink as XMLLink$1, XMLSetItemsData as XMLSetItemsData$1, XMLWebsiteData as XMLWebsiteData$1 } from "./types.mjs";
|
|
2
2
|
import * as v from "valibot";
|
|
3
3
|
//#region src/xml/schemas.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Schema for validating OCR matches fetched from the OCHRE API
|
|
6
|
-
* @internal
|
|
7
|
-
*/
|
|
8
|
-
declare const XMLOcrMatchesData: v.GenericSchema<unknown, XMLOcrMatchesData$1>;
|
|
9
4
|
declare const XMLLink: v.GenericSchema<unknown, XMLLink$1>;
|
|
10
5
|
declare const XMLDataItem: v.GenericSchema<unknown, XMLDataItem$1>;
|
|
11
6
|
declare const XMLItemLinksData: v.GenericSchema<unknown, XMLItemLinksData$1>;
|
|
@@ -14,4 +9,4 @@ declare const XMLSetItemsData: v.GenericSchema<unknown, XMLSetItemsData$1>;
|
|
|
14
9
|
declare const XMLData: v.GenericSchema<unknown, XMLData$1>;
|
|
15
10
|
declare const XMLWebsiteData: v.GenericSchema<unknown, XMLWebsiteData$1>;
|
|
16
11
|
//#endregion
|
|
17
|
-
export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink,
|
|
12
|
+
export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink, XMLSetItemsData, XMLWebsiteData };
|
package/dist/xml/schemas.mjs
CHANGED
|
@@ -224,42 +224,6 @@ const XMLImageMap = v.object({
|
|
|
224
224
|
width: XMLNumber,
|
|
225
225
|
height: XMLNumber
|
|
226
226
|
}, "XMLImageMap: Shape error");
|
|
227
|
-
const XMLOcrString = v.object({
|
|
228
|
-
HPOS: XMLNumber,
|
|
229
|
-
VPOS: XMLNumber,
|
|
230
|
-
WIDTH: XMLNumber,
|
|
231
|
-
HEIGHT: XMLNumber,
|
|
232
|
-
CONTENT: v.string("XMLOcrString: CONTENT is string and required"),
|
|
233
|
-
VERTICES: v.optional(v.string("XMLOcrString: VERTICES is string and optional"))
|
|
234
|
-
}, "XMLOcrString: Shape error");
|
|
235
|
-
const XMLOcrTextLine = v.object({ string: v.optional(v.array(XMLOcrString, "XMLOcrTextLine: string is array of XMLOcrString")) }, "XMLOcrTextLine: Shape error");
|
|
236
|
-
const XMLOcrTextBlock = v.object({ TextLine: v.optional(v.array(XMLOcrTextLine, "XMLOcrTextBlock: TextLine is array of XMLOcrTextLine")) }, "XMLOcrTextBlock: Shape error");
|
|
237
|
-
const XMLOcrPage = v.object({
|
|
238
|
-
n: XMLOptionalNumber,
|
|
239
|
-
fileName: v.optional(v.string("XMLOcrPage: fileName is string and optional")),
|
|
240
|
-
WIDTH: XMLOptionalNumber,
|
|
241
|
-
HEIGHT: XMLOptionalNumber,
|
|
242
|
-
TextBlock: v.optional(v.array(XMLOcrTextBlock, "XMLOcrPage: TextBlock is array of XMLOcrTextBlock"))
|
|
243
|
-
}, "XMLOcrPage: Shape error");
|
|
244
|
-
const XMLOcr = v.object({ Page: v.optional(v.array(XMLOcrPage, "XMLOcr: Page is array of XMLOcrPage")) }, "XMLOcr: Shape error");
|
|
245
|
-
const XMLOcrMatch = v.object({
|
|
246
|
-
resourceUuid: v.optional(v.string("XMLOcrMatch: resourceUuid is string and optional")),
|
|
247
|
-
n: XMLOptionalNumber,
|
|
248
|
-
fileName: v.optional(v.string("XMLOcrMatch: fileName is string and optional")),
|
|
249
|
-
WIDTH: XMLOptionalNumber,
|
|
250
|
-
HEIGHT: XMLOptionalNumber,
|
|
251
|
-
string: v.optional(v.array(XMLOcrString, "XMLOcrMatch: string is array of XMLOcrString"))
|
|
252
|
-
}, "XMLOcrMatch: Shape error");
|
|
253
|
-
const XMLOcrMatchItem = v.object({
|
|
254
|
-
uuid: v.pipe(v.string("XMLOcrMatchItem: uuid is string and required"), v.check(isPseudoUuid, "XMLOcrMatchItem: uuid is not a valid pseudo-UUID")),
|
|
255
|
-
matchCount: XMLNumber,
|
|
256
|
-
ocrMatch: v.optional(v.array(XMLOcrMatch, "XMLOcrMatchItem: ocrMatch is array of XMLOcrMatch"))
|
|
257
|
-
}, "XMLOcrMatchItem: Shape error");
|
|
258
|
-
/**
|
|
259
|
-
* Schema for validating OCR matches fetched from the OCHRE API
|
|
260
|
-
* @internal
|
|
261
|
-
*/
|
|
262
|
-
const XMLOcrMatchesData = v.object({ result: v.object({ ochre: v.object({ ocrMatches: v.optional(v.object({ ocrItem: v.optional(v.array(XMLOcrMatchItem, "XMLOcrMatchesData: ocrItem is array of XMLOcrMatchItem")) })) }) }) }, "XMLOcrMatchesData: Shape error");
|
|
263
227
|
const XMLNote = v.object({
|
|
264
228
|
content: v.optional(XMLContent.entries.content),
|
|
265
229
|
payload: v.optional(v.string("XMLNote: payload is string and optional")),
|
|
@@ -680,7 +644,6 @@ const XMLResource = v.object({
|
|
|
680
644
|
width: XMLOptionalNumber,
|
|
681
645
|
image: v.optional(XMLImage),
|
|
682
646
|
imagemap: v.optional(XMLImageMap),
|
|
683
|
-
ocr: v.optional(XMLOcr),
|
|
684
647
|
document: v.optional(XMLContent),
|
|
685
648
|
coordinates: v.optional(XMLCoordinates),
|
|
686
649
|
periods: v.optional(v.object({ period: v.array(XMLPeriod) })),
|
|
@@ -832,7 +795,6 @@ const XMLWebsiteResource = v.lazy(() => v.object({
|
|
|
832
795
|
width: XMLOptionalNumber,
|
|
833
796
|
image: v.optional(XMLImage),
|
|
834
797
|
imagemap: v.optional(XMLImageMap),
|
|
835
|
-
ocr: v.optional(XMLOcr),
|
|
836
798
|
document: v.optional(XMLContent),
|
|
837
799
|
coordinates: v.optional(XMLCoordinates),
|
|
838
800
|
periods: v.optional(v.object({ period: v.array(XMLPeriod) })),
|
|
@@ -966,4 +928,4 @@ const XMLWebsiteData = v.object({ result: v.object({ ochre: v.object({
|
|
|
966
928
|
tree: v.array(XMLWebsiteTree)
|
|
967
929
|
}, "XMLWebsiteData: ochre is object with website tree") }, "XMLWebsiteData: result is object with ochre") }, "XMLWebsiteData: Shape error");
|
|
968
930
|
//#endregion
|
|
969
|
-
export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink,
|
|
931
|
+
export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink, XMLSetItemsData, XMLWebsiteData };
|
package/dist/xml/types.d.mts
CHANGED
|
@@ -182,48 +182,6 @@ type XMLImageMap = {
|
|
|
182
182
|
width: XMLNumber;
|
|
183
183
|
height: XMLNumber;
|
|
184
184
|
};
|
|
185
|
-
type XMLOcrString = {
|
|
186
|
-
HPOS: XMLNumber;
|
|
187
|
-
VPOS: XMLNumber;
|
|
188
|
-
WIDTH: XMLNumber;
|
|
189
|
-
HEIGHT: XMLNumber;
|
|
190
|
-
CONTENT: string;
|
|
191
|
-
VERTICES?: string;
|
|
192
|
-
};
|
|
193
|
-
type XMLOcrTextLine = {
|
|
194
|
-
string?: Array<XMLOcrString>;
|
|
195
|
-
};
|
|
196
|
-
type XMLOcrTextBlock = {
|
|
197
|
-
TextLine?: Array<XMLOcrTextLine>;
|
|
198
|
-
};
|
|
199
|
-
type XMLOcrPage = {
|
|
200
|
-
n?: XMLNumber;
|
|
201
|
-
fileName?: string;
|
|
202
|
-
WIDTH?: XMLNumber;
|
|
203
|
-
HEIGHT?: XMLNumber;
|
|
204
|
-
TextBlock?: Array<XMLOcrTextBlock>;
|
|
205
|
-
};
|
|
206
|
-
type XMLOcr = {
|
|
207
|
-
Page?: Array<XMLOcrPage>;
|
|
208
|
-
};
|
|
209
|
-
type XMLOcrMatch = Omit<XMLOcrPage, "TextBlock"> & {
|
|
210
|
-
resourceUuid?: string;
|
|
211
|
-
string?: Array<XMLOcrString>;
|
|
212
|
-
};
|
|
213
|
-
type XMLOcrMatchItem = {
|
|
214
|
-
uuid: string;
|
|
215
|
-
matchCount: XMLNumber;
|
|
216
|
-
ocrMatch?: Array<XMLOcrMatch>;
|
|
217
|
-
};
|
|
218
|
-
type XMLOcrMatchesData = {
|
|
219
|
-
result: {
|
|
220
|
-
ochre: {
|
|
221
|
-
ocrMatches?: {
|
|
222
|
-
ocrItem?: Array<XMLOcrMatchItem>;
|
|
223
|
-
};
|
|
224
|
-
};
|
|
225
|
-
};
|
|
226
|
-
};
|
|
227
185
|
type XMLNote = Partial<XMLContent> & XMLString & {
|
|
228
186
|
noteNo?: XMLNumber;
|
|
229
187
|
title?: string;
|
|
@@ -605,7 +563,6 @@ type XMLResource = XMLBaseItem & {
|
|
|
605
563
|
width?: XMLNumber;
|
|
606
564
|
image?: XMLImage;
|
|
607
565
|
imagemap?: XMLImageMap;
|
|
608
|
-
ocr?: XMLOcr;
|
|
609
566
|
document?: XMLContent;
|
|
610
567
|
coordinates?: XMLCoordinates;
|
|
611
568
|
periods?: {
|
|
@@ -963,4 +920,4 @@ type XMLWebsiteData = {
|
|
|
963
920
|
};
|
|
964
921
|
};
|
|
965
922
|
//#endregion
|
|
966
|
-
export { XMLBaseItem, XMLBibliography, XMLBoolean, XMLConcept, XMLContent, XMLContext, XMLContextGroup, XMLContextItem, XMLContextValue, XMLCoordinate, XMLCoordinates, XMLCoordinatesSource, XMLData, XMLDataItem, XMLDictionaryUnit, XMLEmptyContext, XMLEvent, XMLGallery, XMLGalleryData, XMLHeading, XMLHeadingItemCategory, XMLIdentification, XMLImage, XMLImageMap, XMLImageMapArea, XMLInterpretation, XMLItemCategory, XMLItemLinks, XMLItemLinksData, XMLLicense, XMLLink, XMLLinkedBaseItem, XMLLinkedBibliography, XMLLinkedConcept, XMLLinkedPeriod, XMLLinkedPerson, XMLLinkedPropertyValue, XMLLinkedPropertyVariable, XMLLinkedResource, XMLLinkedSet, XMLLinkedSpatialUnit, XMLLinkedText, XMLLinkedTree, XMLMetadata, XMLNote, XMLNumber, XMLObservation,
|
|
923
|
+
export { XMLBaseItem, XMLBibliography, XMLBoolean, XMLConcept, XMLContent, XMLContext, XMLContextGroup, XMLContextItem, XMLContextValue, XMLCoordinate, XMLCoordinates, XMLCoordinatesSource, XMLData, XMLDataItem, XMLDictionaryUnit, XMLEmptyContext, XMLEvent, XMLGallery, XMLGalleryData, XMLHeading, XMLHeadingItemCategory, XMLIdentification, XMLImage, XMLImageMap, XMLImageMapArea, XMLInterpretation, XMLItemCategory, XMLItemLinks, XMLItemLinksData, XMLLicense, XMLLink, XMLLinkedBaseItem, XMLLinkedBibliography, XMLLinkedConcept, XMLLinkedPeriod, XMLLinkedPerson, XMLLinkedPropertyValue, XMLLinkedPropertyVariable, XMLLinkedResource, XMLLinkedSet, XMLLinkedSpatialUnit, XMLLinkedText, XMLLinkedTree, XMLMetadata, XMLNote, XMLNumber, XMLObservation, XMLPeriod, XMLPerson, XMLProperty, XMLPropertyRelation, XMLPropertyValue, XMLPropertyVariable, XMLRecursiveItemCategory, XMLResource, XMLRichTextEnvelope, XMLSection, XMLSet, XMLSetItems, XMLSetItemsData, XMLSimplifiedProperty, XMLSpatialUnit, XMLString, XMLText, XMLTree, XMLWebsiteContext, XMLWebsiteContextItem, XMLWebsiteContextLevel, XMLWebsiteData, XMLWebsiteFilterContext, XMLWebsiteFilterContextItem, XMLWebsiteOptions, XMLWebsiteProperties, XMLWebsiteResource, XMLWebsiteResourceGroup, XMLWebsiteResourceItem, XMLWebsiteScope, XMLWebsiteSegment, XMLWebsiteStyle, XMLWebsiteTree };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ochre-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.73",
|
|
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",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@antfu/eslint-config": "^9.2.0",
|
|
55
55
|
"@types/node": "^24.13.3",
|
|
56
|
-
"bumpp": "^12.
|
|
56
|
+
"bumpp": "^12.2.0",
|
|
57
57
|
"eslint": "^10.8.0",
|
|
58
58
|
"knip": "^6.31.0",
|
|
59
59
|
"oxfmt": "^0.62.0",
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { OcrMatch } from "../types/index.mjs";
|
|
2
|
-
import { FetchFunction } from "../parsers/helpers.mjs";
|
|
3
|
-
//#region src/fetchers/ocr-matches.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Fetches the locations of OCR text matches within OCHRE resources
|
|
6
|
-
*
|
|
7
|
-
* Matching mirrors the `ocr` Set item query target, so the same value and match
|
|
8
|
-
* mode that selected an item will locate its hits. `matchCountsByUuid` reports
|
|
9
|
-
* the untruncated count, which can exceed the returned matches when
|
|
10
|
-
* `maxMatchesPerItem` caps them.
|
|
11
|
-
*
|
|
12
|
-
* @param parameters - The parameters for the fetch
|
|
13
|
-
* @param parameters.uuids - The resource UUIDs to search, typically from a filtered Set item fetch
|
|
14
|
-
* @param parameters.value - The search value
|
|
15
|
-
* @param parameters.matchMode - Whether to match loosely (stemming and wildcards) or on whole OCR words, defaults to "includes"
|
|
16
|
-
* @param parameters.isCaseSensitive - Whether matching is case sensitive, defaults to false
|
|
17
|
-
* @param parameters.maxMatchesPerItem - The cap on returned matches per requested UUID, defaults to 50
|
|
18
|
-
* @param options - Options for the fetch
|
|
19
|
-
* @param options.fetch - The fetch function to use
|
|
20
|
-
* @returns The OCR matches, or null if the fetch/parse fails
|
|
21
|
-
*/
|
|
22
|
-
declare function fetchOcrMatches(parameters: {
|
|
23
|
-
uuids: Array<string>;
|
|
24
|
-
value: string;
|
|
25
|
-
matchMode?: "includes" | "exact";
|
|
26
|
-
isCaseSensitive?: boolean;
|
|
27
|
-
maxMatchesPerItem?: number;
|
|
28
|
-
}, options?: {
|
|
29
|
-
fetch?: FetchFunction;
|
|
30
|
-
}): Promise<{
|
|
31
|
-
matches: Array<OcrMatch>;
|
|
32
|
-
matchesByUuid: Record<string, Array<OcrMatch>>;
|
|
33
|
-
matchCountsByUuid: Record<string, number>;
|
|
34
|
-
error: null;
|
|
35
|
-
detailedError: null;
|
|
36
|
-
} | {
|
|
37
|
-
matches: null;
|
|
38
|
-
matchesByUuid: null;
|
|
39
|
-
matchCountsByUuid: null;
|
|
40
|
-
error: string;
|
|
41
|
-
detailedError: string;
|
|
42
|
-
}>;
|
|
43
|
-
//#endregion
|
|
44
|
-
export { fetchOcrMatches };
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { XML_PARSER_OPTIONS } from "../constants.mjs";
|
|
2
|
-
import { createSchemaValidationError, getErrorOutput, stringLiteral } from "../utilities.mjs";
|
|
3
|
-
import { buildOcrTermQueryExpressions } from "../query.mjs";
|
|
4
|
-
import { ocrMatchesParametersSchema } from "../schemas.mjs";
|
|
5
|
-
import { restoreXMLMetadata } from "../xml/metadata.mjs";
|
|
6
|
-
import { parseOcrMatches } from "../parsers/index.mjs";
|
|
7
|
-
import { XMLOcrMatchesData } from "../xml/schemas.mjs";
|
|
8
|
-
import * as v from "valibot";
|
|
9
|
-
import { XMLParser } from "fast-xml-parser";
|
|
10
|
-
//#region src/fetchers/ocr-matches.ts
|
|
11
|
-
/**
|
|
12
|
-
* Build an XQuery string to fetch OCR match locations from the OCHRE API
|
|
13
|
-
*
|
|
14
|
-
* Each OCR word is matched with `cts:contains` against the same per-term CTS
|
|
15
|
-
* queries the Set item filter compiles, so hit locations always agree with what
|
|
16
|
-
* the filter matched — including stemming and wildcards, which cannot be
|
|
17
|
-
* reproduced outside MarkLogic.
|
|
18
|
-
*
|
|
19
|
-
* @param parameters - The parameters for the fetch
|
|
20
|
-
* @param parameters.uuids - The resource UUIDs to search
|
|
21
|
-
* @param parameters.termQueryExpressions - One CTS query expression per search term, in word order
|
|
22
|
-
* @param parameters.maxMatchesPerItem - The cap on returned matches per requested UUID
|
|
23
|
-
* @returns An XQuery string
|
|
24
|
-
*/
|
|
25
|
-
function buildXQuery(parameters) {
|
|
26
|
-
const { uuids, termQueryExpressions, maxMatchesPerItem } = parameters;
|
|
27
|
-
return `xquery version "1.0-ml";
|
|
28
|
-
|
|
29
|
-
declare variable $uuids := (${Array.from(uuids, (uuid) => stringLiteral(uuid)).join(", ")});
|
|
30
|
-
|
|
31
|
-
declare variable $termQueries := (
|
|
32
|
-
${termQueryExpressions.join(",\n ")}
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
declare variable $termCount := ${termQueryExpressions.length};
|
|
36
|
-
|
|
37
|
-
<ochre>{
|
|
38
|
-
<ocrMatches>{
|
|
39
|
-
for $uuid in $uuids
|
|
40
|
-
let $matches :=
|
|
41
|
-
for $page in doc($uuid)//ocr/Page
|
|
42
|
-
let $words := $page//TextLine/string
|
|
43
|
-
let $wordCount := count($words)
|
|
44
|
-
let $resourceUuid := string($page/ancestor::resource[1]/@uuid)
|
|
45
|
-
for $word at $index in $words
|
|
46
|
-
where $index + $termCount - 1 le $wordCount
|
|
47
|
-
and (every $offset in (1 to $termCount)
|
|
48
|
-
satisfies cts:contains($words[$index + $offset - 1], $termQueries[$offset]))
|
|
49
|
-
return <ocrMatch resourceUuid="{$resourceUuid}">{
|
|
50
|
-
$page/@n, $page/@fileName, $page/@WIDTH, $page/@HEIGHT,
|
|
51
|
-
subsequence($words, $index, $termCount)
|
|
52
|
-
}</ocrMatch>
|
|
53
|
-
return <ocrItem uuid="{$uuid}" matchCount="{count($matches)}">{
|
|
54
|
-
subsequence($matches, 1, ${maxMatchesPerItem})
|
|
55
|
-
}</ocrItem>
|
|
56
|
-
}</ocrMatches>
|
|
57
|
-
}</ochre>`;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Fetches the locations of OCR text matches within OCHRE resources
|
|
61
|
-
*
|
|
62
|
-
* Matching mirrors the `ocr` Set item query target, so the same value and match
|
|
63
|
-
* mode that selected an item will locate its hits. `matchCountsByUuid` reports
|
|
64
|
-
* the untruncated count, which can exceed the returned matches when
|
|
65
|
-
* `maxMatchesPerItem` caps them.
|
|
66
|
-
*
|
|
67
|
-
* @param parameters - The parameters for the fetch
|
|
68
|
-
* @param parameters.uuids - The resource UUIDs to search, typically from a filtered Set item fetch
|
|
69
|
-
* @param parameters.value - The search value
|
|
70
|
-
* @param parameters.matchMode - Whether to match loosely (stemming and wildcards) or on whole OCR words, defaults to "includes"
|
|
71
|
-
* @param parameters.isCaseSensitive - Whether matching is case sensitive, defaults to false
|
|
72
|
-
* @param parameters.maxMatchesPerItem - The cap on returned matches per requested UUID, defaults to 50
|
|
73
|
-
* @param options - Options for the fetch
|
|
74
|
-
* @param options.fetch - The fetch function to use
|
|
75
|
-
* @returns The OCR matches, or null if the fetch/parse fails
|
|
76
|
-
*/
|
|
77
|
-
async function fetchOcrMatches(parameters, options) {
|
|
78
|
-
try {
|
|
79
|
-
const { uuids, value, matchMode, isCaseSensitive, maxMatchesPerItem } = v.parse(ocrMatchesParametersSchema, parameters);
|
|
80
|
-
const termQueryExpressions = buildOcrTermQueryExpressions({
|
|
81
|
-
value,
|
|
82
|
-
matchMode,
|
|
83
|
-
isCaseSensitive
|
|
84
|
-
});
|
|
85
|
-
if (termQueryExpressions.length === 0) return {
|
|
86
|
-
matches: [],
|
|
87
|
-
matchesByUuid: {},
|
|
88
|
-
matchCountsByUuid: {},
|
|
89
|
-
error: null,
|
|
90
|
-
detailedError: null
|
|
91
|
-
};
|
|
92
|
-
const response = await (options?.fetch ?? fetch)("https://ochre.lib.uchicago.edu/ochre/v2/ochre.php?xquery&xsl=none&lang=\"*\"", {
|
|
93
|
-
method: "POST",
|
|
94
|
-
body: buildXQuery({
|
|
95
|
-
uuids,
|
|
96
|
-
termQueryExpressions,
|
|
97
|
-
maxMatchesPerItem
|
|
98
|
-
}),
|
|
99
|
-
headers: { "Content-Type": "application/xquery" }
|
|
100
|
-
});
|
|
101
|
-
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`, { cause: response.statusText });
|
|
102
|
-
const dataRaw = await response.text();
|
|
103
|
-
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
104
|
-
const { success, issues, output } = v.safeParse(XMLOcrMatchesData, data);
|
|
105
|
-
if (!success) throw createSchemaValidationError("Failed to parse OCHRE OCR matches", issues);
|
|
106
|
-
restoreXMLMetadata(output, data);
|
|
107
|
-
const rawOcrItems = output.result.ochre.ocrMatches?.ocrItem ?? [];
|
|
108
|
-
const matches = parseOcrMatches(rawOcrItems);
|
|
109
|
-
const matchesByUuid = {};
|
|
110
|
-
const matchCountsByUuid = {};
|
|
111
|
-
for (const uuid of uuids) {
|
|
112
|
-
matchesByUuid[uuid] = [];
|
|
113
|
-
matchCountsByUuid[uuid] = 0;
|
|
114
|
-
}
|
|
115
|
-
for (const rawOcrItem of rawOcrItems) matchCountsByUuid[rawOcrItem.uuid] = rawOcrItem.matchCount;
|
|
116
|
-
for (const match of matches) matchesByUuid[match.uuid]?.push(match);
|
|
117
|
-
return {
|
|
118
|
-
matches,
|
|
119
|
-
matchesByUuid,
|
|
120
|
-
matchCountsByUuid,
|
|
121
|
-
error: null,
|
|
122
|
-
detailedError: null
|
|
123
|
-
};
|
|
124
|
-
} catch (error) {
|
|
125
|
-
return {
|
|
126
|
-
matches: null,
|
|
127
|
-
matchesByUuid: null,
|
|
128
|
-
matchCountsByUuid: null,
|
|
129
|
-
...getErrorOutput(error, "Unknown error")
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
//#endregion
|
|
134
|
-
export { fetchOcrMatches };
|