ochre-sdk 1.0.76 → 1.0.78

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.
Files changed (42) hide show
  1. package/dist/constants.d.mts +13 -14
  2. package/dist/fetchers/gallery.d.mts +2 -3
  3. package/dist/fetchers/gallery.mjs +2 -1
  4. package/dist/fetchers/item-children.d.mts +3 -4
  5. package/dist/fetchers/item-children.mjs +2 -1
  6. package/dist/fetchers/item-links.d.mts +2 -3
  7. package/dist/fetchers/item-links.mjs +2 -1
  8. package/dist/fetchers/item-ocr-data.d.mts +2 -3
  9. package/dist/fetchers/item.d.mts +7 -8
  10. package/dist/fetchers/item.mjs +2 -1
  11. package/dist/fetchers/set/items.d.mts +2 -3
  12. package/dist/fetchers/set/items.mjs +2 -1
  13. package/dist/fetchers/set/property-values.d.mts +2 -3
  14. package/dist/fetchers/set/property-values.mjs +56 -49
  15. package/dist/fetchers/website-metadata.d.mts +2 -3
  16. package/dist/fetchers/website.d.mts +2 -3
  17. package/dist/getters.d.mts +40 -41
  18. package/dist/getters.mjs +6 -31
  19. package/dist/helpers.d.mts +3 -4
  20. package/dist/parsers/helpers.d.mts +16 -17
  21. package/dist/parsers/index.d.mts +19 -19
  22. package/dist/parsers/index.mjs +65 -48
  23. package/dist/parsers/mdx.d.mts +3 -4
  24. package/dist/parsers/multilingual.d.mts +9 -10
  25. package/dist/parsers/string.d.mts +5 -6
  26. package/dist/parsers/string.mjs +124 -146
  27. package/dist/parsers/website/index.d.mts +4 -5
  28. package/dist/parsers/website/index.mjs +598 -637
  29. package/dist/parsers/website/reader.d.mts +3 -4
  30. package/dist/query.d.mts +3 -4
  31. package/dist/schemas.d.mts +9 -10
  32. package/dist/types/index.d.mts +118 -119
  33. package/dist/types/website.d.mts +36 -38
  34. package/dist/utilities.d.mts +9 -10
  35. package/dist/utilities.mjs +28 -25
  36. package/dist/xml/dates.d.mts +13 -0
  37. package/dist/xml/dates.mjs +49 -0
  38. package/dist/xml/metadata.d.mts +3 -4
  39. package/dist/xml/schemas.d.mts +8 -9
  40. package/dist/xml/schemas.mjs +20 -27
  41. package/dist/xml/types.d.mts +129 -131
  42. package/package.json +13 -12
