ochre-sdk 1.0.79 → 1.1.1

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 (84) hide show
  1. package/README.md +60 -3
  2. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  3. package/dist/categories.d.mts +249 -0
  4. package/dist/categories.mjs +259 -0
  5. package/dist/constants.d.mts +14 -0
  6. package/dist/constants.mjs +18 -1
  7. package/dist/errors.d.mts +23 -0
  8. package/dist/{utilities.mjs → errors.mjs} +33 -84
  9. package/dist/fetchers/gallery.mjs +15 -51
  10. package/dist/fetchers/item-children.mjs +20 -66
  11. package/dist/fetchers/item-links.mjs +26 -79
  12. package/dist/fetchers/item-ocr-data.d.mts +2 -2
  13. package/dist/fetchers/item-ocr-data.mjs +11 -15
  14. package/dist/fetchers/item.d.mts +0 -15
  15. package/dist/fetchers/item.mjs +20 -72
  16. package/dist/fetchers/request.d.mts +70 -0
  17. package/dist/fetchers/request.mjs +100 -0
  18. package/dist/fetchers/set/items.mjs +27 -73
  19. package/dist/fetchers/set/property-values.d.mts +2 -3
  20. package/dist/fetchers/set/property-values.mjs +96 -130
  21. package/dist/fetchers/website-metadata.mjs +35 -57
  22. package/dist/fetchers/website.d.mts +2 -3
  23. package/dist/fetchers/website.mjs +22 -31
  24. package/dist/getters.d.mts +86 -145
  25. package/dist/getters.mjs +136 -207
  26. package/dist/helpers.d.mts +0 -4
  27. package/dist/helpers.mjs +19 -6
  28. package/dist/index.d.mts +8 -6
  29. package/dist/index.mjs +6 -4
  30. package/dist/ocr.d.mts +37 -0
  31. package/dist/ocr.mjs +52 -0
  32. package/dist/parsers/helpers.d.mts +21 -1
  33. package/dist/parsers/helpers.mjs +26 -6
  34. package/dist/parsers/index.d.mts +0 -8
  35. package/dist/parsers/index.mjs +118 -259
  36. package/dist/parsers/languages.d.mts +72 -0
  37. package/dist/parsers/languages.mjs +132 -0
  38. package/dist/parsers/multilingual.d.mts +134 -58
  39. package/dist/parsers/multilingual.mjs +191 -143
  40. package/dist/parsers/property-token.d.mts +34 -0
  41. package/dist/parsers/property-token.mjs +29 -0
  42. package/dist/parsers/string.d.mts +19 -0
  43. package/dist/parsers/string.mjs +45 -25
  44. package/dist/parsers/website/bounds.d.mts +10 -0
  45. package/dist/parsers/website/bounds.mjs +28 -0
  46. package/dist/parsers/website/components.d.mts +91 -0
  47. package/dist/parsers/website/components.mjs +681 -0
  48. package/dist/parsers/website/index.d.mts +0 -7
  49. package/dist/parsers/website/index.mjs +92 -1153
  50. package/dist/parsers/website/links.d.mts +36 -0
  51. package/dist/parsers/website/links.mjs +58 -0
  52. package/dist/parsers/website/messages.d.mts +24 -0
  53. package/dist/parsers/website/messages.mjs +31 -0
  54. package/dist/parsers/website/options.d.mts +6 -0
  55. package/dist/parsers/website/options.mjs +114 -0
  56. package/dist/parsers/website/properties.d.mts +12 -0
  57. package/dist/parsers/website/properties.mjs +158 -0
  58. package/dist/parsers/website/reader.d.mts +54 -4
  59. package/dist/parsers/website/reader.mjs +65 -20
  60. package/dist/parsers/website/slug.d.mts +64 -0
  61. package/dist/parsers/website/slug.mjs +82 -0
  62. package/dist/parsers/website/styles.d.mts +28 -0
  63. package/dist/parsers/website/styles.mjs +103 -0
  64. package/dist/parsers/website/walk.d.mts +68 -0
  65. package/dist/parsers/website/walk.mjs +116 -0
  66. package/dist/query.d.mts +66 -21
  67. package/dist/query.mjs +178 -44
  68. package/dist/reflection.d.mts +64 -0
  69. package/dist/reflection.mjs +79 -0
  70. package/dist/schemas.d.mts +7 -0
  71. package/dist/schemas.mjs +12 -3
  72. package/dist/types/index.d.mts +31 -31
  73. package/dist/types/utilities.d.mts +9 -0
  74. package/dist/types/utilities.mjs +1 -0
  75. package/dist/types/website.d.mts +54 -58
  76. package/dist/xml/metadata.d.mts +16 -0
  77. package/dist/xml/metadata.mjs +32 -11
  78. package/dist/xml/schemas.d.mts +5970 -3
  79. package/dist/xml/schemas.mjs +43 -45
  80. package/dist/xml/types.d.mts +14 -30
  81. package/dist/xquery.d.mts +46 -0
  82. package/dist/xquery.mjs +66 -0
  83. package/package.json +3 -3
  84. package/dist/utilities.d.mts +0 -54
