ochre-sdk 1.0.70 → 1.0.71

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.
@@ -33,6 +33,8 @@ const XML_ARRAY_TAGS = [
33
33
  "Page",
34
34
  "TextBlock",
35
35
  "TextLine",
36
+ "ocrItem",
37
+ "ocrMatch",
36
38
  "footnote",
37
39
  "language",
38
40
  "section",
@@ -0,0 +1,44 @@
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 };
@@ -0,0 +1,134 @@
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 };
@@ -1,10 +1,10 @@
1
1
  import { BELONGS_TO_COLLECTION_UUID, DEFAULT_LANGUAGES, XML_PARSER_OPTIONS } from "../../constants.mjs";
2
2
  import { createSchemaValidationError, getErrorOutput, stringLiteral } from "../../utilities.mjs";
3
+ import { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan } from "../../query.mjs";
3
4
  import { iso639_3Schema, setItemsParametersSchema } from "../../schemas.mjs";
4
5
  import { restoreXMLMetadata } from "../../xml/metadata.mjs";
5
6
  import { parseSetItems } from "../../parsers/index.mjs";
6
7
  import { XMLSetItemsData } from "../../xml/schemas.mjs";
7
- import { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan } from "../../query.mjs";
8
8
  import * as v from "valibot";
9
9
  import { XMLParser } from "fast-xml-parser";
10
10
  //#region src/fetchers/set/items.ts
@@ -138,8 +138,8 @@ function buildXQuery(parameters) {
138
138
  const { queries, sort, setScopeUuids, belongsToCollectionScopeUuids, page, pageSize } = parameters;
139
139
  const startPosition = (page - 1) * pageSize + 1;
140
140
  const setScopeDeclaration = `declare variable $setScopeUuids := (${setScopeUuids.map((uuid) => stringLiteral(uuid)).join(", ")});`;
141
- const baseItemsExpression = "doc()/ochre/set[@uuid = $setScopeUuids]/items/*";
142
141
  const compiledQueryPlan = buildQueryPlan({ queries });
142
+ const baseItemsExpression = `doc()/ochre/set[@uuid = $setScopeUuids]/items/*${compiledQueryPlan.itemPredicates}`;
143
143
  const itemsQueryExpressions = [];
144
144
  const belongsToCollectionQueryExpression = buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids, BELONGS_TO_COLLECTION_UUID);
145
145
  if (compiledQueryPlan.queryExpression != null) itemsQueryExpressions.push(compiledQueryPlan.queryExpression);