@@ -4,39 +4,37 @@ import { Bibliography, Identification, ItemCategory, LanguageCodes, License, Met
4
4
  /**
5
5
  * Represents a context tree level item with a variable and value
6
6
  */
7
- type ContextTreeLevelItem = {
7
+ export type ContextTreeLevelItem = {
8
8
  variableUuid: string;
9
9
  valueUuid: string | null;
10
10
  };
11
11
  /**
12
12
  * Represents a context tree level with a context item
13
13
  */
14
- type ContextTreeLevel<T extends LanguageCodes = LanguageCodes> = {
14
+ export type ContextTreeLevel<T extends LanguageCodes = LanguageCodes> = {
15
15
  context: Array<ContextTreeLevelItem>;
16
16
  identification: Identification<T>;
17
+ description: MultilingualString<T> | null;
17
18
  type: string;
18
19
  };
19
20
  /**
20
21
  * Represents the input control a filter context level is rendered with
21
22
  */
22
- type ContextTreeFilterVariant = "checkbox" | "chip" | "range" | "tile" | "toggle";
23
+ export type ContextTreeFilterVariant = "checkbox" | "chip" | "range" | "tile" | "toggle";
23
24
  /**
24
25
  * Represents a filter context tree level with a context item
25
26
  */
26
- type ContextTreeFilterLevel<T extends LanguageCodes = LanguageCodes> = {
27
- context: Array<ContextTreeLevelItem>;
28
- identification: Identification<T>;
29
- type: string;
27
+ export type ContextTreeFilterLevel<T extends LanguageCodes = LanguageCodes> = Prettify<ContextTreeLevel<T> & {
30
28
  filterType: "property" | "coordinates" | "bibliography" | "period";
31
29
  filterVariant: ContextTreeFilterVariant | null;
32
30
  isInlineDisplayed: boolean;
33
31
  isSidebarDisplayed: boolean;
34
32
  isSidebarOpen: boolean;
35
- };
33
+ }>;
36
34
  /**
37
35
  * Represents a context tree with levels grouped by behavior
38
36
  */
39
- type ContextTree<T extends LanguageCodes = LanguageCodes> = {
37
+ export type ContextTree<T extends LanguageCodes = LanguageCodes> = {
40
38
  flatten: Array<ContextTreeLevel<T>>;
41
39
  suppress: Array<ContextTreeLevel<T>>;
42
40
  filter: Array<ContextTreeFilterLevel<T>>;
@@ -49,7 +47,7 @@ type ContextTree<T extends LanguageCodes = LanguageCodes> = {
49
47
  /**
50
48
  * Represents a scope with its UUID, type and identification
51
49
  */
52
- type Scope<T extends LanguageCodes = LanguageCodes> = {
50
+ export type Scope<T extends LanguageCodes = LanguageCodes> = {
53
51
  uuid: string;
54
52
  type: string;
55
53
  identification: Identification<T>;
@@ -58,7 +56,7 @@ type Scope<T extends LanguageCodes = LanguageCodes> = {
58
56
  * Represents the parsed OCHRE "options" block shared by the website itself and
59
57
  * by every web element component that supports it
60
58
  */
61
- type WebOptions<T extends LanguageCodes = LanguageCodes> = {
59
+ export type WebOptions<T extends LanguageCodes = LanguageCodes> = {
62
60
  scopes: Array<Scope<T>> | null;
63
61
  contextTree: ContextTree<T> | null;
64
62
  labels: {
@@ -68,8 +66,8 @@ type WebOptions<T extends LanguageCodes = LanguageCodes> = {
68
66
  /**
69
67
  * Represents a stylesheet item with its UUID and category
70
68
  */
71
- type StylesheetCategory = Extract<ItemCategory, "propertyVariable" | "propertyValue">;
72
- type StylesheetItem = {
69
+ export type StylesheetCategory = Extract<ItemCategory, "propertyVariable" | "propertyValue">;
70
+ export type StylesheetItem = {
73
71
  uuid: string;
74
72
  category: "propertyVariable";
75
73
  icon: string | null;
@@ -89,7 +87,7 @@ type StylesheetItem = {
89
87
  mobile: Array<Style>;
90
88
  };
91
89
  };
92
- type WebsitePropertyQueryNode<T extends LanguageCodes = LanguageCodes> = {
90
+ export type WebsitePropertyQueryNode<T extends LanguageCodes = LanguageCodes> = {
93
91
  target: "property";
94
92
  propertyVariable: string;
95
93
  dataType: QueryablePropertyValueDataType;
@@ -97,7 +95,7 @@ type WebsitePropertyQueryNode<T extends LanguageCodes = LanguageCodes> = {
97
95
  isCaseSensitive: boolean;
98
96
  language: T[number];
99
97
  };
100
- type WebsitePropertyQuery<T extends LanguageCodes = LanguageCodes> = WebsitePropertyQueryNode<T> | {
98
+ export type WebsitePropertyQuery<T extends LanguageCodes = LanguageCodes> = WebsitePropertyQueryNode<T> | {
101
99
  and: Array<WebsitePropertyQuery<T>>;
102
100
  } | {
103
101
  or: Array<WebsitePropertyQuery<T>>;
@@ -105,11 +103,11 @@ type WebsitePropertyQuery<T extends LanguageCodes = LanguageCodes> = WebsiteProp
105
103
  /**
106
104
  * Represents the OCHRE website type
107
105
  */
108
- type WebsiteType = "traditional" | "digital-collection" | "plum" | "cedar" | "elm" | "maple" | "oak" | "palm";
106
+ export type WebsiteType = "traditional" | "digital-collection" | "plum" | "cedar" | "elm" | "maple" | "oak" | "palm";
109
107
  /**
110
108
  * Represents a sidebar with its title, items, layout and responsive styles
111
109
  */
112
- type WebSidebar<T extends LanguageCodes = LanguageCodes> = {
110
+ export type WebSidebar<T extends LanguageCodes = LanguageCodes> = {
113
111
  isDisplayed: boolean;
114
112
  items: Array<WebElement<T> | WebBlock<T>>;
115
113
  title: WebTitle<T>;
@@ -124,7 +122,7 @@ type WebSidebar<T extends LanguageCodes = LanguageCodes> = {
124
122
  /**
125
123
  * Represents a website with its properties and items
126
124
  */
127
- type Website<T extends LanguageCodes = LanguageCodes> = {
125
+ export type Website<T extends LanguageCodes = LanguageCodes> = {
128
126
  uuid: string;
129
127
  type: "website" | "segment";
130
128
  belongsTo: {
@@ -211,13 +209,13 @@ type Website<T extends LanguageCodes = LanguageCodes> = {
211
209
  }>;
212
210
  };
213
211
  };
214
- type WebsiteSegment<T extends LanguageCodes = LanguageCodes> = Website<T> & {
212
+ export type WebsiteSegment<T extends LanguageCodes = LanguageCodes> = Website<T> & {
215
213
  type: "segment";
216
214
  };
217
215
  /**
218
216
  * Represents a webpage with its title, slug, properties, items and subpages
219
217
  */
220
- type Webpage<T extends LanguageCodes = LanguageCodes> = {
218
+ export type Webpage<T extends LanguageCodes = LanguageCodes> = {
221
219
  uuid: string;
222
220
  type: "page";
223
221
  title: MultilingualString<T>;
@@ -258,7 +256,7 @@ type Webpage<T extends LanguageCodes = LanguageCodes> = {
258
256
  /**
259
257
  * Represents a title with its label and variant
260
258
  */
261
- type WebTitle<T extends LanguageCodes = LanguageCodes> = {
259
+ export type WebTitle<T extends LanguageCodes = LanguageCodes> = {
262
260
  label: MultilingualString<T>;
263
261
  variant: "default" | "simple";
264
262
  properties: {
@@ -272,7 +270,7 @@ type WebTitle<T extends LanguageCodes = LanguageCodes> = {
272
270
  /**
273
271
  * Base properties for web elements
274
272
  */
275
- type WebElement<T extends LanguageCodes = LanguageCodes> = {
273
+ export type WebElement<T extends LanguageCodes = LanguageCodes> = {
276
274
  uuid: string;
277
275
  language: string | null;
278
276
  type: "element";
@@ -286,7 +284,7 @@ type WebElement<T extends LanguageCodes = LanguageCodes> = {
286
284
  /**
287
285
  * Union type of all possible web element components
288
286
  */
289
- type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
287
+ export type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
290
288
  component: "3d-viewer";
291
289
  linkUuid: string;
292
290
  fileSize: number | null;
@@ -364,6 +362,7 @@ type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
364
362
  isLimitedToInputFilter: boolean;
365
363
  isLimitedToLeafPropertyValues: boolean;
366
364
  sidebarSort: "default" | "alphabetical";
365
+ isSidebarHelpTooltipsDisplayed: boolean;
367
366
  };
368
367
  options: WebOptions<T>;
369
368
  } | {
@@ -469,17 +468,17 @@ type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
469
468
  linkUuid: string;
470
469
  isChaptersDisplayed: boolean;
471
470
  };
472
- type WebElementComponentName = WebElementComponent["component"];
473
- type WebElementComponentOf<U extends WebElementComponentName, T extends LanguageCodes = LanguageCodes> = Extract<WebElementComponent<T>, {
471
+ export type WebElementComponentName = WebElementComponent["component"];
472
+ export type WebElementComponentOf<U extends WebElementComponentName, T extends LanguageCodes = LanguageCodes> = Extract<WebElementComponent<T>, {
474
473
  component: U;
475
474
  }>;
476
- type WebElementOf<U extends WebElementComponentName, T extends LanguageCodes = LanguageCodes> = Extract<WebElement<T>, {
475
+ export type WebElementOf<U extends WebElementComponentName, T extends LanguageCodes = LanguageCodes> = Extract<WebElement<T>, {
477
476
  component: U;
478
477
  }>;
479
478
  /**
480
479
  * Represents an image used in web elements
481
480
  */
482
- type WebImage<T extends LanguageCodes = LanguageCodes> = {
481
+ export type WebImage<T extends LanguageCodes = LanguageCodes> = {
483
482
  uuid: string | null;
484
483
  label: MultilingualString<T> | null;
485
484
  description: MultilingualString<T> | null;
@@ -490,13 +489,13 @@ type WebImage<T extends LanguageCodes = LanguageCodes> = {
490
489
  /**
491
490
  * Represents a CSS style with label and value
492
491
  */
493
- type Style = {
492
+ export type Style = {
494
493
  label: string;
495
494
  value: string;
496
495
  };
497
- type WebBlockLayout = "vertical" | "horizontal" | "grid" | "vertical-flex" | "horizontal-flex" | "accordion";
498
- type WebBlockItem<T extends LanguageCodes = LanguageCodes> = WebElement<T> | WebBlock<T>;
499
- type WebAccordionItem<T extends LanguageCodes = LanguageCodes> = {
496
+ export type WebBlockLayout = "vertical" | "horizontal" | "grid" | "vertical-flex" | "horizontal-flex" | "accordion";
497
+ export type WebBlockItem<T extends LanguageCodes = LanguageCodes> = WebElement<T> | WebBlock<T>;
498
+ export type WebAccordionItem<T extends LanguageCodes = LanguageCodes> = {
500
499
  uuid: string;
501
500
  type: "accordion-item";
502
501
  trigger: WebElementOf<"text", T>;
@@ -505,7 +504,7 @@ type WebAccordionItem<T extends LanguageCodes = LanguageCodes> = {
505
504
  /**
506
505
  * Represents a block of vertical or horizontal content alignment
507
506
  */
508
- type WebBlock<T extends LanguageCodes = LanguageCodes, U extends WebBlockLayout = WebBlockLayout> = {
507
+ export type WebBlock<T extends LanguageCodes = LanguageCodes, U extends WebBlockLayout = WebBlockLayout> = {
509
508
  uuid: string;
510
509
  language: string | null;
511
510
  type: "block";
@@ -536,9 +535,9 @@ type WebBlock<T extends LanguageCodes = LanguageCodes, U extends WebBlockLayout
536
535
  mobile: Array<Style>;
537
536
  };
538
537
  };
539
- type WebBlockByLayout<U extends WebBlockLayout = WebBlockLayout, T extends LanguageCodes = LanguageCodes> = WebBlock<T, U>;
540
- type AccordionWebBlock<T extends LanguageCodes = LanguageCodes> = WebBlock<T, "accordion">;
541
- type WebsiteMetadata<T extends LanguageCodes = LanguageCodes> = {
538
+ export type WebBlockByLayout<U extends WebBlockLayout = WebBlockLayout, T extends LanguageCodes = LanguageCodes> = WebBlock<T, U>;
539
+ export type AccordionWebBlock<T extends LanguageCodes = LanguageCodes> = WebBlock<T, "accordion">;
540
+ export type WebsiteMetadata<T extends LanguageCodes = LanguageCodes> = {
542
541
  uuid: string;
543
542
  belongsTo: {
544
543
  uuid: string;
@@ -555,12 +554,11 @@ type WebsiteMetadata<T extends LanguageCodes = LanguageCodes> = {
555
554
  };
556
555
  };
557
556
  };
558
- type ProtectedWebsite<T extends LanguageCodes = LanguageCodes> = {
557
+ export type ProtectedWebsite<T extends LanguageCodes = LanguageCodes> = {
559
558
  uuid: string;
560
559
  identification: Identification<T>;
561
560
  properties: {
562
561
  privacy: "password" | "credentials-ochre";
563
562
  };
564
563
  };
565
- //#endregion
566
- export { AccordionWebBlock, ContextTree, ContextTreeFilterLevel, ContextTreeFilterVariant, ContextTreeLevel, ContextTreeLevelItem, ProtectedWebsite, Scope, Style, StylesheetCategory, StylesheetItem, WebAccordionItem, WebBlock, WebBlockByLayout, WebBlockItem, WebBlockLayout, WebElement, WebElementComponent, WebElementComponentName, WebElementComponentOf, WebElementOf, WebImage, WebOptions, WebSidebar, WebTitle, Webpage, Website, WebsiteMetadata, WebsitePropertyQuery, WebsitePropertyQueryNode, WebsiteSegment, WebsiteType };
564
+ //#endregion
@@ -2,24 +2,24 @@ import { LanguageCodes, Property, SetItemProperty } from "./types/index.mjs";
2
2
  import * as v from "valibot";
3
3
  //#region src/utilities.d.ts
4
4
  type SchemaValidationIssue = v.BaseIssue<unknown>;
5
- declare function getErrorOutput(error: unknown, fallbackMessage: string): {
5
+ export declare function getErrorOutput(error: unknown, fallbackMessage: string): {
6
6
  error: string;
7
7
  detailedError: string;
8
8
  };
9
- declare function createSchemaValidationError(message: string, issues: ReadonlyArray<SchemaValidationIssue>): Error;
9
+ export declare function createSchemaValidationError(message: string, issues: ReadonlyArray<SchemaValidationIssue>): Error;
10
10
  /**
11
11
  * Validates a pseudo-UUID string
12
12
  * @param value - The string to validate
13
13
  * @returns True if the string is a valid pseudo-UUID, false otherwise
14
14
  * @internal
15
15
  */
16
- declare function isPseudoUuid(value: string): boolean;
16
+ export declare function isPseudoUuid(value: string): boolean;
17
17
  /**
18
18
  * Build a string literal for an XQuery string
19
19
  * @param value - The string value to escape
20
20
  * @returns The escaped string literal
21
21
  */
22
- declare function stringLiteral(value: string): string;
22
+ export declare function stringLiteral(value: string): string;
23
23
  /**
24
24
  * XQuery prolog declaring `local:omit-supplemental`, which drops every element
25
25
  * carrying `supplemental="true"` from a node sequence, at any depth.
@@ -31,25 +31,24 @@ declare function stringLiteral(value: string): string;
31
31
  *
32
32
  * Must be declared before any query body that calls {@link omitSupplemental}.
33
33
  */
34
- declare const SUPPLEMENTAL_XQUERY_PROLOG = "declare function local:omit-supplemental($nodes as node()*) as node()* {\n for $node in $nodes\n return\n if ($node instance of element())\n then\n if ($node/@supplemental = \"true\")\n then ()\n else if (empty($node//@supplemental[. = \"true\"]))\n then $node\n else element { node-name($node) } {\n $node/@*,\n local:omit-supplemental($node/node())\n }\n else $node\n};";
34
+ export declare const SUPPLEMENTAL_XQUERY_PROLOG = "declare function local:omit-supplemental($nodes as node()*) as node()* {\n for $node in $nodes\n return\n if ($node instance of element())\n then\n if ($node/@supplemental = \"true\")\n then ()\n else if (empty($node//@supplemental[. = \"true\"]))\n then $node\n else element { node-name($node) } {\n $node/@*,\n local:omit-supplemental($node/node())\n }\n else $node\n};";
35
35
  /**
36
36
  * Wrap an XQuery node expression so supplemental nodes are omitted from it
37
37
  * @param expression - The XQuery expression returning the nodes to filter
38
38
  * @returns The wrapped XQuery expression
39
39
  */
40
- declare function omitSupplemental(expression: string): string;
40
+ export declare function omitSupplemental(expression: string): string;
41
41
  /**
42
42
  * XQuery predicate keeping only nodes that are neither supplemental themselves
43
43
  * nor nested inside a supplemental node. Use it when aggregating over nodes
44
44
  * instead of returning them.
45
45
  */
46
- declare const NOT_SUPPLEMENTAL_PREDICATE = "[not(ancestor-or-self::*[@supplemental = \"true\"])]";
46
+ export declare const NOT_SUPPLEMENTAL_PREDICATE = "[not(ancestor-or-self::*[@supplemental = \"true\"])]";
47
47
  /**
48
48
  * Flatten a properties array
49
49
  * @param properties - The properties to flatten
50
50
  * @returns The flattened properties
51
51
  * @internal
52
52
  */
53
- declare function flattenProperties<T extends LanguageCodes = LanguageCodes>(properties: ReadonlyArray<Property<T> | SetItemProperty<T>>): Array<SetItemProperty<T>>;
54
- //#endregion
55
- export { NOT_SUPPLEMENTAL_PREDICATE, SUPPLEMENTAL_XQUERY_PROLOG, createSchemaValidationError, flattenProperties, getErrorOutput, isPseudoUuid, omitSupplemental, stringLiteral };
53
+ export declare function flattenProperties<T extends LanguageCodes = LanguageCodes>(properties: ReadonlyArray<Property<T> | SetItemProperty<T>>): Array<SetItemProperty<T>>;
54
+ //#endregion
@@ -44,28 +44,39 @@ function appendSchemaValidationIssues(lines, issues, depth = 0, prefix = "") {
44
44
  }
45
45
  }
46
46
  }
47
+ function formatCauseArray(value) {
48
+ const values = [];
49
+ for (const item of value) {
50
+ const formattedItem = typeof item === "string" && item.length > 0 ? item : formatPrimitiveValue(item);
51
+ if (formattedItem != null && formattedItem.length > 0) values.push(formattedItem);
52
+ }
53
+ return values.length > 0 ? values.join(", ") : null;
54
+ }
55
+ function formatCauseRecord(value) {
56
+ const values = [];
57
+ for (const [key, entryValue] of Object.entries(value)) {
58
+ const formattedEntryValue = formatPrimitiveValue(entryValue);
59
+ if (formattedEntryValue != null) values.push(`${key}: ${formattedEntryValue}`);
60
+ }
61
+ return values.length > 0 ? values.join("; ") : null;
62
+ }
47
63
  function formatCauseValue(value) {
48
64
  if (typeof value === "string") return value.length > 0 ? value : null;
49
65
  const primitiveValue = formatPrimitiveValue(value);
50
66
  if (primitiveValue != null) return primitiveValue;
51
- if (Array.isArray(value)) {
52
- const values = [];
53
- for (const item of value) {
54
- const formattedItem = typeof item === "string" && item.length > 0 ? item : formatPrimitiveValue(item);
55
- if (formattedItem != null && formattedItem.length > 0) values.push(formattedItem);
56
- }
57
- return values.length > 0 ? values.join(", ") : null;
58
- }
59
- if (isRecord(value)) {
60
- const values = [];
61
- for (const [key, entryValue] of Object.entries(value)) {
62
- const formattedEntryValue = formatPrimitiveValue(entryValue);
63
- if (formattedEntryValue != null) values.push(`${key}: ${formattedEntryValue}`);
64
- }
65
- return values.length > 0 ? values.join("; ") : null;
66
- }
67
+ if (Array.isArray(value)) return formatCauseArray(value);
68
+ if (isRecord(value)) return formatCauseRecord(value);
67
69
  return null;
68
70
  }
71
+ function appendContainedErrors(lines, containedErrors, indent, depth, seenErrors) {
72
+ lines.push("", `${indent}Contained errors`);
73
+ let index = 0;
74
+ for (const containedError of containedErrors) {
75
+ index += 1;
76
+ lines.push(`${indent}${index}.`);
77
+ appendDetailedError(lines, containedError, "Unknown error", depth + 1, seenErrors);
78
+ }
79
+ }
69
80
  function appendDetailedError(lines, error, fallbackMessage, depth, seenErrors) {
70
81
  const indent = " ".repeat(depth);
71
82
  if (error instanceof Error) {
@@ -77,15 +88,7 @@ function appendDetailedError(lines, error, fallbackMessage, depth, seenErrors) {
77
88
  lines.push(`${indent}Error`);
78
89
  if (error.name !== "Error") lines.push(`${indent}Name: ${error.name}`);
79
90
  lines.push(`${indent}Message: ${error.message}`);
80
- if (error instanceof AggregateError && error.errors.length > 0) {
81
- lines.push("", `${indent}Contained errors`);
82
- let index = 0;
83
- for (const containedError of error.errors) {
84
- index += 1;
85
- lines.push(`${indent}${index}.`);
86
- appendDetailedError(lines, containedError, "Unknown error", depth + 1, seenErrors);
87
- }
88
- }
91
+ if (error instanceof AggregateError && error.errors.length > 0) appendContainedErrors(lines, error.errors, indent, depth, seenErrors);
89
92
  if (error.cause != null) {
90
93
  const causeLines = [];
91
94
  if (didAppendDetailedCause(causeLines, error.cause, depth, seenErrors)) lines.push("", ...causeLines);
@@ -0,0 +1,13 @@
1
+ //#region src/xml/dates.d.ts
2
+ /**
3
+ * Parses ISO date/time strings and OCHRE's "YYYY-MM-DD HH:mm:ss" format.
4
+ * Like date-fns parseISO: strings without a timezone offset (including
5
+ * date-only strings) are parsed as local time, not UTC. Returns an
6
+ * Invalid Date for anything unparseable.
7
+ *
8
+ * @param value - The date/time string to parse.
9
+ * @returns A Date object representing the parsed date/time, or an Invalid Date if parsing fails.
10
+ * @internal
11
+ */
12
+ export declare function parseDateTime(value: string): Date;
13
+ //#endregion
@@ -0,0 +1,49 @@
1
+ //#region src/xml/dates.ts
2
+ /**
3
+ * Regular expression to match ISO date/time strings and OCHRE's "YYYY-MM-DD HH:mm:ss" format.
4
+ */
5
+ const DATE_TIME_REGEX = /^(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2})(?::(\d{2})(?::(\d{2})(?:[.,](\d+))?)?)?(Z|[+-]\d{2}(?::?\d{2})?)?)?$/;
6
+ function applyTimezoneOffset(date, timezone) {
7
+ const offsetSign = timezone.startsWith("+") ? -1 : 1;
8
+ const offsetHours = Number(timezone.slice(1, 3));
9
+ const offsetMinutes = Number(timezone.slice(3).replace(":", "") || "0");
10
+ if (offsetMinutes > 59) return /* @__PURE__ */ new Date(NaN);
11
+ return new Date(date.getTime() + offsetSign * (offsetHours * 36e5 + offsetMinutes * 6e4));
12
+ }
13
+ /**
14
+ * Parses ISO date/time strings and OCHRE's "YYYY-MM-DD HH:mm:ss" format.
15
+ * Like date-fns parseISO: strings without a timezone offset (including
16
+ * date-only strings) are parsed as local time, not UTC. Returns an
17
+ * Invalid Date for anything unparseable.
18
+ *
19
+ * @param value - The date/time string to parse.
20
+ * @returns A Date object representing the parsed date/time, or an Invalid Date if parsing fails.
21
+ * @internal
22
+ */
23
+ function parseDateTime(value) {
24
+ const match = DATE_TIME_REGEX.exec(value.replace(" ", "T"));
25
+ if (match == null) return /* @__PURE__ */ new Date(NaN);
26
+ const year = Number(match[1]);
27
+ const month = match[2] != null ? Number(match[2]) - 1 : 0;
28
+ const day = match[3] != null ? Number(match[3]) : 1;
29
+ const hours = Number(match[4] ?? 0);
30
+ const minutes = Number(match[5] ?? 0);
31
+ const seconds = Number(match[6] ?? 0);
32
+ const milliseconds = match[7] != null ? Number(match[7].slice(0, 3).padEnd(3, "0")) : 0;
33
+ const timezone = match[8];
34
+ if (minutes > 59 || seconds > 59 || !(hours === 24 && minutes === 0 && seconds === 0 && milliseconds === 0) && hours > 23) return /* @__PURE__ */ new Date(NaN);
35
+ const date = /* @__PURE__ */ new Date(0);
36
+ if (timezone != null) {
37
+ date.setUTCFullYear(year, month, day);
38
+ if (date.getUTCMonth() !== month || date.getUTCDate() !== day) return /* @__PURE__ */ new Date(NaN);
39
+ date.setUTCHours(hours, minutes, seconds, milliseconds);
40
+ } else {
41
+ date.setFullYear(year, month, day);
42
+ if (date.getMonth() !== month || date.getDate() !== day) return /* @__PURE__ */ new Date(NaN);
43
+ date.setHours(hours, minutes, seconds, milliseconds);
44
+ }
45
+ if (timezone == null || timezone === "Z") return date;
46
+ return applyTimezoneOffset(date, timezone);
47
+ }
48
+ //#endregion
49
+ export { parseDateTime };
@@ -1,5 +1,4 @@
1
1
  //#region src/xml/metadata.d.ts
2
- declare function getXMLSourceIndex(value: unknown): number | null;
3
- declare function restoreXMLMetadata(output: unknown, input: unknown): void;
4
- //#endregion
5
- export { getXMLSourceIndex, restoreXMLMetadata };
2
+ export declare function getXMLSourceIndex(value: unknown): number | null;
3
+ export declare function restoreXMLMetadata(output: unknown, input: unknown): void;
4
+ //#endregion
@@ -1,12 +1,11 @@
1
1
  import { XMLData as XMLData$1, XMLDataItem as XMLDataItem$1, XMLGalleryData as XMLGalleryData$1, XMLItemLinksData as XMLItemLinksData$1, XMLLink as XMLLink$1, XMLSetItemsData as XMLSetItemsData$1, XMLWebsiteData as XMLWebsiteData$1 } from "./types.mjs";
2
2
  import * as v from "valibot";
3
3
  //#region src/xml/schemas.d.ts
4
- declare const XMLLink: v.GenericSchema<unknown, XMLLink$1>;
5
- declare const XMLDataItem: v.GenericSchema<unknown, XMLDataItem$1>;
6
- declare const XMLItemLinksData: v.GenericSchema<unknown, XMLItemLinksData$1>;
7
- declare const XMLGalleryData: v.GenericSchema<unknown, XMLGalleryData$1>;
8
- declare const XMLSetItemsData: v.GenericSchema<unknown, XMLSetItemsData$1>;
9
- declare const XMLData: v.GenericSchema<unknown, XMLData$1>;
10
- declare const XMLWebsiteData: v.GenericSchema<unknown, XMLWebsiteData$1>;
11
- //#endregion
12
- export { XMLData, XMLDataItem, XMLGalleryData, XMLItemLinksData, XMLLink, XMLSetItemsData, XMLWebsiteData };
4
+ export declare const XMLLink: v.GenericSchema<unknown, XMLLink$1>;
5
+ export declare const XMLDataItem: v.GenericSchema<unknown, XMLDataItem$1>;
6
+ export declare const XMLItemLinksData: v.GenericSchema<unknown, XMLItemLinksData$1>;
7
+ export declare const XMLGalleryData: v.GenericSchema<unknown, XMLGalleryData$1>;
8
+ export declare const XMLSetItemsData: v.GenericSchema<unknown, XMLSetItemsData$1>;
9
+ export declare const XMLData: v.GenericSchema<unknown, XMLData$1>;
10
+ export declare const XMLWebsiteData: v.GenericSchema<unknown, XMLWebsiteData$1>;
11
+ //#endregion
@@ -1,15 +1,15 @@
1
1
  import { isPseudoUuid } from "../utilities.mjs";
2
+ import { parseDateTime } from "./dates.mjs";
2
3
  import * as v from "valibot";
3
- import { isValid, parseISO } from "date-fns";
4
4
  //#region src/xml/schemas.ts
5
5
  function getXMLStringPayload(value) {
6
6
  return typeof value === "string" ? value : value.payload ?? null;
7
7
  }
8
8
  function parseXMLDate(value) {
9
- return parseISO(getXMLStringPayload(value)?.replace(" ", "T") ?? "");
9
+ return parseDateTime(getXMLStringPayload(value) ?? "");
10
10
  }
11
11
  function isXMLDate(value) {
12
- return isValid(parseXMLDate(value));
12
+ return !Number.isNaN(parseXMLDate(value).getTime());
13
13
  }
14
14
  function isXMLNumber(value) {
15
15
  const payload = getXMLStringPayload(value);
@@ -717,13 +717,14 @@ const XMLWebsiteContextLevel = v.intersect([XMLString, v.object({
717
717
  payload: v.string("XMLWebsiteContextLevel: payload is required"),
718
718
  dataType: v.optional(v.string("XMLWebsiteContextLevel: dataType is optional string"))
719
719
  }, "XMLWebsiteContextLevel: Shape error")]);
720
- const XMLWebsiteContextItem = v.object({
720
+ const XMLWebsiteContextItemEntries = {
721
721
  identification: XMLIdentification,
722
+ description: v.optional(XMLContent),
722
723
  levels: v.optional(v.object({ level: v.array(XMLWebsiteContextLevel) }, "XMLWebsiteContextItem: levels is object with level"))
723
- }, "XMLWebsiteContextItem: Shape error");
724
+ };
725
+ const XMLWebsiteContextItem = v.object(XMLWebsiteContextItemEntries, "XMLWebsiteContextItem: Shape error");
724
726
  const XMLWebsiteFilterContextItem = v.object({
725
- identification: XMLIdentification,
726
- levels: v.optional(v.object({ level: v.array(XMLWebsiteContextLevel) }, "XMLWebsiteFilterContextItem: levels is object with level")),
727
+ ...XMLWebsiteContextItemEntries,
727
728
  filterType: v.optional(v.picklist([
728
729
  "property",
729
730
  "coordinates",
@@ -846,28 +847,20 @@ const XMLDataItem = v.union([
846
847
  v.object({ text: v.array(XMLText) }, "XMLDataItem: text is array of XMLText"),
847
848
  v.object({ set: v.array(XMLSet) }, "XMLDataItem: set is array of XMLSet")
848
849
  ], "XMLDataItem: Shape error");
850
+ function hasNestedRecursiveChildren(items, getChildren) {
851
+ for (const item of items) {
852
+ const children = getChildren(item) ?? [];
853
+ for (const child of children) if ((getChildren(child)?.length ?? 0) > 0) return true;
854
+ }
855
+ return false;
856
+ }
849
857
  const XMLTopLevelDataItem = v.pipe(XMLDataItem, v.check((dataItem) => {
850
858
  if ("tree" in dataItem) return true;
851
- if ("bibliography" in dataItem) for (const bibliography of dataItem.bibliography) {
852
- const children = bibliography.bibliography ?? [];
853
- for (const child of children) if ((child.bibliography?.length ?? 0) > 0) return false;
854
- }
855
- if ("concept" in dataItem) for (const concept of dataItem.concept) {
856
- const children = concept.concept ?? [];
857
- for (const child of children) if ((child.concept?.length ?? 0) > 0) return false;
858
- }
859
- if ("spatialUnit" in dataItem) for (const spatialUnit of dataItem.spatialUnit) {
860
- const children = spatialUnit.spatialUnit ?? [];
861
- for (const child of children) if ((child.spatialUnit?.length ?? 0) > 0) return false;
862
- }
863
- if ("period" in dataItem) for (const period of dataItem.period) {
864
- const children = period.period ?? [];
865
- for (const child of children) if ((child.period?.length ?? 0) > 0) return false;
866
- }
867
- if ("resource" in dataItem) for (const resource of dataItem.resource) {
868
- const children = resource.resource ?? [];
869
- for (const child of children) if ((child.resource?.length ?? 0) > 0) return false;
870
- }
859
+ if ("bibliography" in dataItem && hasNestedRecursiveChildren(dataItem.bibliography, (item) => item.bibliography)) return false;
860
+ if ("concept" in dataItem && hasNestedRecursiveChildren(dataItem.concept, (item) => item.concept)) return false;
861
+ if ("spatialUnit" in dataItem && hasNestedRecursiveChildren(dataItem.spatialUnit, (item) => item.spatialUnit)) return false;
862
+ if ("period" in dataItem && hasNestedRecursiveChildren(dataItem.period, (item) => item.period)) return false;
863
+ if ("resource" in dataItem && hasNestedRecursiveChildren(dataItem.resource, (item) => item.resource)) return false;
871
864
  return true;
872
865
  }, "XMLDataItem: standalone recursive item children cannot contain nested recursive children"));
873
866
  const XMLItemLinks = v.object({