@@ -0,0 +1,132 @@
1
+ import { DEFAULT_LANGUAGES } from "../constants.mjs";
2
+ import { readArrayProperty, readEntries } from "../reflection.mjs";
3
+ import { iso639_3Schema } from "../schemas.mjs";
4
+ import { parseStringLike } from "./helpers.mjs";
5
+ import * as v from "valibot";
6
+ //#region src/parsers/languages.ts
7
+ /**
8
+ * A content entry carrying a language tag
9
+ *
10
+ * A schema rather than a hand-written predicate, because this is exactly a
11
+ * shape check: `v.is` narrows only what it has verified, and an array or a
12
+ * `Date` cannot pass because neither carries a string `lang`.
13
+ */
14
+ const languageTaggedContentSchema = v.looseObject({ lang: v.string() });
15
+ /**
16
+ * The language tag OCHRE uses for content that has no language
17
+ */
18
+ const UNTAGGED_LANGUAGE = "zxx";
19
+ function collectContentLanguages(value, languages) {
20
+ if (Array.isArray(value)) {
21
+ for (const item of value) collectContentLanguages(item, languages);
22
+ return;
23
+ }
24
+ for (const contentItem of readArrayProperty(value, "content")) if (v.is(languageTaggedContentSchema, contentItem) && contentItem.lang !== UNTAGGED_LANGUAGE) languages.add(contentItem.lang);
25
+ for (const [, child] of readEntries(value)) collectContentLanguages(child, languages);
26
+ }
27
+ /**
28
+ * Validate language codes while preserving literal tuple inference
29
+ * @param languages - The language codes to validate
30
+ * @returns The same tuple, with its literal types intact
31
+ * @internal
32
+ */
33
+ function parseLanguages(languages) {
34
+ for (const language of languages) v.parse(iso639_3Schema, language);
35
+ return languages;
36
+ }
37
+ /**
38
+ * Define a reusable languages tuple with validation and literal type inference
39
+ *
40
+ * Inline arrays can be passed directly to a fetcher
41
+ * (`fetchItem(uuid, { languages: ["eng", "spa"] })`); use this when the
42
+ * language set is stored separately.
43
+ * @param languages - The language codes to validate
44
+ * @returns The same tuple, with its literal types intact
45
+ */
46
+ function defineLanguages(...languages) {
47
+ return parseLanguages(languages);
48
+ }
49
+ /**
50
+ * Validate an optional caller-supplied language tuple
51
+ * @param languages - The language codes to validate, or undefined
52
+ * @returns The validated codes, or an empty array when none were requested
53
+ * @internal
54
+ */
55
+ function parseRequestedLanguages(languages) {
56
+ return languages == null ? [] : parseLanguages(languages);
57
+ }
58
+ /**
59
+ * Resolve which languages to parse from the content of a payload
60
+ *
61
+ * Requested languages win. Otherwise every `content/@xml:lang` found anywhere
62
+ * beneath the node is used, falling back to {@link DEFAULT_LANGUAGES} when the
63
+ * payload carries no tagged content at all.
64
+ * @param node - The payload node to walk
65
+ * @param requestedLanguages - The languages the caller asked for
66
+ * @returns The languages to parse
67
+ * @internal
68
+ */
69
+ function resolveContentLanguages(node, requestedLanguages) {
70
+ if (requestedLanguages.length > 0) return requestedLanguages;
71
+ const languages = /* @__PURE__ */ new Set();
72
+ collectContentLanguages(node, languages);
73
+ return languages.size > 0 ? [...languages] : [...DEFAULT_LANGUAGES];
74
+ }
75
+ /**
76
+ * Read the languages a dataset declares in its metadata
77
+ * @param rawOchre - The raw OCHRE payload root
78
+ * @param rawOchre.metadata - The payload metadata declaring the languages
79
+ * @param rawOchre.languages - The semicolon-separated fallback language list
80
+ * @returns The declared languages, falling back to {@link DEFAULT_LANGUAGES}
81
+ * @internal
82
+ */
83
+ function parseMetadataLanguages(rawOchre) {
84
+ const languages = [];
85
+ const metadataLanguages = rawOchre.metadata.language ?? [];
86
+ for (const language of metadataLanguages) {
87
+ const parsedLanguage = parseStringLike(language);
88
+ if (parsedLanguage != null) languages.push(parsedLanguage);
89
+ }
90
+ if (languages.length > 0) return languages;
91
+ if (rawOchre.languages != null) {
92
+ for (const language of rawOchre.languages.split(";")) if (language !== "") languages.push(language);
93
+ }
94
+ return languages.length > 0 ? languages : [...DEFAULT_LANGUAGES];
95
+ }
96
+ /**
97
+ * Reconcile requested languages against the ones a dataset declares
98
+ * @param requestedLanguages - The languages the caller asked for
99
+ * @param metadataLanguages - The languages the dataset declares
100
+ * @returns The languages to parse
101
+ * @throws When a requested language is not offered by the dataset
102
+ * @internal
103
+ */
104
+ function resolveLanguages(requestedLanguages, metadataLanguages) {
105
+ if (requestedLanguages == null || requestedLanguages.length === 0) return metadataLanguages;
106
+ const unsupportedLanguages = [];
107
+ for (const requestedLanguage of requestedLanguages) if (!metadataLanguages.some((metadataLanguage) => metadataLanguage.toLocaleLowerCase("en-US") === requestedLanguage.toLocaleLowerCase("en-US"))) unsupportedLanguages.push(requestedLanguage);
108
+ if (unsupportedLanguages.length > 0) throw new Error(`The following language(s) are not supported by the dataset: ${unsupportedLanguages.toSorted((a, b) => a.localeCompare(b, "en-US")).join(", ")}. Available languages: ${metadataLanguages.toSorted((a, b) => a.localeCompare(b, "en-US")).join(", ")}`, { cause: unsupportedLanguages });
109
+ return requestedLanguages;
110
+ }
111
+ /**
112
+ * Pick the language a dataset treats as its default
113
+ * @param rawOchre - The raw OCHRE payload root
114
+ * @param rawOchre.metadata - The payload metadata declaring the default
115
+ * @param languages - The languages being parsed
116
+ * @returns The default language
117
+ * @throws When `languages` is empty
118
+ * @internal
119
+ */
120
+ function resolveDefaultLanguage(rawOchre, languages) {
121
+ const metadataLanguages = rawOchre.metadata.language ?? [];
122
+ for (const language of metadataLanguages) {
123
+ const parsedLanguage = parseStringLike(language);
124
+ if (parsedLanguage != null && language.default === "true" && languages.includes(parsedLanguage)) return parsedLanguage;
125
+ }
126
+ for (const language of languages) if (language === DEFAULT_LANGUAGES[0]) return language;
127
+ const firstLanguage = languages[0];
128
+ if (firstLanguage == null) throw new Error("Default language not found", { cause: languages });
129
+ return firstLanguage;
130
+ }
131
+ //#endregion
132
+ export { defineLanguages, parseLanguages, parseMetadataLanguages, parseRequestedLanguages, resolveContentLanguages, resolveDefaultLanguage, resolveLanguages };
@@ -19,6 +19,13 @@ export type MultilingualStringInput = string | {
19
19
  export type MultilingualStringJSON<T extends ReadonlyArray<string> = ReadonlyArray<string>> = {
20
20
  content: Partial<Record<T[number], Array<MultilingualStringEntry>>>;
21
21
  aliases: Array<string>;
22
+ /**
23
+ * The language reads fall back to first
24
+ *
25
+ * Optional so payloads written before it existed still parse; when absent the
26
+ * first available language is used, which is what the old shape implied.
27
+ */
28
+ defaultLanguage?: string;
22
29
  };
23
30
  export type MultilingualStringObject<T extends ReadonlyArray<string> = ReadonlyArray<string>> = Partial<Record<T[number], MultilingualStringInput>>;
24
31
  export type MultilingualStringEntries<T extends ReadonlyArray<string> = ReadonlyArray<string>> = Partial<Record<T[number], ReadonlyArray<MultilingualStringInput>>>;
@@ -90,109 +97,178 @@ export declare class MultilingualString<T extends ReadonlyArray<string> = Readon
90
97
  constructor(init: MultilingualStringInternalInit<T>);
91
98
  constructor(content: MultilingualStringObject<T>, languages: T, options?: MultilingualOptions);
92
99
  constructor(content?: Partial<Record<string, MultilingualStringInput>>, languages?: undefined, options?: MultilingualOptions);
93
- private getPrimaryEntry;
94
100
  /**
95
- * Get text in a specific language with automatic fallback
101
+ * Resolve the entries to read for a language
102
+ *
103
+ * The fallback order is requested language, then the dataset's default
104
+ * language, then the first language that has any content. This is the only
105
+ * place that order is written down; every reader below is a projection of it.
106
+ */
107
+ private resolveEntries;
108
+ private resolvePrimaryEntry;
109
+ /**
110
+ * Get text in a specific language, falling back when it has none
96
111
  */
97
112
  getText(language?: T[number]): string;
98
113
  /**
99
- * Get rich text in a specific language with automatic fallback
114
+ * Get rich text in a specific language, falling back when it has none
100
115
  */
101
116
  getRichText(language?: T[number]): string;
102
117
  /**
103
- * Get primary text in a specific language without fallback
118
+ * Get text in a specific language, with no fallback
104
119
  */
105
- getExactText(language: T[number]): string | null;
120
+ getExactText(language: T[number]): string;
106
121
  /**
107
- * Get primary rich text in a specific language without fallback
122
+ * Get rich text in a specific language, with no fallback
108
123
  */
109
- getExactRichText(language: T[number]): string | null;
124
+ getExactRichText(language: T[number]): string;
110
125
  /**
111
- * Get all text entries in a specific language without fallback
126
+ * Get every entry for a specific language, with no fallback
112
127
  */
113
- getExactTexts(language: T[number]): Array<string>;
128
+ getExactEntries(language: T[number]): Array<MultilingualStringEntry>;
114
129
  /**
115
- * Get all rich text entries in a specific language without fallback
130
+ * Get every entry for a language, falling back when it has none
131
+ *
132
+ * The multi-entry counterpart of {@link MultilingualString.getText}: OCHRE
133
+ * can carry several entries for one language, and this returns all of them
134
+ * rather than only the primary. Each entry carries both `text` and
135
+ * `richText`, so a caller rendering a rich field reads them from here.
136
+ * @param language - The language to read, or undefined for the default
137
+ * @returns The entries, or an empty array when no language has any
116
138
  */
117
- getExactRichTexts(language: T[number]): Array<string>;
139
+ getEntries(language?: T[number]): Array<MultilingualStringEntry>;
118
140
  /**
119
- * Get all text entries in a specific language with fallback
141
+ * Get the text of every entry for a language, falling back when it has none
142
+ * @param language - The language to read, or undefined for the default
143
+ * @returns The texts, or an empty array when no language has any
120
144
  */
121
145
  getTexts(language?: T[number]): Array<string>;
122
146
  /**
123
- * Get all rich text entries in a specific language with fallback
147
+ * Get the text of every entry for a language, with no fallback
148
+ * @param language - The language to read
149
+ * @returns The texts, or an empty array when that language has none
124
150
  */
125
- getRichTexts(language?: T[number]): Array<string>;
126
- /**
127
- * Get all entries in a specific language without fallback
128
- */
129
- getExactEntries(language: T[number]): Array<MultilingualStringEntry>;
130
- /**
131
- * Get all entries in a specific language with fallback
132
- */
133
- getEntries(language?: T[number]): Array<MultilingualStringEntry>;
151
+ getExactTexts(language: T[number]): Array<string>;
134
152
  /**
135
- * Get aliases carried by OCHRE as zxx content
153
+ * Get the alias values OCHRE carries as `zxx` content
136
154
  */
137
155
  getAliases(): Array<string>;
138
156
  /**
139
- * Check if text exists for a specific language
157
+ * Get the languages that actually carry content
140
158
  */
141
- hasLanguage(language: T[number]): boolean;
159
+ getAvailableLanguages(): Array<T[number]>;
142
160
  /**
143
- * Check if aliases exist
161
+ * Get the language reads fall back to before trying the rest
144
162
  */
145
- hasAliases(): boolean;
146
- /**
147
- * Get all available languages
148
- */
149
- getAvailableLanguages(): ReadonlyArray<T[number]>;
163
+ getDefaultLanguage(): T[number];
150
164
  /**
151
- * Get all supported languages (the full language array passed to constructor)
165
+ * Get every language this string was built to hold
166
+ *
167
+ * The configured language list, which is not the same question as
168
+ * {@link MultilingualString.getAvailableLanguages}: that one answers which
169
+ * languages actually carry content, and is a subset of this.
170
+ * @returns The supported languages
152
171
  */
153
- getSupportedLanguages(): T;
172
+ getSupportedLanguages(): Array<T[number]>;
154
173
  /**
155
- * Check if the multilingual string is empty (no content in any language)
174
+ * Whether any language carries an entry
175
+ *
176
+ * Answers the structural question. A language whose only entry is blank
177
+ * still counts here; {@link MultilingualString.hasContent} is the question
178
+ * about text. Aliases are not entries, so a string carrying only aliases is
179
+ * empty by this measure and {@link MultilingualString.hasAliases} is true.
180
+ * @returns True when no language carries an entry
156
181
  */
157
182
  isEmpty(): boolean;
158
183
  /**
159
- * Check if the multilingual string has any content
184
+ * Whether any entry in any language carries text that is not whitespace
185
+ *
186
+ * Deliberately not the negation of {@link MultilingualString.isEmpty}, which
187
+ * only asks whether entries exist. OCHRE does serve fields holding a single
188
+ * whitespace entry, so a caller deciding whether to render something wants
189
+ * this one, and it looks at every entry rather than only the primary.
190
+ * @returns True when some entry has non-whitespace text
160
191
  */
161
192
  hasContent(): boolean;
162
193
  /**
163
- * Get the default language
194
+ * Whether a specific language carries an entry, with no fallback
195
+ * @param language - The language to test
196
+ * @returns True when that language carries at least one entry
164
197
  */
165
- getDefaultLanguage(): T[number];
166
- /**
167
- * Add or update the primary text for a language (returns new instance)
168
- */
169
- withText(language: T[number], text: MultilingualStringInput): MultilingualString<T>;
198
+ hasLanguage(language: T[number]): boolean;
170
199
  /**
171
- * Add another text entry for a language (returns new instance)
200
+ * Whether OCHRE carried any `zxx` alias values for this string
201
+ * @returns True when there is at least one alias
172
202
  */
173
- withEntry(language: T[number], text: MultilingualStringInput): MultilingualString<T>;
203
+ hasAliases(): boolean;
174
204
  /**
175
- * Replace aliases (returns new instance)
205
+ * Set the text for a language, or append another entry to it
206
+ * @param language - The language to write
207
+ * @param text - The text to write
208
+ * @param options - Write options
209
+ * @param options.shouldAppend - Append as an additional entry instead of replacing
210
+ * @returns A new multilingual string
211
+ */
212
+ with(language: T[number], text: MultilingualStringInput, options?: {
213
+ shouldAppend?: boolean;
214
+ }): MultilingualString<T>;
215
+ /**
216
+ * Remove the content for a language
217
+ *
218
+ * When the removed language was the default, the default moves to the first
219
+ * language that still has content, so reads keep resolving.
220
+ * @param language - The language to remove
221
+ * @returns A new multilingual string
222
+ */
223
+ without(language: T[number]): MultilingualString<T>;
224
+ /**
225
+ * Replace the alias values
226
+ *
227
+ * Aliases are the `zxx` content OCHRE carries alongside a field's languages,
228
+ * so they are set as a whole rather than per language. Empty strings are
229
+ * dropped, matching how they are read from a payload.
230
+ * @param aliases - The aliases to carry
231
+ * @returns A new multilingual string
176
232
  */
177
233
  withAliases(aliases: ReadonlyArray<string>): MultilingualString<T>;
178
234
  /**
179
- * Remove text for a language (returns new instance)
180
- */
181
- withoutLanguage(language: T[number]): MultilingualString<T>;
182
- /**
183
- * Transform all language versions (returns new instance)
184
- */
185
- map(function_: (text: string, language: T[number]) => string): MultilingualString<T>;
186
- /**
187
- * Filter languages based on predicate (returns new instance)
188
- */
189
- filter(shouldInclude: (text: string, language: T[number]) => boolean): MultilingualString<T>;
190
- /**
191
- * Get the string representation (uses default language)
235
+ * Transform the text of every entry in every language
236
+ *
237
+ * Replaces the old `map`, which corrupted rich text: it wrote the
238
+ * transformed plain text and left the entry's `richText` to be re-derived,
239
+ * so a transform such as uppercasing turned `<InternalLink uuid="abc">` into
240
+ * markup OCHRE never wrote. The transform here runs against plain text only,
241
+ * and the entry's rich text is rebuilt from the result, so the two can never
242
+ * disagree.
243
+ *
244
+ * A transform that needs to keep or rewrite markup returns
245
+ * `{ text, richText }` instead of a string, and both are used verbatim.
246
+ * @param transform - Produces the new text for one entry
247
+ * @returns A new multilingual string
248
+ */
249
+ mapText(transform: (text: string, language: T[number]) => MultilingualStringInput): MultilingualString<T>;
250
+ /**
251
+ * Keep only the entries a predicate accepts
252
+ *
253
+ * The callback receives the whole entry rather than just its text, so it
254
+ * can also test `richText` and `isPrimary`. Dropping every entry of a
255
+ * language removes that language, and when that was the default the default
256
+ * moves to the first language that still has content, so reads keep
257
+ * resolving.
258
+ * @param shouldKeep - Whether to keep one entry
259
+ * @returns A new multilingual string
260
+ */
261
+ filterEntries(shouldKeep: (entry: MultilingualStringEntry, language: T[number]) => boolean): MultilingualString<T>;
262
+ /**
263
+ * Get the string representation, using the default language
192
264
  */
193
265
  toString(): string;
194
266
  /**
195
- * Get JSON representation
267
+ * Get the JSON representation
268
+ *
269
+ * Carries `defaultLanguage`, because it is not derivable from the content:
270
+ * without it {@link MultilingualString.fromJSON} would fall back to the first
271
+ * available language and `getText()` would resolve differently.
196
272
  */
197
273
  toJSON(): MultilingualStringJSON<T>;
198
274
  }