@@ -148,8 +148,10 @@ function buildXQuery(parameters) {
148
148
  const orderedItemsClause = buildOrderedItemsClause(sort);
149
149
  const xqueryDeclarations = ["xquery version \"1.0-ml\";", setScopeDeclaration];
150
150
  if (compiledQueryPlan.prolog !== "") xqueryDeclarations.push(compiledQueryPlan.prolog);
151
- const itemsClause = itemsQueryExpression == null ? `let $items := ${baseItemsExpression}` : `let $query := ${itemsQueryExpression}
152
- let $items := cts:search(${baseItemsExpression}, $query)`;
151
+ const letClauses = Array.from(compiledQueryPlan.ocrBindings, (binding) => `let ${binding.name} := ${binding.expression}`);
152
+ if (itemsQueryExpression == null) letClauses.push(`let $items := ${baseItemsExpression}`);
153
+ else letClauses.push(`let $query := ${itemsQueryExpression}`, `let $items := cts:search(${baseItemsExpression}, $query)`);
154
+ const itemsClause = letClauses.join("\n ");
153
155
  return `${xqueryDeclarations.join("\n\n")}
154
156
 
155
157
  <ochre>{
@@ -1,9 +1,9 @@
1
1
  import { BELONGS_TO_COLLECTION_UUID, DEFAULT_LANGUAGES, XML_PARSER_OPTIONS } from "../../constants.mjs";
2
2
  import { createSchemaValidationError, getErrorOutput, stringLiteral } from "../../utilities.mjs";
3
3
  import { MultilingualString } from "../../parsers/multilingual.mjs";
4
+ import { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan } from "../../query.mjs";
4
5
  import { setPropertyValuesParametersSchema } from "../../schemas.mjs";
5
6
  import { parseXMLContent } from "../../parsers/string.mjs";
6
- import { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan } from "../../query.mjs";
7
7
  import * as v from "valibot";
8
8
  import { XMLParser } from "fast-xml-parser";
9
9
  //#region src/fetchers/set/property-values.ts
@@ -190,8 +190,8 @@ const responseSchema = v.object({ result: v.object({ ochre: v.object({
190
190
  function buildXQuery(parameters) {
191
191
  const { setScopeUuids, belongsToCollectionScopeUuids, queries, propertyFacetSelectors, attributes, isLimitedToLeafPropertyValues } = parameters;
192
192
  const setScopeDeclaration = `declare variable $setScopeUuids := (${setScopeUuids.map((uuid) => stringLiteral(uuid)).join(", ")});`;
193
- const baseItemsExpression = "doc()/ochre/set[@uuid = $setScopeUuids]/items/*";
194
193
  const compiledQueryPlan = buildQueryPlan({ queries: getItemFilterQueriesFromPropertyValueQueries(queries) });
194
+ const baseItemsExpression = `doc()/ochre/set[@uuid = $setScopeUuids]/items/*${compiledQueryPlan.itemPredicates}`;
195
195
  const itemsQueryExpressions = [];
196
196
  const belongsToCollectionQueryExpression = buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids, BELONGS_TO_COLLECTION_UUID);
197
197
  if (compiledQueryPlan.queryExpression != null) itemsQueryExpressions.push(compiledQueryPlan.queryExpression);
@@ -404,8 +404,10 @@ let $period-values :=
404
404
  )`);
405
405
  returnedSequences.push("$period-values");
406
406
  }
407
- const itemsClause = itemsQueryExpression == null ? `let $items := ${baseItemsExpression}` : `let $query := ${itemsQueryExpression}
408
- let $items := cts:search(${baseItemsExpression}, $query)`;
407
+ const letClauses = Array.from(compiledQueryPlan.ocrBindings, (binding) => `let ${binding.name} := ${binding.expression}`);
408
+ if (itemsQueryExpression == null) letClauses.push(`let $items := ${baseItemsExpression}`);
409
+ else letClauses.push(`let $query := ${itemsQueryExpression}`, `let $items := cts:search(${baseItemsExpression}, $query)`);
410
+ const itemsClause = letClauses.join("\n ");
409
411
  return `${xqueryDeclarations.join("\n\n")}
410
412
 
411
413
  <ochre>{
@@ -7,6 +7,10 @@ type FlattenedItem<U, T extends LanguageCodes> = Omit<U, "properties"> & {
7
7
  * The default page size to use for fetching paginated items
8
8
  */
9
9
  declare const DEFAULT_PAGE_SIZE = 48;
10
+ /**
11
+ * The default cap on OCR matches returned per requested item
12
+ */
13
+ declare const DEFAULT_MAX_OCR_MATCHES_PER_ITEM = 50;
10
14
  /**
11
15
  * Flatten the properties of an item
12
16
  * @param item - The item whose properties to flatten
@@ -14,4 +18,4 @@ declare const DEFAULT_PAGE_SIZE = 48;
14
18
  */
15
19
  declare function flattenItemProperties<U extends ItemCategory = ItemCategory, V extends ContainedItemCategory<U> = ContainedItemCategory<U>, T extends LanguageCodes = LanguageCodes, W extends ItemPayloadKind = "topLevel">(item: Item<U, V, T, W>): FlattenedItem<Item<U, V, T, W>, T>;
16
20
  //#endregion
17
- export { DEFAULT_PAGE_SIZE, flattenItemProperties };
21
+ export { DEFAULT_MAX_OCR_MATCHES_PER_ITEM, DEFAULT_PAGE_SIZE, flattenItemProperties };
package/dist/helpers.mjs CHANGED
@@ -5,6 +5,10 @@ import { flattenProperties } from "./utilities.mjs";
5
5
  */
6
6
  const DEFAULT_PAGE_SIZE = 48;
7
7
  /**
8
+ * The default cap on OCR matches returned per requested item
9
+ */
10
+ const DEFAULT_MAX_OCR_MATCHES_PER_ITEM = 50;
11
+ /**
8
12
  * Flatten the properties of an item
9
13
  * @param item - The item whose properties to flatten
10
14
  * @returns The item with the properties flattened
@@ -30,4 +34,4 @@ function flattenItemProperties(item) {
30
34
  };
31
35
  }
32
36
  //#endregion
33
- export { DEFAULT_PAGE_SIZE, flattenItemProperties };
37
+ export { DEFAULT_MAX_OCR_MATCHES_PER_ITEM, DEFAULT_PAGE_SIZE, flattenItemProperties };
package/dist/index.d.mts CHANGED
@@ -1,14 +1,15 @@
1
1
  import { MultilingualOptions, MultilingualString, MultilingualStringEntries, MultilingualStringEntry, MultilingualStringInput, MultilingualStringJSON, MultilingualStringObject, MultilingualStringText } from "./parsers/multilingual.mjs";
2
2
  import { AccordionWebBlock, ContextTree, ContextTreeFilterLevel, ContextTreeLevel, ContextTreeLevelItem, ProtectedWebsite, Scope, Style, StylesheetCategory, StylesheetItem, WebAccordionItem, WebBlock, WebBlockByLayout, WebBlockItem, WebBlockLayout, WebElement, WebElementComponent, WebElementComponentName, WebElementComponentOf, WebElementOf, WebImage, WebSidebar, WebTitle, Webpage, Website, WebsiteMetadata, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteSegment, WebsiteType } from "./types/website.mjs";
3
- import { 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, OcrPage, OcrPoint, OcrTextBlock, OcrTextLine, OcrWord, 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 } from "./types/index.mjs";
3
+ import { 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, OcrMatch, OcrPage, OcrPoint, OcrTextBlock, OcrTextLine, OcrWord, 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 } from "./types/index.mjs";
4
4
  import { fetchGallery } from "./fetchers/gallery.mjs";
5
5
  import { fetchItemChildren } from "./fetchers/item-children.mjs";
6
6
  import { fetchItemLinks } from "./fetchers/item-links.mjs";
7
7
  import { defineLanguages, fetchItem, withLanguages } from "./fetchers/item.mjs";
8
+ import { fetchOcrMatches } from "./fetchers/ocr-matches.mjs";
8
9
  import { fetchSetItems } from "./fetchers/set/items.mjs";
9
10
  import { fetchSetPropertyValues } from "./fetchers/set/property-values.mjs";
10
11
  import { fetchWebsiteMetadata } from "./fetchers/website-metadata.mjs";
11
12
  import { fetchWebsite } from "./fetchers/website.mjs";
12
13
  import { PropertyOptions, filterProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels } from "./getters.mjs";
13
- import { DEFAULT_PAGE_SIZE, flattenItemProperties } from "./helpers.mjs";
14
- export { type AccordionWebBlock, type AnyBibliography, type AnyConcept, type AnyItem, type AnyPeriod, type AnyPerson, type AnyPropertyValue, type AnyPropertyVariable, type AnyResource, type AnySet, type AnySpatialUnit, type AnyText, type AnyTree, type BaseItem, type BaseItemLink, type BelongsTo, type Bibliography, type BibliographyEntryInfo, type BibliographyItemLink, type BibliographySourceDocument, type Concept, type ConceptItemLink, type ContainedItemCategory, type ContainedItemCategoryFromOption, type ContainedItemCategoryOption, type Context, type ContextItem, type ContextItemCategory, type ContextNode, type ContextTree, type ContextTreeFilterLevel, type ContextTreeLevel, type ContextTreeLevelItem, type Coordinates, type CoordinatesSource, DEFAULT_PAGE_SIZE, type DictionaryUnitItemLink, type EmbeddedBibliography, type EmbeddedConcept, type EmbeddedItem, type EmbeddedPeriod, type EmbeddedPerson, type EmbeddedPropertyValue, type EmbeddedPropertyVariable, type EmbeddedResource, type EmbeddedSet, type EmbeddedSpatialUnit, type EmbeddedText, type EmbeddedTree, type Event, type Gallery, type Heading, type HeadingItemCategory, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type Item, type ItemCategory, type ItemCategoryFromOption, type ItemCategoryOption, type ItemCategoryWithEmbeddedItems, type ItemContainerCategory, type ItemLink, type ItemLinkCategory, type ItemLinks, type ItemPayloadKind, type ItemProperty, type ItemWithoutEmbeddedItems, type LanguageCodes, type License, type Metadata, type MultilingualOptions, MultilingualString, type MultilingualStringEntries, type MultilingualStringEntry, type MultilingualStringInput, type MultilingualStringJSON, type MultilingualStringObject, type MultilingualStringText, type Note, type Observation, type OcrPage, type OcrPoint, type OcrTextBlock, type OcrTextLine, type OcrWord, type Period, type PeriodItemLink, type Person, type PersonItemLink, type Prettify, type Property, type PropertyLike, PropertyOptions, type PropertyRelation, type PropertyValue, type PropertyValueContent, type PropertyValueDataType, type PropertyValueItemLink, type PropertyValueQueryItem, type PropertyVariable, type PropertyVariableItemLink, type ProtectedWebsite, type Query, type QueryGroup, type QueryLeaf, type QueryablePropertyValueDataType, type RecursiveItemCategory, type Resource, type ResourceItemLink, type Scope, type Section, type Set, type SetAttributeValueQueryItem, type SetBibliography, type SetConcept, type SetItem, type SetItemCategory, type SetItemLink, type SetItemProperty, type SetItemSimplifiedProperty, type SetItemsSort, type SetItemsSortDirection, type SetPeriod, type SetResource, type SetSpatialUnit, type SetTree, type SimplifiedProperty, type SpatialUnit, type SpatialUnitItemLink, type Style, type StylesheetCategory, type StylesheetItem, type Text, type TextItemLink, type TopLevelItem, type Tree, type TreeItemCategory, type TreeItemLink, type WebAccordionItem, type WebBlock, type WebBlockByLayout, type WebBlockItem, type WebBlockLayout, type WebElement, type WebElementComponent, type WebElementComponentName, type WebElementComponentOf, type WebElementOf, type WebImage, type WebSidebar, type WebTitle, type Webpage, type Website, type WebsiteMetadata, type WebsitePropertyQuery, type WebsitePropertyQueryNode, type WebsiteSegment, type WebsiteType, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchSetItems, fetchSetPropertyValues, fetchWebsite, fetchWebsiteMetadata, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels, withLanguages };
14
+ import { DEFAULT_MAX_OCR_MATCHES_PER_ITEM, DEFAULT_PAGE_SIZE, flattenItemProperties } from "./helpers.mjs";
15
+ export { type AccordionWebBlock, type AnyBibliography, type AnyConcept, type AnyItem, type AnyPeriod, type AnyPerson, type AnyPropertyValue, type AnyPropertyVariable, type AnyResource, type AnySet, type AnySpatialUnit, type AnyText, type AnyTree, type BaseItem, type BaseItemLink, type BelongsTo, type Bibliography, type BibliographyEntryInfo, type BibliographyItemLink, type BibliographySourceDocument, type Concept, type ConceptItemLink, type ContainedItemCategory, type ContainedItemCategoryFromOption, type ContainedItemCategoryOption, type Context, type ContextItem, type ContextItemCategory, type ContextNode, type ContextTree, type ContextTreeFilterLevel, type ContextTreeLevel, type ContextTreeLevelItem, type Coordinates, type CoordinatesSource, DEFAULT_MAX_OCR_MATCHES_PER_ITEM, DEFAULT_PAGE_SIZE, type DictionaryUnitItemLink, type EmbeddedBibliography, type EmbeddedConcept, type EmbeddedItem, type EmbeddedPeriod, type EmbeddedPerson, type EmbeddedPropertyValue, type EmbeddedPropertyVariable, type EmbeddedResource, type EmbeddedSet, type EmbeddedSpatialUnit, type EmbeddedText, type EmbeddedTree, type Event, type Gallery, type Heading, type HeadingItemCategory, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type Item, type ItemCategory, type ItemCategoryFromOption, type ItemCategoryOption, type ItemCategoryWithEmbeddedItems, type ItemContainerCategory, type ItemLink, type ItemLinkCategory, type ItemLinks, type ItemPayloadKind, type ItemProperty, type ItemWithoutEmbeddedItems, type LanguageCodes, type License, type Metadata, type MultilingualOptions, MultilingualString, type MultilingualStringEntries, type MultilingualStringEntry, type MultilingualStringInput, type MultilingualStringJSON, type MultilingualStringObject, type MultilingualStringText, type Note, type Observation, type OcrMatch, type OcrPage, type OcrPoint, type OcrTextBlock, type OcrTextLine, type OcrWord, type Period, type PeriodItemLink, type Person, type PersonItemLink, type Prettify, type Property, type PropertyLike, PropertyOptions, type PropertyRelation, type PropertyValue, type PropertyValueContent, type PropertyValueDataType, type PropertyValueItemLink, type PropertyValueQueryItem, type PropertyVariable, type PropertyVariableItemLink, type ProtectedWebsite, type Query, type QueryGroup, type QueryLeaf, type QueryablePropertyValueDataType, type RecursiveItemCategory, type Resource, type ResourceItemLink, type Scope, type Section, type Set, type SetAttributeValueQueryItem, type SetBibliography, type SetConcept, type SetItem, type SetItemCategory, type SetItemLink, type SetItemProperty, type SetItemSimplifiedProperty, type SetItemsSort, type SetItemsSortDirection, type SetPeriod, type SetResource, type SetSpatialUnit, type SetTree, type SimplifiedProperty, type SpatialUnit, type SpatialUnitItemLink, type Style, type StylesheetCategory, type StylesheetItem, type Text, type TextItemLink, type TopLevelItem, type Tree, type TreeItemCategory, type TreeItemLink, type WebAccordionItem, type WebBlock, type WebBlockByLayout, type WebBlockItem, type WebBlockLayout, type WebElement, type WebElementComponent, type WebElementComponentName, type WebElementComponentOf, type WebElementOf, type WebImage, type WebSidebar, type WebTitle, type Webpage, type Website, type WebsiteMetadata, type WebsitePropertyQuery, type WebsitePropertyQueryNode, type WebsiteSegment, type WebsiteType, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchOcrMatches, fetchSetItems, fetchSetPropertyValues, fetchWebsite, fetchWebsiteMetadata, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels, withLanguages };
package/dist/index.mjs CHANGED
@@ -1,12 +1,13 @@
1
1
  import { filterProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels } from "./getters.mjs";
2
- import { DEFAULT_PAGE_SIZE, flattenItemProperties } from "./helpers.mjs";
2
+ import { DEFAULT_MAX_OCR_MATCHES_PER_ITEM, DEFAULT_PAGE_SIZE, flattenItemProperties } from "./helpers.mjs";
3
3
  import { MultilingualString } from "./parsers/multilingual.mjs";
4
4
  import { fetchGallery } from "./fetchers/gallery.mjs";
5
5
  import { fetchItemChildren } from "./fetchers/item-children.mjs";
6
6
  import { fetchItemLinks } from "./fetchers/item-links.mjs";
7
7
  import { defineLanguages, fetchItem, withLanguages } from "./fetchers/item.mjs";
8
+ import { fetchOcrMatches } from "./fetchers/ocr-matches.mjs";
8
9
  import { fetchSetItems } from "./fetchers/set/items.mjs";
9
10
  import { fetchSetPropertyValues } from "./fetchers/set/property-values.mjs";
10
11
  import { fetchWebsiteMetadata } from "./fetchers/website-metadata.mjs";
11
12
  import { fetchWebsite } from "./fetchers/website.mjs";
12
- export { DEFAULT_PAGE_SIZE, MultilingualString, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchSetItems, fetchSetPropertyValues, fetchWebsite, fetchWebsiteMetadata, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels, withLanguages };
13
+ export { DEFAULT_MAX_OCR_MATCHES_PER_ITEM, DEFAULT_PAGE_SIZE, MultilingualString, defineLanguages, fetchGallery, fetchItem, fetchItemChildren, fetchItemLinks, fetchOcrMatches, fetchSetItems, fetchSetPropertyValues, fetchWebsite, fetchWebsiteMetadata, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByVariableLabel, getPropertyByVariableLabelAndValue, getPropertyByVariableLabelAndValueContent, getPropertyByVariableLabelAndValueContents, getPropertyByVariableLabelAndValues, getPropertyByVariableUuid, getPropertyValueByVariableLabel, getPropertyValueByVariableUuid, getPropertyValueContentByVariableLabel, getPropertyValueContentByVariableUuid, getPropertyValueContentsByVariableUuid, getPropertyValuesByVariableLabel, getPropertyValuesByVariableUuid, getUniqueProperties, getUniquePropertyVariableLabels, withLanguages };
@@ -1,12 +1,19 @@
1
1
  import { Webpage } from "../types/website.mjs";
2
- import { Bibliography, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Gallery, Identification, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemContainerCategory, ItemLinks, Metadata, Note, Person, Property, Resource, SetItem, SetItemCategory, SimplifiedProperty } from "../types/index.mjs";
3
- import { XMLBibliography, XMLData, XMLDataItem, XMLGalleryData, XMLIdentification, XMLItemLinks, XMLLink, XMLMetadata, XMLNote, XMLPerson, XMLProperty, XMLResource, XMLSetItems, XMLSimplifiedProperty } from "../xml/types.mjs";
2
+ import { Bibliography, ContainedItemCategoryFromOption, ContainedItemCategoryOption, Gallery, Identification, Item, ItemCategory, ItemCategoryFromOption, ItemCategoryOption, ItemContainerCategory, ItemLinks, Metadata, Note, OcrMatch, Person, Property, Resource, SetItem, SetItemCategory, SimplifiedProperty } from "../types/index.mjs";
3
+ import { XMLBibliography, XMLData, XMLDataItem, XMLGalleryData, XMLIdentification, XMLItemLinks, XMLLink, XMLMetadata, XMLNote, XMLOcrMatchItem, XMLPerson, XMLProperty, XMLResource, XMLSetItems, XMLSimplifiedProperty } from "../xml/types.mjs";
4
4
  import { ParserOptions, getParserOptions, parseStringLike } from "./helpers.mjs";
5
5
  //#region src/parsers/index.d.ts
6
6
  type RawOchre = XMLData["result"]["ochre"];
7
7
  type ResourceViewParser<T extends ReadonlyArray<string>> = (view: XMLResource["view"], context: Pick<Resource<T, "topLevel">, "belongsTo" | "metadata">) => Webpage<T> | null;
8
8
  type SetItemCategoryFromCategories<T extends ReadonlyArray<SetItemCategory> | undefined> = T extends ReadonlyArray<infer U> ? Extract<U, SetItemCategory> : SetItemCategory;
9
9
  declare function parseIdentification<T extends ReadonlyArray<string>>(rawIdentification: XMLIdentification, options: ParserOptions<T>): Identification<T>;
10
+ /**
11
+ * Parse OCR matches returned by the OCHRE API
12
+ * @param rawOcrItems - The raw OCR match items
13
+ * @returns The parsed OCR matches, in request order
14
+ * @internal
15
+ */
16
+ declare function parseOcrMatches(rawOcrItems: Array<XMLOcrMatchItem>): Array<OcrMatch>;
10
17
  declare function parseNotes<T extends ReadonlyArray<string>>(rawNotes: {
11
18
  note: Array<XMLNote>;
12
19
  } | undefined, options: ParserOptions<T>): Array<Note<T>>;
@@ -61,4 +68,4 @@ declare function parseItem(rawData: XMLData, options: {
61
68
  parseResourceView?: ResourceViewParser<ReadonlyArray<string>>;
62
69
  }): Item<ItemCategory, SetItemCategory, ReadonlyArray<string>>;
63
70
  //#endregion
64
- export { type ParserOptions, RawOchre, getParserOptions, parseBibliographyList, parseGallery, parseIdentification, parseItem, parseLinkedItems, parseLinks, parseMetadata, parseMetadataLanguages, parseNotes, parsePersonList, parseProperties, parseSetItems, parseSimplifiedProperties, parseStringLike, resolveDefaultLanguage, resolveLanguages };
71
+ export { type ParserOptions, RawOchre, getParserOptions, parseBibliographyList, parseGallery, parseIdentification, parseItem, parseLinkedItems, parseLinks, parseMetadata, parseMetadataLanguages, parseNotes, parseOcrMatches, parsePersonList, parseProperties, parseSetItems, parseSimplifiedProperties, parseStringLike, resolveDefaultLanguage, resolveLanguages };
@@ -443,18 +443,24 @@ function parseOcrVertices(rawVertices) {
443
443
  }
444
444
  return vertices;
445
445
  }
