ochre-sdk 1.0.78 → 1.1.0
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 +31 -3
- package/dist/_virtual/_rolldown/runtime.mjs +13 -0
- package/dist/categories.d.mts +249 -0
- package/dist/categories.mjs +259 -0
- package/dist/constants.d.mts +14 -0
- package/dist/constants.mjs +18 -1
- package/dist/errors.d.mts +23 -0
- package/dist/{utilities.mjs → errors.mjs} +33 -84
- package/dist/fetchers/gallery.mjs +15 -51
- package/dist/fetchers/item-children.mjs +20 -66
- package/dist/fetchers/item-links.mjs +26 -79
- package/dist/fetchers/item-ocr-data.d.mts +2 -2
- package/dist/fetchers/item-ocr-data.mjs +11 -15
- package/dist/fetchers/item.d.mts +0 -15
- package/dist/fetchers/item.mjs +20 -72
- package/dist/fetchers/request.d.mts +70 -0
- package/dist/fetchers/request.mjs +100 -0
- package/dist/fetchers/set/items.mjs +27 -73
- package/dist/fetchers/set/property-values.d.mts +2 -3
- package/dist/fetchers/set/property-values.mjs +96 -130
- package/dist/fetchers/website-metadata.mjs +35 -57
- package/dist/fetchers/website.d.mts +2 -3
- package/dist/fetchers/website.mjs +22 -31
- package/dist/getters.d.mts +78 -148
- package/dist/getters.mjs +127 -208
- package/dist/helpers.d.mts +0 -4
- package/dist/helpers.mjs +19 -6
- package/dist/index.d.mts +8 -6
- package/dist/index.mjs +6 -4
- package/dist/ocr.d.mts +37 -0
- package/dist/ocr.mjs +52 -0
- package/dist/parsers/helpers.d.mts +21 -1
- package/dist/parsers/helpers.mjs +26 -6
- package/dist/parsers/index.d.mts +0 -8
- package/dist/parsers/index.mjs +118 -259
- package/dist/parsers/languages.d.mts +72 -0
- package/dist/parsers/languages.mjs +132 -0
- package/dist/parsers/multilingual.d.mts +49 -74
- package/dist/parsers/multilingual.mjs +88 -189
- package/dist/parsers/property-token.d.mts +34 -0
- package/dist/parsers/property-token.mjs +29 -0
- package/dist/parsers/string.d.mts +19 -0
- package/dist/parsers/string.mjs +45 -25
- package/dist/parsers/website/bounds.d.mts +10 -0
- package/dist/parsers/website/bounds.mjs +28 -0
- package/dist/parsers/website/components.d.mts +91 -0
- package/dist/parsers/website/components.mjs +681 -0
- package/dist/parsers/website/index.d.mts +0 -7
- package/dist/parsers/website/index.mjs +92 -1153
- package/dist/parsers/website/links.d.mts +36 -0
- package/dist/parsers/website/links.mjs +58 -0
- package/dist/parsers/website/messages.d.mts +24 -0
- package/dist/parsers/website/messages.mjs +31 -0
- package/dist/parsers/website/options.d.mts +6 -0
- package/dist/parsers/website/options.mjs +114 -0
- package/dist/parsers/website/properties.d.mts +12 -0
- package/dist/parsers/website/properties.mjs +158 -0
- package/dist/parsers/website/reader.d.mts +54 -4
- package/dist/parsers/website/reader.mjs +65 -20
- package/dist/parsers/website/slug.d.mts +64 -0
- package/dist/parsers/website/slug.mjs +82 -0
- package/dist/parsers/website/styles.d.mts +28 -0
- package/dist/parsers/website/styles.mjs +103 -0
- package/dist/parsers/website/walk.d.mts +68 -0
- package/dist/parsers/website/walk.mjs +116 -0
- package/dist/query.d.mts +66 -18
- package/dist/query.mjs +202 -48
- package/dist/reflection.d.mts +64 -0
- package/dist/reflection.mjs +79 -0
- package/dist/schemas.d.mts +7 -0
- package/dist/schemas.mjs +12 -3
- package/dist/types/index.d.mts +1 -31
- package/dist/types/utilities.d.mts +9 -0
- package/dist/types/utilities.mjs +1 -0
- package/dist/types/website.d.mts +49 -58
- package/dist/xml/metadata.d.mts +16 -0
- package/dist/xml/metadata.mjs +32 -11
- package/dist/xml/schemas.d.mts +5970 -3
- package/dist/xml/schemas.mjs +43 -45
- package/dist/xml/types.d.mts +13 -30
- package/dist/xquery.d.mts +46 -0
- package/dist/xquery.mjs +66 -0
- package/package.json +3 -3
- package/dist/utilities.d.mts +0 -54
package/dist/fetchers/item.mjs
CHANGED
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { ITEM_CATEGORIES_WITH_EMBEDDED_ITEMS, ITEM_CONTAINER_CATEGORIES, isItemCategoryWithEmbeddedItems, isItemContainerCategory } from "../categories.mjs";
|
|
2
|
+
import { getErrorOutput } from "../errors.mjs";
|
|
3
|
+
import { requestOchre } from "./request.mjs";
|
|
4
|
+
import { uuidSchema } from "../schemas.mjs";
|
|
5
|
+
import { parseRequestedLanguages } from "../parsers/languages.mjs";
|
|
5
6
|
import { parseItem } from "../parsers/index.mjs";
|
|
6
7
|
import { XMLData } from "../xml/schemas.mjs";
|
|
8
|
+
import { compileOchreQuery, stringLiteral } from "../xquery.mjs";
|
|
7
9
|
import { parseWebpageView } from "../parsers/website/index.mjs";
|
|
8
10
|
import * as v from "valibot";
|
|
9
|
-
import { XMLParser } from "fast-xml-parser";
|
|
10
11
|
//#region src/fetchers/item.ts
|
|
11
|
-
function isItemContainerCategory(category) {
|
|
12
|
-
return category === "tree" || category === "set";
|
|
13
|
-
}
|
|
14
|
-
function isItemCategoryWithEmbeddedItems(category) {
|
|
15
|
-
return [
|
|
16
|
-
"tree",
|
|
17
|
-
"bibliography",
|
|
18
|
-
"concept",
|
|
19
|
-
"spatialUnit",
|
|
20
|
-
"period",
|
|
21
|
-
"resource",
|
|
22
|
-
"set"
|
|
23
|
-
].includes(category);
|
|
24
|
-
}
|
|
25
12
|
function isItemWithEmbeddedItems(item) {
|
|
26
13
|
return isItemCategoryWithEmbeddedItems(item.category);
|
|
27
14
|
}
|
|
@@ -49,14 +36,8 @@ function buildXQuery(parameters) {
|
|
|
49
36
|
let itemNodesExpression = "$ochre/node()";
|
|
50
37
|
if (shouldOmitEmbeddedItems) {
|
|
51
38
|
letClauses.push(`let $item := (
|
|
52
|
-
$ochre
|
|
53
|
-
|
|
54
|
-
$ochre/concept,
|
|
55
|
-
$ochre/spatialUnit,
|
|
56
|
-
$ochre/period,
|
|
57
|
-
$ochre/resource,
|
|
58
|
-
$ochre/set
|
|
59
|
-
)[1]`, `let $embedded-child-name := if (local-name($item) = ("tree", "set")) then "items" else local-name($item)`);
|
|
39
|
+
${ITEM_CATEGORIES_WITH_EMBEDDED_ITEMS.map((category) => ` $ochre/${category}`).join(",\n")}
|
|
40
|
+
)[1]`, `let $embedded-child-name := if (local-name($item) = (${ITEM_CONTAINER_CATEGORIES.map((category) => stringLiteral(category)).join(", ")})) then "items" else local-name($item)`);
|
|
60
41
|
itemNodesExpression = `(
|
|
61
42
|
for $node in $ochre/node()
|
|
62
43
|
return
|
|
@@ -65,69 +46,36 @@ function buildXQuery(parameters) {
|
|
|
65
46
|
else $node
|
|
66
47
|
)`;
|
|
67
48
|
}
|
|
68
|
-
return
|
|
69
|
-
|
|
70
|
-
${SUPPLEMENTAL_XQUERY_PROLOG}
|
|
71
|
-
|
|
72
|
-
${letClauses.join("\n")}
|
|
49
|
+
return compileOchreQuery({ body: ({ omitSupplemental }) => `${letClauses.join("\n")}
|
|
73
50
|
return
|
|
74
51
|
if (empty($ochre)) then ()
|
|
75
52
|
else element ochre {
|
|
76
53
|
$ochre/@*,
|
|
77
54
|
${omitSupplemental(itemNodesExpression)}
|
|
78
|
-
}
|
|
55
|
+
}` });
|
|
79
56
|
}
|
|
80
57
|
function omitEmbeddedItems(item) {
|
|
81
58
|
const { items: _items, ...itemWithoutEmbeddedItems } = item;
|
|
82
59
|
return itemWithoutEmbeddedItems;
|
|
83
60
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Validate language codes while preserving literal tuple inference.
|
|
86
|
-
*/
|
|
87
|
-
function parseLanguages(languages) {
|
|
88
|
-
for (const language of languages) v.parse(iso639_3Schema, language);
|
|
89
|
-
return languages;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Defines a reusable languages tuple with validation and literal type inference.
|
|
93
|
-
*
|
|
94
|
-
* Inline arrays can be passed directly to fetchItem:
|
|
95
|
-
* `fetchItem(uuid, { languages: ["eng", "spa"] })`.
|
|
96
|
-
*
|
|
97
|
-
* Use this helper when the language set is stored separately:
|
|
98
|
-
* `const languages = defineLanguages("eng", "spa")`.
|
|
99
|
-
*/
|
|
100
|
-
function defineLanguages(...languages) {
|
|
101
|
-
return parseLanguages(languages);
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* @deprecated Pass inline language arrays directly to fetchItem, or use
|
|
105
|
-
* defineLanguages("eng", "spa") for reusable language tuples.
|
|
106
|
-
*/
|
|
107
|
-
function withLanguages(languages) {
|
|
108
|
-
return parseLanguages(languages);
|
|
109
|
-
}
|
|
110
61
|
async function fetchItem(uuid, options) {
|
|
111
62
|
try {
|
|
112
63
|
const parsedUuid = v.parse(uuidSchema, uuid);
|
|
113
64
|
assertItemCategoryAllowed(options?.category, options?.containedItemCategory);
|
|
114
65
|
const shouldOmitEmbeddedItems = options?.shouldOmitEmbeddedItems === true;
|
|
115
|
-
const languages = options?.languages
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
body: buildXQuery({
|
|
66
|
+
const languages = parseRequestedLanguages(options?.languages);
|
|
67
|
+
const output = await requestOchre({
|
|
68
|
+
xquery: buildXQuery({
|
|
119
69
|
uuid: parsedUuid,
|
|
120
70
|
shouldOmitEmbeddedItems
|
|
121
71
|
}),
|
|
122
|
-
|
|
72
|
+
schema: XMLData,
|
|
73
|
+
label: "OCHRE item",
|
|
74
|
+
options,
|
|
75
|
+
checkRawData: (data) => {
|
|
76
|
+
if (data.result?.ochre?.uuid == null) throw new Error(`No OCHRE item found for UUID "${parsedUuid}"`, { cause: data });
|
|
77
|
+
}
|
|
123
78
|
});
|
|
124
|
-
if (!response.ok) throw new Error("Failed to fetch OCHRE data", { cause: response.statusText });
|
|
125
|
-
const dataRaw = await response.text();
|
|
126
|
-
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
127
|
-
if (data.result?.ochre?.uuid == null) throw new Error(`No OCHRE item found for UUID "${parsedUuid}"`, { cause: dataRaw });
|
|
128
|
-
const { success, issues, output } = v.safeParse(XMLData, data);
|
|
129
|
-
if (!success) throw createSchemaValidationError("Failed to parse OCHRE data", issues);
|
|
130
|
-
restoreXMLMetadata(output, data);
|
|
131
79
|
const parsedItem = parseItem(output, {
|
|
132
80
|
category: options?.category,
|
|
133
81
|
containedItemCategory: options?.containedItemCategory,
|
|
@@ -148,4 +96,4 @@ async function fetchItem(uuid, options) {
|
|
|
148
96
|
}
|
|
149
97
|
}
|
|
150
98
|
//#endregion
|
|
151
|
-
export {
|
|
99
|
+
export { fetchItem };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { FetchFunction } from "../parsers/helpers.mjs";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
//#region src/fetchers/request.d.ts
|
|
4
|
+
export type OchreRequestOptions = {
|
|
5
|
+
fetch?: FetchFunction;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
timeoutMilliseconds?: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Turn an OCHRE XML response into validated data
|
|
11
|
+
*
|
|
12
|
+
* The XML parser, the schema check and the metadata graft are one step: the
|
|
13
|
+
* graft has to follow validation because `v.safeParse` drops the
|
|
14
|
+
* non-enumerable source offsets `fast-xml-parser` records, and skipping it
|
|
15
|
+
* leaves a value that is the right shape but has lost its source order. Kept
|
|
16
|
+
* separate from the request so a caller holding an XML string, such as a test,
|
|
17
|
+
* gets exactly what the network path produces.
|
|
18
|
+
* @param parameters - The decode parameters
|
|
19
|
+
* @param parameters.xml - The raw XML response body
|
|
20
|
+
* @param parameters.schema - The schema the response must satisfy
|
|
21
|
+
* @param parameters.label - What is being decoded, used in failure messages
|
|
22
|
+
* @param parameters.checkRawData - Guard run against the parsed XML before validation
|
|
23
|
+
* @returns The validated response, with XML source metadata restored
|
|
24
|
+
* @throws When the guard rejects or validation fails
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export declare function decodeOchreResponse<TOutput>(parameters: {
|
|
28
|
+
xml: string;
|
|
29
|
+
schema: v.GenericSchema<unknown, TOutput>;
|
|
30
|
+
label: string;
|
|
31
|
+
checkRawData?: (data: unknown) => void;
|
|
32
|
+
}): TOutput;
|
|
33
|
+
/**
|
|
34
|
+
* Post an XQuery to the OCHRE API and validate the response
|
|
35
|
+
*
|
|
36
|
+
* Owns every fact about talking to OCHRE: the endpoint, the request shape and
|
|
37
|
+
* the failure policy. Decoding the body is {@link decodeOchreResponse}.
|
|
38
|
+
* @param parameters - The request parameters
|
|
39
|
+
* @param parameters.xquery - The XQuery to post
|
|
40
|
+
* @param parameters.schema - The schema the response must satisfy
|
|
41
|
+
* @param parameters.label - What is being fetched, used in failure messages
|
|
42
|
+
* @param parameters.options - Transport options
|
|
43
|
+
* @param parameters.checkRawData - Guard run against the parsed XML before validation
|
|
44
|
+
* @returns The validated response, with XML source metadata restored
|
|
45
|
+
* @throws When the request fails, the guard rejects, or validation fails
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export declare function requestOchre<TOutput>(parameters: {
|
|
49
|
+
xquery: string;
|
|
50
|
+
schema: v.GenericSchema<unknown, TOutput>;
|
|
51
|
+
label: string;
|
|
52
|
+
options?: OchreRequestOptions;
|
|
53
|
+
checkRawData?: (data: unknown) => void;
|
|
54
|
+
}): Promise<TOutput>;
|
|
55
|
+
/**
|
|
56
|
+
* Post a JSON payload to the OCHRE API
|
|
57
|
+
* @param parameters - The request parameters
|
|
58
|
+
* @param parameters.body - The JSON payload to post
|
|
59
|
+
* @param parameters.label - What is being posted, used in failure messages
|
|
60
|
+
* @param parameters.options - Transport options
|
|
61
|
+
* @returns Whether the API accepted the payload
|
|
62
|
+
* @throws When the request cannot be completed at all
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
export declare function isOchreJsonAccepted(parameters: {
|
|
66
|
+
body: unknown;
|
|
67
|
+
label: string;
|
|
68
|
+
options?: OchreRequestOptions;
|
|
69
|
+
}): Promise<boolean>;
|
|
70
|
+
//#endregion
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { OCHRE_ENDPOINT, XML_PARSER_OPTIONS } from "../constants.mjs";
|
|
2
|
+
import { createSchemaValidationError } from "../errors.mjs";
|
|
3
|
+
import { restoreXMLMetadata } from "../xml/metadata.mjs";
|
|
4
|
+
import * as v from "valibot";
|
|
5
|
+
import { XMLParser } from "fast-xml-parser";
|
|
6
|
+
//#region src/fetchers/request.ts
|
|
7
|
+
const OCHRE_XQUERY_ENDPOINT = `${OCHRE_ENDPOINT}?xquery&xsl=none&lang="*"`;
|
|
8
|
+
const xmlParser = new XMLParser(XML_PARSER_OPTIONS);
|
|
9
|
+
function resolveSignal(options) {
|
|
10
|
+
const { signal, timeoutMilliseconds } = options ?? {};
|
|
11
|
+
if (timeoutMilliseconds == null) return signal;
|
|
12
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMilliseconds);
|
|
13
|
+
return signal == null ? timeoutSignal : AbortSignal.any([signal, timeoutSignal]);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Turn an OCHRE XML response into validated data
|
|
17
|
+
*
|
|
18
|
+
* The XML parser, the schema check and the metadata graft are one step: the
|
|
19
|
+
* graft has to follow validation because `v.safeParse` drops the
|
|
20
|
+
* non-enumerable source offsets `fast-xml-parser` records, and skipping it
|
|
21
|
+
* leaves a value that is the right shape but has lost its source order. Kept
|
|
22
|
+
* separate from the request so a caller holding an XML string, such as a test,
|
|
23
|
+
* gets exactly what the network path produces.
|
|
24
|
+
* @param parameters - The decode parameters
|
|
25
|
+
* @param parameters.xml - The raw XML response body
|
|
26
|
+
* @param parameters.schema - The schema the response must satisfy
|
|
27
|
+
* @param parameters.label - What is being decoded, used in failure messages
|
|
28
|
+
* @param parameters.checkRawData - Guard run against the parsed XML before validation
|
|
29
|
+
* @returns The validated response, with XML source metadata restored
|
|
30
|
+
* @throws When the guard rejects or validation fails
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
function decodeOchreResponse(parameters) {
|
|
34
|
+
const { xml, schema, label, checkRawData } = parameters;
|
|
35
|
+
const data = xmlParser.parse(xml);
|
|
36
|
+
checkRawData?.(data);
|
|
37
|
+
const { success, issues, output } = v.safeParse(schema, data);
|
|
38
|
+
if (!success) throw createSchemaValidationError(`Failed to parse ${label}`, issues);
|
|
39
|
+
restoreXMLMetadata(output, data);
|
|
40
|
+
return output;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Post an XQuery to the OCHRE API and validate the response
|
|
44
|
+
*
|
|
45
|
+
* Owns every fact about talking to OCHRE: the endpoint, the request shape and
|
|
46
|
+
* the failure policy. Decoding the body is {@link decodeOchreResponse}.
|
|
47
|
+
* @param parameters - The request parameters
|
|
48
|
+
* @param parameters.xquery - The XQuery to post
|
|
49
|
+
* @param parameters.schema - The schema the response must satisfy
|
|
50
|
+
* @param parameters.label - What is being fetched, used in failure messages
|
|
51
|
+
* @param parameters.options - Transport options
|
|
52
|
+
* @param parameters.checkRawData - Guard run against the parsed XML before validation
|
|
53
|
+
* @returns The validated response, with XML source metadata restored
|
|
54
|
+
* @throws When the request fails, the guard rejects, or validation fails
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
async function requestOchre(parameters) {
|
|
58
|
+
const { xquery, schema, label, options, checkRawData } = parameters;
|
|
59
|
+
const response = await (options?.fetch ?? fetch)(OCHRE_XQUERY_ENDPOINT, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: xquery,
|
|
62
|
+
headers: { "Content-Type": "application/xquery" },
|
|
63
|
+
signal: resolveSignal(options)
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) throw new Error(`Failed to fetch ${label}: OCHRE API responded with status ${response.status}`, { cause: response.statusText });
|
|
66
|
+
return decodeOchreResponse({
|
|
67
|
+
xml: await response.text(),
|
|
68
|
+
schema,
|
|
69
|
+
label,
|
|
70
|
+
checkRawData
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Post a JSON payload to the OCHRE API
|
|
75
|
+
* @param parameters - The request parameters
|
|
76
|
+
* @param parameters.body - The JSON payload to post
|
|
77
|
+
* @param parameters.label - What is being posted, used in failure messages
|
|
78
|
+
* @param parameters.options - Transport options
|
|
79
|
+
* @returns Whether the API accepted the payload
|
|
80
|
+
* @throws When the request cannot be completed at all
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
async function isOchreJsonAccepted(parameters) {
|
|
84
|
+
const { body, label, options } = parameters;
|
|
85
|
+
let response;
|
|
86
|
+
try {
|
|
87
|
+
response = await (options?.fetch ?? fetch)(OCHRE_ENDPOINT, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
body: JSON.stringify(body),
|
|
90
|
+
headers: { "Content-Type": "application/json" },
|
|
91
|
+
signal: resolveSignal(options)
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
throw new Error(`Failed to post ${label}`, { cause: error });
|
|
95
|
+
}
|
|
96
|
+
if (response.status >= 500) throw new Error(`Failed to post ${label}: OCHRE API responded with status ${response.status}`, { cause: response.statusText });
|
|
97
|
+
return response.ok;
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { decodeOchreResponse, isOchreJsonAccepted, requestOchre };
|
|
@@ -1,40 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { getErrorOutput } from "../../errors.mjs";
|
|
2
|
+
import { requestOchre } from "../request.mjs";
|
|
3
|
+
import { setItemsParametersSchema } from "../../schemas.mjs";
|
|
4
|
+
import { parseRequestedLanguages, resolveContentLanguages } from "../../parsers/languages.mjs";
|
|
5
5
|
import { parseSetItems } from "../../parsers/index.mjs";
|
|
6
6
|
import { XMLSetItemsData } from "../../xml/schemas.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import { stringLiteral } from "../../xquery.mjs";
|
|
8
|
+
import { compileSetItemsQuery } from "../../query.mjs";
|
|
8
9
|
import * as v from "valibot";
|
|
9
|
-
import { XMLParser } from "fast-xml-parser";
|
|
10
10
|
//#region src/fetchers/set/items.ts
|
|
11
|
-
function parseLanguages(languages) {
|
|
12
|
-
for (const language of languages) v.parse(iso639_3Schema, language);
|
|
13
|
-
return languages;
|
|
14
|
-
}
|
|
15
|
-
function isRecord(value) {
|
|
16
|
-
return typeof value === "object" && value !== null;
|
|
17
|
-
}
|
|
18
|
-
function collectContentLanguages(value, languages) {
|
|
19
|
-
if (Array.isArray(value)) {
|
|
20
|
-
for (const item of value) collectContentLanguages(item, languages);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (!isRecord(value)) return;
|
|
24
|
-
const content = value.content;
|
|
25
|
-
if (Array.isArray(content)) for (const contentItem of content) {
|
|
26
|
-
if (!isRecord(contentItem)) continue;
|
|
27
|
-
const language = contentItem.lang;
|
|
28
|
-
if (typeof language === "string" && language !== "zxx") languages.add(language);
|
|
29
|
-
}
|
|
30
|
-
for (const child of Object.values(value)) collectContentLanguages(child, languages);
|
|
31
|
-
}
|
|
32
|
-
function resolveSetItemsLanguages(data, requestedLanguages) {
|
|
33
|
-
if (requestedLanguages.length > 0) return requestedLanguages;
|
|
34
|
-
const languages = /* @__PURE__ */ new Set();
|
|
35
|
-
collectContentLanguages(data.result.ochre.items, languages);
|
|
36
|
-
return languages.size > 0 ? [...languages] : [...DEFAULT_LANGUAGES];
|
|
37
|
-
}
|
|
38
11
|
function hasArray(items) {
|
|
39
12
|
return items != null && items.length > 0;
|
|
40
13
|
}
|
|
@@ -138,60 +111,41 @@ function buildOrderedItemsClause(sort) {
|
|
|
138
111
|
function buildXQuery(parameters) {
|
|
139
112
|
const { queries, sort, setScopeUuids, belongsToCollectionScopeUuids, page, pageSize } = parameters;
|
|
140
113
|
const startPosition = (page - 1) * pageSize + 1;
|
|
141
|
-
|
|
142
|
-
|
|
114
|
+
return compileSetItemsQuery({
|
|
115
|
+
setScopeUuids,
|
|
116
|
+
belongsToCollectionScopeUuids,
|
|
143
117
|
queries,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
});
|
|
147
|
-
const orderedItemsClause = buildOrderedItemsClause(sort);
|
|
148
|
-
const xqueryDeclarations = [
|
|
149
|
-
"xquery version \"1.0-ml\";",
|
|
150
|
-
setScopeDeclaration,
|
|
151
|
-
SUPPLEMENTAL_XQUERY_PROLOG
|
|
152
|
-
];
|
|
153
|
-
if (compiledQueryPlan.prolog !== "") xqueryDeclarations.push(compiledQueryPlan.prolog);
|
|
154
|
-
return `${xqueryDeclarations.join("\n\n")}
|
|
155
|
-
|
|
156
|
-
<ochre>{
|
|
157
|
-
${compiledQueryPlan.itemsClause}
|
|
158
|
-
let $totalCount := count($items)
|
|
159
|
-
${orderedItemsClause}
|
|
118
|
+
body: ({ items, omitSupplemental }) => ` let $totalCount := count(${items})
|
|
119
|
+
${buildOrderedItemsClause(sort)}
|
|
160
120
|
let $pagedItems := subsequence($orderedItems, ${startPosition}, ${pageSize})
|
|
161
121
|
|
|
162
122
|
return <items totalCount="{$totalCount}" page="${page}" pageSize="${pageSize}">{
|
|
163
123
|
${omitSupplemental("$pagedItems")}
|
|
164
|
-
}</items
|
|
165
|
-
}
|
|
124
|
+
}</items>`
|
|
125
|
+
});
|
|
166
126
|
}
|
|
167
127
|
async function fetchSetItems(parameters, containedItemCategories, options) {
|
|
168
128
|
try {
|
|
169
129
|
const { setScopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize } = v.parse(setItemsParametersSchema, parameters);
|
|
170
|
-
const requestedLanguages = options?.languages
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
130
|
+
const requestedLanguages = parseRequestedLanguages(options?.languages);
|
|
131
|
+
const output = await requestOchre({
|
|
132
|
+
xquery: buildXQuery({
|
|
133
|
+
setScopeUuids,
|
|
134
|
+
belongsToCollectionScopeUuids,
|
|
135
|
+
queries,
|
|
136
|
+
sort,
|
|
137
|
+
page,
|
|
138
|
+
pageSize
|
|
139
|
+
}),
|
|
140
|
+
schema: XMLSetItemsData,
|
|
141
|
+
label: "OCHRE Set items",
|
|
142
|
+
options
|
|
183
143
|
});
|
|
184
|
-
if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`, { cause: response.statusText });
|
|
185
|
-
const dataRaw = await response.text();
|
|
186
|
-
const data = new XMLParser(XML_PARSER_OPTIONS).parse(dataRaw);
|
|
187
|
-
const { success, issues, output } = v.safeParse(XMLSetItemsData, data);
|
|
188
|
-
if (!success) throw createSchemaValidationError("Failed to parse OCHRE Set items", issues);
|
|
189
|
-
restoreXMLMetadata(output, data);
|
|
190
144
|
if (containedItemCategories != null) {
|
|
191
145
|
const missingCategories = containedItemCategories.filter((category) => !hasSetItemsCategory(output.result.ochre.items, category));
|
|
192
146
|
if (missingCategories.length > 0) throw new Error(`No Set items found for item categories: ${missingCategories.join(", ")}`, { cause: missingCategories });
|
|
193
147
|
}
|
|
194
|
-
const languages =
|
|
148
|
+
const languages = resolveContentLanguages(output.result.ochre.items, requestedLanguages);
|
|
195
149
|
const items = parseSetItems(output.result.ochre.items, {
|
|
196
150
|
containedItemCategories,
|
|
197
151
|
languages
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PropertyValueQueryItem, Query, SetAttributeValueQueryItem } from "../../types/index.mjs";
|
|
2
|
+
import { OchreRequestOptions } from "../request.mjs";
|
|
2
3
|
//#region src/fetchers/set/property-values.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* Fetches and parses Set property values from the OCHRE API
|
|
@@ -23,9 +24,7 @@ export declare function fetchSetPropertyValues(parameters: {
|
|
|
23
24
|
periods: boolean;
|
|
24
25
|
};
|
|
25
26
|
isLimitedToLeafPropertyValues?: boolean;
|
|
26
|
-
}, options?: {
|
|
27
|
-
fetch?: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response>;
|
|
28
|
-
}): Promise<{
|
|
27
|
+
}, options?: OchreRequestOptions): Promise<{
|
|
29
28
|
propertyValues: Array<PropertyValueQueryItem>;
|
|
30
29
|
propertyValuesByPropertyVariableUuid: Record<string, Array<PropertyValueQueryItem>>;
|
|
31
30
|
attributeValues: {
|