ochre-sdk 1.0.77 → 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 +595 -635
  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 +34 -34
  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 +15 -23
  41. package/dist/xml/types.d.mts +128 -131
  42. package/package.json +13 -12
@@ -4,14 +4,14 @@ 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
17
  description: MultilingualString<T> | null;
@@ -20,11 +20,11 @@ type ContextTreeLevel<T extends LanguageCodes = LanguageCodes> = {
20
20
  /**
21
21
  * Represents the input control a filter context level is rendered with
22
22
  */
23
- type ContextTreeFilterVariant = "checkbox" | "chip" | "range" | "tile" | "toggle";
23
+ export type ContextTreeFilterVariant = "checkbox" | "chip" | "range" | "tile" | "toggle";
24
24
  /**
25
25
  * Represents a filter context tree level with a context item
26
26
  */
27
- type ContextTreeFilterLevel<T extends LanguageCodes = LanguageCodes> = Prettify<ContextTreeLevel<T> & {
27
+ export type ContextTreeFilterLevel<T extends LanguageCodes = LanguageCodes> = Prettify<ContextTreeLevel<T> & {
28
28
  filterType: "property" | "coordinates" | "bibliography" | "period";
29
29
  filterVariant: ContextTreeFilterVariant | null;
30
30
  isInlineDisplayed: boolean;
@@ -34,7 +34,7 @@ type ContextTreeFilterLevel<T extends LanguageCodes = LanguageCodes> = Prettify<
34
34
  /**
35
35
  * Represents a context tree with levels grouped by behavior
36
36
  */
37
- type ContextTree<T extends LanguageCodes = LanguageCodes> = {
37
+ export type ContextTree<T extends LanguageCodes = LanguageCodes> = {
38
38
  flatten: Array<ContextTreeLevel<T>>;
39
39
  suppress: Array<ContextTreeLevel<T>>;
40
40
  filter: Array<ContextTreeFilterLevel<T>>;
@@ -47,7 +47,7 @@ type ContextTree<T extends LanguageCodes = LanguageCodes> = {
47
47
  /**
48
48
  * Represents a scope with its UUID, type and identification
49
49
  */
50
- type Scope<T extends LanguageCodes = LanguageCodes> = {
50
+ export type Scope<T extends LanguageCodes = LanguageCodes> = {
51
51
  uuid: string;
52
52
  type: string;
53
53
  identification: Identification<T>;
@@ -56,7 +56,7 @@ type Scope<T extends LanguageCodes = LanguageCodes> = {
56
56
  * Represents the parsed OCHRE "options" block shared by the website itself and
57
57
  * by every web element component that supports it
58
58
  */
59
- type WebOptions<T extends LanguageCodes = LanguageCodes> = {
59
+ export type WebOptions<T extends LanguageCodes = LanguageCodes> = {
60
60
  scopes: Array<Scope<T>> | null;
61
61
  contextTree: ContextTree<T> | null;
62
62
  labels: {
@@ -66,8 +66,8 @@ type WebOptions<T extends LanguageCodes = LanguageCodes> = {
66
66
  /**
67
67
  * Represents a stylesheet item with its UUID and category
68
68
  */
69
- type StylesheetCategory = Extract<ItemCategory, "propertyVariable" | "propertyValue">;
70
- type StylesheetItem = {
69
+ export type StylesheetCategory = Extract<ItemCategory, "propertyVariable" | "propertyValue">;
70
+ export type StylesheetItem = {
71
71
  uuid: string;
72
72
  category: "propertyVariable";
73
73
  icon: string | null;
@@ -87,7 +87,7 @@ type StylesheetItem = {
87
87
  mobile: Array<Style>;
88
88
  };
89
89
  };
90
- type WebsitePropertyQueryNode<T extends LanguageCodes = LanguageCodes> = {
90
+ export type WebsitePropertyQueryNode<T extends LanguageCodes = LanguageCodes> = {
91
91
  target: "property";
92
92
  propertyVariable: string;
93
93
  dataType: QueryablePropertyValueDataType;
@@ -95,7 +95,7 @@ type WebsitePropertyQueryNode<T extends LanguageCodes = LanguageCodes> = {
95
95
  isCaseSensitive: boolean;
96
96
  language: T[number];
97
97
  };
98
- type WebsitePropertyQuery<T extends LanguageCodes = LanguageCodes> = WebsitePropertyQueryNode<T> | {
98
+ export type WebsitePropertyQuery<T extends LanguageCodes = LanguageCodes> = WebsitePropertyQueryNode<T> | {
99
99
  and: Array<WebsitePropertyQuery<T>>;
100
100
  } | {
101
101
  or: Array<WebsitePropertyQuery<T>>;
@@ -103,11 +103,11 @@ type WebsitePropertyQuery<T extends LanguageCodes = LanguageCodes> = WebsiteProp
103
103
  /**
104
104
  * Represents the OCHRE website type
105
105
  */
106
- type WebsiteType = "traditional" | "digital-collection" | "plum" | "cedar" | "elm" | "maple" | "oak" | "palm";
106
+ export type WebsiteType = "traditional" | "digital-collection" | "plum" | "cedar" | "elm" | "maple" | "oak" | "palm";
107
107
  /**
108
108
  * Represents a sidebar with its title, items, layout and responsive styles
109
109
  */
110
- type WebSidebar<T extends LanguageCodes = LanguageCodes> = {
110
+ export type WebSidebar<T extends LanguageCodes = LanguageCodes> = {
111
111
  isDisplayed: boolean;
112
112
  items: Array<WebElement<T> | WebBlock<T>>;
113
113
  title: WebTitle<T>;
@@ -122,7 +122,7 @@ type WebSidebar<T extends LanguageCodes = LanguageCodes> = {
122
122
  /**
123
123
  * Represents a website with its properties and items
124
124
  */
125
- type Website<T extends LanguageCodes = LanguageCodes> = {
125
+ export type Website<T extends LanguageCodes = LanguageCodes> = {
126
126
  uuid: string;
127
127
  type: "website" | "segment";
128
128
  belongsTo: {
@@ -209,13 +209,13 @@ type Website<T extends LanguageCodes = LanguageCodes> = {
209
209
  }>;
210
210
  };
211
211
  };
212
- type WebsiteSegment<T extends LanguageCodes = LanguageCodes> = Website<T> & {
212
+ export type WebsiteSegment<T extends LanguageCodes = LanguageCodes> = Website<T> & {
213
213
  type: "segment";
214
214
  };
215
215
  /**
216
216
  * Represents a webpage with its title, slug, properties, items and subpages
217
217
  */
218
- type Webpage<T extends LanguageCodes = LanguageCodes> = {
218
+ export type Webpage<T extends LanguageCodes = LanguageCodes> = {
219
219
  uuid: string;
220
220
  type: "page";
221
221
  title: MultilingualString<T>;
@@ -256,7 +256,7 @@ type Webpage<T extends LanguageCodes = LanguageCodes> = {
256
256
  /**
257
257
  * Represents a title with its label and variant
258
258
  */
259
- type WebTitle<T extends LanguageCodes = LanguageCodes> = {
259
+ export type WebTitle<T extends LanguageCodes = LanguageCodes> = {
260
260
  label: MultilingualString<T>;
261
261
  variant: "default" | "simple";
262
262
  properties: {
@@ -270,7 +270,7 @@ type WebTitle<T extends LanguageCodes = LanguageCodes> = {
270
270
  /**
271
271
  * Base properties for web elements
272
272
  */
273
- type WebElement<T extends LanguageCodes = LanguageCodes> = {
273
+ export type WebElement<T extends LanguageCodes = LanguageCodes> = {
274
274
  uuid: string;
275
275
  language: string | null;
276
276
  type: "element";
@@ -284,7 +284,7 @@ type WebElement<T extends LanguageCodes = LanguageCodes> = {
284
284
  /**
285
285
  * Union type of all possible web element components
286
286
  */
287
- type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
287
+ export type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
288
288
  component: "3d-viewer";
289
289
  linkUuid: string;
290
290
  fileSize: number | null;
@@ -362,6 +362,7 @@ type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
362
362
  isLimitedToInputFilter: boolean;
363
363
  isLimitedToLeafPropertyValues: boolean;
364
364
  sidebarSort: "default" | "alphabetical";
365
+ isSidebarHelpTooltipsDisplayed: boolean;
365
366
  };
366
367
  options: WebOptions<T>;
367
368
  } | {
@@ -467,17 +468,17 @@ type WebElementComponent<T extends LanguageCodes = LanguageCodes> = {
467
468
  linkUuid: string;
468
469
  isChaptersDisplayed: boolean;
469
470
  };
470
- type WebElementComponentName = WebElementComponent["component"];
471
- 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>, {
472
473
  component: U;
473
474
  }>;
474
- 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>, {
475
476
  component: U;
476
477
  }>;
477
478
  /**
478
479
  * Represents an image used in web elements
479
480
  */
480
- type WebImage<T extends LanguageCodes = LanguageCodes> = {
481
+ export type WebImage<T extends LanguageCodes = LanguageCodes> = {
481
482
  uuid: string | null;
482
483
  label: MultilingualString<T> | null;
483
484
  description: MultilingualString<T> | null;
@@ -488,13 +489,13 @@ type WebImage<T extends LanguageCodes = LanguageCodes> = {
488
489
  /**
489
490
  * Represents a CSS style with label and value
490
491
  */
491
- type Style = {
492
+ export type Style = {
492
493
  label: string;
493
494
  value: string;
494
495
  };
495
- type WebBlockLayout = "vertical" | "horizontal" | "grid" | "vertical-flex" | "horizontal-flex" | "accordion";
496
- type WebBlockItem<T extends LanguageCodes = LanguageCodes> = WebElement<T> | WebBlock<T>;
497
- 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> = {
498
499
  uuid: string;
499
500
  type: "accordion-item";
500
501
  trigger: WebElementOf<"text", T>;
@@ -503,7 +504,7 @@ type WebAccordionItem<T extends LanguageCodes = LanguageCodes> = {
503
504
  /**
504
505
  * Represents a block of vertical or horizontal content alignment
505
506
  */
506
- type WebBlock<T extends LanguageCodes = LanguageCodes, U extends WebBlockLayout = WebBlockLayout> = {
507
+ export type WebBlock<T extends LanguageCodes = LanguageCodes, U extends WebBlockLayout = WebBlockLayout> = {
507
508
  uuid: string;
508
509
  language: string | null;
509
510
  type: "block";
@@ -534,9 +535,9 @@ type WebBlock<T extends LanguageCodes = LanguageCodes, U extends WebBlockLayout
534
535
  mobile: Array<Style>;
535
536
  };
536
537
  };
537
- type WebBlockByLayout<U extends WebBlockLayout = WebBlockLayout, T extends LanguageCodes = LanguageCodes> = WebBlock<T, U>;
538
- type AccordionWebBlock<T extends LanguageCodes = LanguageCodes> = WebBlock<T, "accordion">;
539
- 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> = {
540
541
  uuid: string;
541
542
  belongsTo: {
542
543
  uuid: string;
@@ -553,12 +554,11 @@ type WebsiteMetadata<T extends LanguageCodes = LanguageCodes> = {
553
554
  };
554
555
  };
555
556
  };
556
- type ProtectedWebsite<T extends LanguageCodes = LanguageCodes> = {
557
+ export type ProtectedWebsite<T extends LanguageCodes = LanguageCodes> = {
557
558
  uuid: string;
558
559
  identification: Identification<T>;
559
560
  properties: {
560
561
  privacy: "password" | "credentials-ochre";
561
562
  };
562
563
  };
563
- //#endregion
564
- 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);
@@ -847,28 +847,20 @@ const XMLDataItem = v.union([
847
847
  v.object({ text: v.array(XMLText) }, "XMLDataItem: text is array of XMLText"),
848
848
  v.object({ set: v.array(XMLSet) }, "XMLDataItem: set is array of XMLSet")
849
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
+ }
850
857
  const XMLTopLevelDataItem = v.pipe(XMLDataItem, v.check((dataItem) => {
851
858
  if ("tree" in dataItem) return true;
852
- if ("bibliography" in dataItem) for (const bibliography of dataItem.bibliography) {
853
- const children = bibliography.bibliography ?? [];
854
- for (const child of children) if ((child.bibliography?.length ?? 0) > 0) return false;
855
- }
856
- if ("concept" in dataItem) for (const concept of dataItem.concept) {
857
- const children = concept.concept ?? [];
858
- for (const child of children) if ((child.concept?.length ?? 0) > 0) return false;
859
- }
860
- if ("spatialUnit" in dataItem) for (const spatialUnit of dataItem.spatialUnit) {
861
- const children = spatialUnit.spatialUnit ?? [];
862
- for (const child of children) if ((child.spatialUnit?.length ?? 0) > 0) return false;
863
- }
864
- if ("period" in dataItem) for (const period of dataItem.period) {
865
- const children = period.period ?? [];
866
- for (const child of children) if ((child.period?.length ?? 0) > 0) return false;
867
- }
868
- if ("resource" in dataItem) for (const resource of dataItem.resource) {
869
- const children = resource.resource ?? [];
870
- for (const child of children) if ((child.resource?.length ?? 0) > 0) return false;
871
- }
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;
872
864
  return true;
873
865
  }, "XMLDataItem: standalone recursive item children cannot contain nested recursive children"));
874
866
  const XMLItemLinks = v.object({