446
+ function parseOcrWords(rawWords) {
447
+ return Array.from(rawWords ?? [], (rawWord) => ({
448
+ content: rawWord.CONTENT,
449
+ x: rawWord.HPOS,
450
+ y: rawWord.VPOS,
451
+ width: rawWord.WIDTH,
452
+ height: rawWord.HEIGHT,
453
+ vertices: parseOcrVertices(rawWord.VERTICES)
454
+ }));
455
+ }
456
+ function joinOcrWordContents(words) {
457
+ return Array.from(words, (word) => word.content).join(" ");
458
+ }
446
459
  function parseOcrPage(rawPage) {
447
460
  const blocks = Array.from(rawPage.TextBlock ?? [], (rawBlock) => ({ lines: Array.from(rawBlock.TextLine ?? [], (rawLine) => {
448
- const words = Array.from(rawLine.string ?? [], (rawWord) => ({
449
- content: rawWord.CONTENT,
450
- x: rawWord.HPOS,
451
- y: rawWord.VPOS,
452
- width: rawWord.WIDTH,
453
- height: rawWord.HEIGHT,
454
- vertices: parseOcrVertices(rawWord.VERTICES)
455
- }));
461
+ const words = parseOcrWords(rawLine.string);
456
462
  return {
457
- content: Array.from(words, (word) => word.content).join(" "),
463
+ content: joinOcrWordContents(words),
458
464
  words
459
465
  };
460
466
  }) }));
@@ -469,6 +475,34 @@ function parseOcrPage(rawPage) {
469
475
  function parseOcr(rawOcr) {
470
476
  return Array.from(rawOcr?.Page ?? [], (rawPage) => parseOcrPage(rawPage));
471
477
  }
478
+ /**
479
+ * Parse OCR matches returned by the OCHRE API
480
+ * @param rawOcrItems - The raw OCR match items
481
+ * @returns The parsed OCR matches, in request order
482
+ * @internal
483
+ */
484
+ function parseOcrMatches(rawOcrItems) {
485
+ const matches = [];
486
+ for (const rawOcrItem of rawOcrItems) {
487
+ const rawMatches = rawOcrItem.ocrMatch ?? [];
488
+ for (const rawMatch of rawMatches) {
489
+ const words = parseOcrWords(rawMatch.string);
490
+ matches.push({
491
+ uuid: rawOcrItem.uuid,
492
+ resourceUuid: rawMatch.resourceUuid ?? null,
493
+ page: {
494
+ number: rawMatch.n ?? null,
495
+ fileName: rawMatch.fileName ?? null,
496
+ width: rawMatch.WIDTH ?? null,
497
+ height: rawMatch.HEIGHT ?? null
498
+ },
499
+ content: joinOcrWordContents(words),
500
+ words
501
+ });
502
+ }
503
+ }
504
+ return matches;
505
+ }
472
506
  function parseNote(rawNote, options) {
473
507
  const authors = Array.from(rawNote.authors?.author ?? [], (author) => parsePerson(author, options));
474
508
  const content = rawNote.content == null ? multilingualFromText(parseXMLString(rawNote), options) : parseRequiredContentLike(rawNote, options);
@@ -1365,4 +1399,4 @@ function parseItem(rawData, options) {
1365
1399
  };
1366
1400
  }
1367
1401
  //#endregion
1368
- export { getParserOptions, parseBibliographyList, parseGallery, parseIdentification, parseItem, parseLinkedItems, parseLinks, parseMetadata, parseMetadataLanguages, parseNotes, parsePersonList, parseProperties, parseSetItems, parseSimplifiedProperties, parseStringLike, resolveDefaultLanguage, resolveLanguages };
1402
+ export { getParserOptions, parseBibliographyList, parseGallery, parseIdentification, parseItem, parseLinkedItems, parseLinks, parseMetadata, parseMetadataLanguages, parseNotes, parseOcrMatches, parsePersonList, parseProperties, parseSetItems, parseSimplifiedProperties, parseStringLike, resolveDefaultLanguage, resolveLanguages };
package/dist/query.d.mts CHANGED
@@ -1,12 +1,40 @@
1
1
  import { Query } from "./types/index.mjs";
2
2
  //#region src/query.d.ts
3
+ /**
4
+ * Error message for OCR queries nested inside an OR group
5
+ * @internal
6
+ */
7
+ declare const OCR_DISJUNCTION_ERROR_MESSAGE = "OCR queries cannot be nested inside an OR group because they are resolved by a document join instead of a CTS query";
8
+ type OcrUuidBinding = {
9
+ name: string;
10
+ expression: string;
11
+ };
3
12
  declare function buildAndCtsQueryExpression(queryExpressions: Array<string>): string | null;
13
+ /**
14
+ * Compile one CTS query expression per OCR search term, in word order
15
+ *
16
+ * Highlighting matches each OCR word against these same per-term expressions,
17
+ * so hit locations always agree with what the filter matched.
18
+ * @internal
19
+ */
20
+ declare function buildOcrTermQueryExpressions(parameters: {
21
+ value: string;
22
+ matchMode: "includes" | "exact";
23
+ isCaseSensitive: boolean;
24
+ }): Array<string>;
25
+ /**
26
+ * Whether a query tree nests an OCR leaf inside an OR group
27
+ * @internal
28
+ */
29
+ declare function hasOcrQueryInDisjunction(query: Query, isInDisjunction?: boolean): boolean;
4
30
  declare function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids: Array<string>, belongsToCollectionPropertyVariableUuid: string): string | null;
5
31
  declare function buildQueryPlan(parameters: {
6
32
  queries: Query | null;
7
33
  }): {
8
34
  prolog: string;
9
35
  queryExpression: string | null;
36
+ ocrBindings: Array<OcrUuidBinding>;
37
+ itemPredicates: string;
10
38
  };
11
39
  //#endregion
12
- export { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan };
40
+ export { OCR_DISJUNCTION_ERROR_MESSAGE, buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildOcrTermQueryExpressions, buildQueryPlan, hasOcrQueryInDisjunction };
package/dist/query.mjs CHANGED
@@ -12,6 +12,11 @@ const CTS_INCLUDES_STOP_WORDS = /* @__PURE__ */ new Set([
12
12
  const CTS_INCLUDES_TOKEN_WORD_REGEX = /^\p{L}+$/u;
13
13
  const CTS_INCLUDES_TOKEN_REGEX = /[\p{L}\p{N}*?]+/gu;
14
14
  const CTS_EXACT_TEXT_TOKEN_REGEX = /[\p{L}\p{N}]+/gu;
15
+ /**
16
+ * Error message for OCR queries nested inside an OR group
17
+ * @internal
18
+ */
19
+ const OCR_DISJUNCTION_ERROR_MESSAGE = "OCR queries cannot be nested inside an OR group because they are resolved by a document join instead of a CTS query";
15
20
  const CONTENT_TARGET_CONTENT_ELEMENT_PATHS = {
16
21
  title: [
17
22
  "identification",
@@ -199,6 +204,9 @@ function buildNestedElementQuery(elementNames, queryExpression) {
199
204
  function buildNotCtsQueryExpression(queryExpression) {
200
205
  return `cts:not-query(${queryExpression})`;
201
206
  }
207
+ function buildCtsNearQueryExpression(queryExpressions) {
208
+ return `cts:near-query((${queryExpressions.join(", ")}), ${queryExpressions.length - 1}, ("ordered"))`;
209
+ }
202
210
  function buildAndCtsQueryExpressionInternal(queryExpressions) {
203
211
  if (queryExpressions.length === 0) return "cts:true-query()";
204
212
  if (queryExpressions.length === 1) return queryExpressions[0] ?? "cts:true-query()";
@@ -472,6 +480,63 @@ function buildItemStringQueryExpression(parameters) {
472
480
  language
473
481
  })]);
474
482
  }
483
+ function tokenizeOcrSearchValue(parameters) {
484
+ const { value, matchMode, isCaseSensitive } = parameters;
485
+ const rawTerms = (isCaseSensitive ? value : value.toLowerCase()).match(matchMode === "exact" ? CTS_EXACT_TEXT_TOKEN_REGEX : CTS_INCLUDES_TOKEN_REGEX) ?? [];
486
+ const terms = [];
487
+ for (const term of rawTerms) if (getWildcardStrippedValue(term) !== "") terms.push(term);
488
+ return terms;
489
+ }
490
+ /**
491
+ * Compile one CTS query expression per OCR search term, in word order
492
+ *
493
+ * Highlighting matches each OCR word against these same per-term expressions,
494
+ * so hit locations always agree with what the filter matched.
495
+ * @internal
496
+ */
497
+ function buildOcrTermQueryExpressions(parameters) {
498
+ const { value, matchMode, isCaseSensitive } = parameters;
499
+ const terms = tokenizeOcrSearchValue({
500
+ value,
501
+ matchMode,
502
+ isCaseSensitive
503
+ });
504
+ const isWholeWordEquality = matchMode === "exact" && terms.length === 1;
505
+ return Array.from(terms, (term) => isWholeWordEquality ? buildCtsElementValueQueryExpression({
506
+ elementName: "string",
507
+ value: term,
508
+ isCaseSensitive
509
+ }) : buildCtsWordQueryExpression({
510
+ value: term,
511
+ matchMode,
512
+ isCaseSensitive,
513
+ queryFamily: "text"
514
+ }));
515
+ }
516
+ function buildOcrQueryExpression(query) {
517
+ const termQueryExpressions = buildOcrTermQueryExpressions(query);
518
+ if (termQueryExpressions.length === 0) return "cts:false-query()";
519
+ return buildNestedElementQuery(["ocr"], termQueryExpressions.length > 1 ? buildCtsNearQueryExpression(termQueryExpressions) : termQueryExpressions[0] ?? "cts:false-query()");
520
+ }
521
+ function registerOcrItemPredicate(context, query) {
522
+ const bindingKey = [
523
+ query.value,
524
+ query.matchMode,
525
+ query.isCaseSensitive ? "case-sensitive" : "case-insensitive"
526
+ ].join("|");
527
+ let variableName = context.ocrVariableNamesByKey.get(bindingKey);
528
+ if (variableName == null) {
529
+ variableName = `$ocrUuids${context.nextOcrSerial}`;
530
+ context.nextOcrSerial += 1;
531
+ context.ocrVariableNamesByKey.set(bindingKey, variableName);
532
+ context.ocrBindings.push({
533
+ name: variableName,
534
+ expression: `for $ocrDocument in cts:search(doc(), ${buildOcrQueryExpression(query)})\n return document-uri($ocrDocument)`
535
+ });
536
+ }
537
+ const itemPredicate = query.isNegated === true ? `[not(@uuid = ${variableName})]` : `[@uuid = ${variableName}]`;
538
+ if (!context.itemPredicates.includes(itemPredicate)) context.itemPredicates.push(itemPredicate);
539
+ }
475
540
  function getLeafSearchValue(query) {
476
541
  switch (query.target) {
477
542
  case "string":
@@ -552,7 +617,11 @@ function createQueryCompilerContext() {
552
617
  return {
553
618
  nextHelperSerial: 1,
554
619
  helperNamesByKey: /* @__PURE__ */ new Map(),
555
- helperDeclarations: []
620
+ helperDeclarations: [],
621
+ nextOcrSerial: 1,
622
+ ocrVariableNamesByKey: /* @__PURE__ */ new Map(),
623
+ ocrBindings: [],
624
+ itemPredicates: []
556
625
  };
557
626
  }
558
627
  function registerConstantHelper(parameters) {
@@ -749,11 +818,24 @@ function getQueryGroupChildren(query) {
749
818
  function getQueryGroupOperator(query) {
750
819
  return "and" in query ? "and" : "or";
751
820
  }
821
+ function isDisjunctiveQueryGroup(query) {
822
+ return "or" in query && query.or.length > 1;
823
+ }
824
+ /**
825
+ * Whether a query tree nests an OCR leaf inside an OR group
826
+ * @internal
827
+ */
828
+ function hasOcrQueryInDisjunction(query, isInDisjunction = false) {
829
+ if (isQueryLeaf(query)) return query.target === "ocr" && isInDisjunction;
830
+ const isChildInDisjunction = isInDisjunction || isDisjunctiveQueryGroup(query);
831
+ for (const childQuery of getQueryGroupChildren(query)) if (hasOcrQueryInDisjunction(childQuery, isChildInDisjunction)) return true;
832
+ return false;
833
+ }
752
834
  function getCompatibleIncludesGroupLeaves(query) {
753
835
  if (!("or" in query) || query.or.length <= 1) return null;
754
836
  const leafQueries = [];
755
837
  for (const childQuery of query.or) {
756
- if (!isQueryLeaf(childQuery)) return null;
838
+ if (!isQueryLeaf(childQuery) || childQuery.target === "ocr") return null;
757
839
  leafQueries.push(childQuery);
758
840
  }
759
841
  const firstQuery = leafQueries[0];
@@ -814,14 +896,20 @@ function buildIncludesGroupQueryExpression(context, queries) {
814
896
  bodyExpression: buildOrCtsQueryExpressionInternal(exactMemberHelpers.map((helper) => helper.callExpression))
815
897
  }).callExpression, tokenizedQueryExpression]);
816
898
  }
817
- function buildQueryNode(context, query) {
899
+ function buildQueryNode(context, query, isInDisjunction) {
818
900
  if (isQueryLeaf(query)) {
901
+ if (query.target === "ocr") {
902
+ if (isInDisjunction) throw new Error(OCR_DISJUNCTION_ERROR_MESSAGE, { cause: query });
903
+ registerOcrItemPredicate(context, query);
904
+ return "cts:true-query()";
905
+ }
819
906
  const queryExpression = buildLeafQueryExpression(context, query);
820
907
  return query.isNegated === true ? buildNotCtsQueryExpression(queryExpression) : queryExpression;
821
908
  }
822
909
  const optimizedIncludesGroupQueries = getCompatibleIncludesGroupLeaves(query);
823
910
  if (optimizedIncludesGroupQueries != null) return buildIncludesGroupQueryExpression(context, optimizedIncludesGroupQueries);
824
- const childQueryExpressions = Array.from(getQueryGroupChildren(query), (childQuery) => buildQueryNode(context, childQuery));
911
+ const isChildInDisjunction = isInDisjunction || isDisjunctiveQueryGroup(query);
912
+ const childQueryExpressions = Array.from(getQueryGroupChildren(query), (childQuery) => buildQueryNode(context, childQuery, isChildInDisjunction));
825
913
  return (getQueryGroupOperator(query) === "and" ? buildAndCtsQueryExpressionInternal : buildOrCtsQueryExpressionInternal)(childQueryExpressions);
826
914
  }
827
915
  function buildBelongsToCollectionQueryExpression(belongsToCollectionScopeUuids, belongsToCollectionPropertyVariableUuid) {
@@ -839,14 +927,18 @@ function buildQueryPlan(parameters) {
839
927
  const { queries } = parameters;
840
928
  if (queries == null) return {
841
929
  prolog: "",
842
- queryExpression: null
930
+ queryExpression: null,
931
+ ocrBindings: [],
932
+ itemPredicates: ""
843
933
  };
844
934
  const context = createQueryCompilerContext();
845
- const queryExpression = buildQueryNode(context, queries);
935
+ const queryExpression = buildQueryNode(context, queries, false);
846
936
  return {
847
937
  prolog: context.helperDeclarations.join("\n\n"),
848
- queryExpression
938
+ queryExpression,
939
+ ocrBindings: context.ocrBindings,
940
+ itemPredicates: context.itemPredicates.join("")
849
941
  };
850
942
  }
851
943
  //#endregion
852
- export { buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildQueryPlan };
944
+ export { OCR_DISJUNCTION_ERROR_MESSAGE, buildAndCtsQueryExpression, buildBelongsToCollectionQueryExpression, buildOcrTermQueryExpressions, buildQueryPlan, hasOcrQueryInDisjunction };
@@ -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.GenericSchema<unknown, Query>, undefined>, null>;
41
+ readonly queries: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.GenericSchema<unknown, Query>, v.CheckAction<Query, "OCR queries cannot be nested inside an OR group because they are resolved by a document join instead of a CTS 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>;
@@ -48,6 +48,17 @@ declare const setPropertyValuesParametersSchema: v.ObjectSchema<{
48
48
  }>;
49
49
  readonly isLimitedToLeafPropertyValues: v.GenericSchema<unknown, boolean>;
50
50
  }, undefined>;
51
+ /**
52
+ * Schema for validating OCR matches parameters
53
+ * @internal
54
+ */
55
+ declare const ocrMatchesParametersSchema: v.ObjectSchema<{
56
+ readonly uuids: 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 UUID is required">]>;
57
+ readonly value: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, "A search value is required">]>;
58
+ readonly matchMode: v.OptionalSchema<v.PicklistSchema<["includes", "exact"], undefined>, "includes">;
59
+ readonly isCaseSensitive: v.GenericSchema<unknown, boolean>;
60
+ readonly maxMatchesPerItem: v.OptionalSchema<v.GenericSchema<unknown, number>, 50>;
61
+ }, undefined>;
51
62
  /**
52
63
  * Schema for validating Set items parameters
53
64
  * @internal
@@ -55,7 +66,7 @@ declare const setPropertyValuesParametersSchema: v.ObjectSchema<{
55
66
  declare const setItemsParametersSchema: v.ObjectSchema<{
56
67
  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">]>;
57
68
  readonly belongsToCollectionScopeUuids: v.OptionalSchema<v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.CheckAction<string, "Invalid pseudo-UUID">]>, undefined>, readonly []>;
58
- readonly queries: v.OptionalSchema<v.NullableSchema<v.GenericSchema<unknown, Query>, undefined>, null>;
69
+ readonly queries: v.OptionalSchema<v.NullableSchema<v.SchemaWithPipe<readonly [v.GenericSchema<unknown, Query>, v.CheckAction<Query, "OCR queries cannot be nested inside an OR group because they are resolved by a document join instead of a CTS query">]>, undefined>, null>;
59
70
  readonly sort: v.OptionalSchema<v.VariantSchema<"target", [v.StrictObjectSchema<{
60
71
  readonly target: v.LiteralSchema<"none", undefined>;
61
72
  }, undefined>, v.StrictObjectSchema<{
@@ -75,4 +86,4 @@ declare const setItemsParametersSchema: v.ObjectSchema<{
75
86
  readonly pageSize: v.OptionalSchema<v.GenericSchema<unknown, number>, 48>;
76
87
  }, undefined>;
77
88
  //#endregion
78
- export { componentSchema, gallerySchema, iso639_3Schema, renderOptionsSchema, setItemsParametersSchema, setPropertyValuesParametersSchema, uuidSchema };
89
+ export { componentSchema, gallerySchema, iso639_3Schema, ocrMatchesParametersSchema, renderOptionsSchema, setItemsParametersSchema, setPropertyValuesParametersSchema, uuidSchema };
package/dist/schemas.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { isPseudoUuid } from "./utilities.mjs";
2
2
  import "./helpers.mjs";
3
+ import { OCR_DISJUNCTION_ERROR_MESSAGE, hasOcrQueryInDisjunction } from "./query.mjs";
3
4
  import * as v from "valibot";
4
5
  //#region src/schemas.ts
5
6
  const positiveNumber = (message) => v.pipe(v.number(), v.minValue(1, message));
@@ -141,6 +142,13 @@ const setQueryLeafSchema = v.union([
141
142
  value: v.string(),
142
143
  ...standardQueryFields
143
144
  }),
145
+ v.strictObject({
146
+ target: v.literal("ocr"),
147
+ value: v.string(),
148
+ matchMode: standardQueryFields.matchMode,
149
+ isCaseSensitive: standardQueryFields.isCaseSensitive,
150
+ isNegated: standardQueryFields.isNegated
151
+ }),
144
152
  v.strictObject({
145
153
  target: v.picklist([
146
154
  "title",
@@ -167,7 +175,7 @@ const setQuerySchema = v.lazy(() => v.union([
167
175
  * Schema for validating Set queries
168
176
  * @internal
169
177
  */
170
- const setQueriesSchema = v.optional(v.nullable(setQuerySchema), null);
178
+ const setQueriesSchema = v.optional(v.nullable(v.pipe(setQuerySchema, v.check((query) => !hasOcrQueryInDisjunction(query), OCR_DISJUNCTION_ERROR_MESSAGE))), null);
171
179
  /**
172
180
  * Schema for validating Set items sort
173
181
  * @internal
@@ -214,6 +222,17 @@ const setPropertyValuesParametersSchema = v.object({
214
222
  isLimitedToLeafPropertyValues: defaultBoolean(false)
215
223
  });
216
224
  /**
225
+ * Schema for validating OCR matches parameters
226
+ * @internal
227
+ */
228
+ const ocrMatchesParametersSchema = v.object({
229
+ uuids: v.pipe(v.array(uuidSchema), v.minLength(1, "At least one UUID is required")),
230
+ value: v.pipe(v.string(), v.minLength(1, "A search value is required")),
231
+ 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)
234
+ });
235
+ /**
217
236
  * Schema for validating Set items parameters
218
237
  * @internal
219
238
  */
@@ -226,4 +245,4 @@ const setItemsParametersSchema = v.object({
226
245
  pageSize: v.optional(positiveNumber("Page size must be positive"), 48)
227
246
  });
228
247
  //#endregion
229
- export { componentSchema, gallerySchema, iso639_3Schema, renderOptionsSchema, setItemsParametersSchema, setPropertyValuesParametersSchema, uuidSchema };
248
+ export { componentSchema, gallerySchema, iso639_3Schema, ocrMatchesParametersSchema, renderOptionsSchema, setItemsParametersSchema, setPropertyValuesParametersSchema, uuidSchema };
@@ -303,6 +303,19 @@ type OcrPage = {
303
303
  height: number | null;
304
304
  blocks: Array<OcrTextBlock>;
305
305
  };
306
+ /**
307
+ * A run of adjacent OCR words matching a search value in OCHRE
308
+ *
309
+ * `uuid` is the requested resource, while `resourceUuid` is the resource that
310
+ * owns the OCR page — they differ when the OCR lives on a child page resource.
311
+ */
312
+ type OcrMatch = {
313
+ uuid: string;
314
+ resourceUuid: string | null;
315
+ page: Omit<OcrPage, "blocks">;
316
+ content: string;
317
+ words: Array<OcrWord>;
318
+ };
306
319
  /**
307
320
  * Note in OCHRE
308
321
  */
@@ -831,6 +844,13 @@ type SetItemsSort = {
831
844
  };
832
845
  /**
833
846
  * Represents a leaf query for Set items
847
+ *
848
+ * The `ocr` target matches the OCR text layer of resources. Because OCR is not
849
+ * carried by Set item projections, it is resolved by a document join rather
850
+ * than a CTS term, which means `ocr` leaves compose with `and` and `isNegated`
851
+ * but cannot be nested inside an `or` group. Both match modes are adjacency
852
+ * based: `includes` allows stemming and wildcards, `exact` requires whole OCR
853
+ * words. OCR carries no language, so `ocr` leaves take no `language`.
834
854
  */
835
855
  type QueryLeaf = {
836
856
  target: "property";
@@ -897,6 +917,12 @@ type QueryLeaf = {
897
917
  isCaseSensitive: boolean;
898
918
  language: string;
899
919
  isNegated?: boolean;
920
+ } | {
921
+ target: "ocr";
922
+ value: string;
923
+ matchMode: "includes" | "exact";
924
+ isCaseSensitive: boolean;
925
+ isNegated?: boolean;
900
926
  } | {
901
927
  target: "title" | "description" | "image" | "periods" | "bibliography" | "notes";
902
928
  value: string;
@@ -918,4 +944,4 @@ type QueryGroup = {
918
944
  */
919
945
  type Query = QueryLeaf | QueryGroup;
920
946
  //#endregion
921
- 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, OcrPage, OcrPoint, OcrTextBlock, OcrTextLine, OcrWord, 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 };
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, OcrMatch, OcrPage, OcrPoint, OcrTextBlock, OcrTextLine, OcrWord, 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 };
@@ -1,6 +1,11 @@
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";
1
+ import { XMLData as XMLData$1, XMLDataItem as XMLDataItem$1, XMLGalleryData as XMLGalleryData$1, XMLItemLinksData as XMLItemLinksData$1, XMLLink as XMLLink$1, XMLOcrMatchesData as XMLOcrMatchesData$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>;
4
9
  declare const XMLLink: v.GenericSchema<unknown, XMLLink$1>;
5
10
  declare const XMLDataItem: v.GenericSchema<unknown, XMLDataItem$1>;
6
11
  declare const XMLItemLinksData: v.GenericSchema<unknown, XMLItemLinksData$1>;
@@ -9,4 +14,4 @@ declare const XMLSetItemsData: v.GenericSchema<unknown, XMLSetItemsData$1>;
9
14
  declare const XMLData: v.GenericSchema<unknown, XMLData$1>;
10
15
  declare const XMLWebsiteData: v.GenericSchema<unknown, XMLWebsiteData$1>;
11
16
  //#endregion
12
- export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink, XMLSetItemsData, XMLWebsiteData };
17
+ export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink, XMLOcrMatchesData, XMLSetItemsData, XMLWebsiteData };
@@ -238,6 +238,24 @@ const XMLOcrPage = v.object({
238
238
  TextBlock: v.optional(v.array(XMLOcrTextBlock, "XMLOcrPage: TextBlock is array of XMLOcrTextBlock"))
239
239
  }, "XMLOcrPage: Shape error");
240
240
  const XMLOcr = v.object({ Page: v.optional(v.array(XMLOcrPage, "XMLOcr: Page is array of XMLOcrPage")) }, "XMLOcr: Shape error");
241
+ const XMLOcrMatch = v.object({
242
+ resourceUuid: v.optional(v.string("XMLOcrMatch: resourceUuid is string and optional")),
243
+ n: XMLOptionalNumber,
244
+ fileName: v.optional(v.string("XMLOcrMatch: fileName is string and optional")),
245
+ WIDTH: XMLOptionalNumber,
246
+ HEIGHT: XMLOptionalNumber,
247
+ string: v.optional(v.array(XMLOcrString, "XMLOcrMatch: string is array of XMLOcrString"))
248
+ }, "XMLOcrMatch: Shape error");
249
+ const XMLOcrMatchItem = v.object({
250
+ uuid: v.pipe(v.string("XMLOcrMatchItem: uuid is string and required"), v.check(isPseudoUuid, "XMLOcrMatchItem: uuid is not a valid pseudo-UUID")),
251
+ matchCount: XMLNumber,
252
+ ocrMatch: v.optional(v.array(XMLOcrMatch, "XMLOcrMatchItem: ocrMatch is array of XMLOcrMatch"))
253
+ }, "XMLOcrMatchItem: Shape error");
254
+ /**
255
+ * Schema for validating OCR matches fetched from the OCHRE API
256
+ * @internal
257
+ */
258
+ 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");
241
259
  const XMLNote = v.object({
242
260
  content: v.optional(XMLContent.entries.content),
243
261
  payload: v.optional(v.string("XMLNote: payload is string and optional")),
@@ -944,4 +962,4 @@ const XMLWebsiteData = v.object({ result: v.object({ ochre: v.object({
944
962
  tree: v.array(XMLWebsiteTree)
945
963
  }, "XMLWebsiteData: ochre is object with website tree") }, "XMLWebsiteData: result is object with ochre") }, "XMLWebsiteData: Shape error");
946
964
  //#endregion
947
- export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink, XMLSetItemsData, XMLWebsiteData };
965
+ export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink, XMLOcrMatchesData, XMLSetItemsData, XMLWebsiteData };
@@ -199,6 +199,24 @@ type XMLOcrPage = {
199
199
  type XMLOcr = {
200
200
  Page?: Array<XMLOcrPage>;
201
201
  };
202
+ type XMLOcrMatch = Omit<XMLOcrPage, "TextBlock"> & {
203
+ resourceUuid?: string;
204
+ string?: Array<XMLOcrString>;
205
+ };
206
+ type XMLOcrMatchItem = {
207
+ uuid: string;
208
+ matchCount: XMLNumber;
209
+ ocrMatch?: Array<XMLOcrMatch>;
210
+ };
211
+ type XMLOcrMatchesData = {
212
+ result: {
213
+ ochre: {
214
+ ocrMatches?: {
215
+ ocrItem?: Array<XMLOcrMatchItem>;
216
+ };
217
+ };
218
+ };
219
+ };
202
220
  type XMLNote = Partial<XMLContent> & XMLString & {
203
221
  noteNo?: XMLNumber;
204
222
  title?: string;
@@ -938,4 +956,4 @@ type XMLWebsiteData = {
938
956
  };
939
957
  };
940
958
  //#endregion
941
- 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, XMLOcr, XMLOcrPage, XMLOcrString, XMLOcrTextBlock, XMLOcrTextLine, XMLPeriod, XMLPerson, XMLProperty, XMLPropertyRelation, XMLPropertyValue, XMLPropertyVariable, XMLRecursiveItemCategory, XMLResource, XMLSection, XMLSet, XMLSetItems, XMLSetItemsData, XMLSimplifiedProperty, XMLSpatialUnit, XMLString, XMLText, XMLTree, XMLWebsiteContext, XMLWebsiteContextItem, XMLWebsiteContextLevel, XMLWebsiteData, XMLWebsiteFilterContext, XMLWebsiteFilterContextItem, XMLWebsiteOptions, XMLWebsiteProperties, XMLWebsiteResource, XMLWebsiteResourceGroup, XMLWebsiteResourceItem, XMLWebsiteScope, XMLWebsiteSegment, XMLWebsiteStyle, XMLWebsiteTree };
959
+ 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, XMLOcr, XMLOcrMatch, XMLOcrMatchItem, XMLOcrMatchesData, XMLOcrPage, XMLOcrString, XMLOcrTextBlock, XMLOcrTextLine, XMLPeriod, XMLPerson, XMLProperty, XMLPropertyRelation, XMLPropertyValue, XMLPropertyVariable, XMLRecursiveItemCategory, XMLResource, 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.70",
3
+ "version": "1.0.71",
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",