open-board-format 1.0.3 → 1.0.5

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/dist/index.d.mts CHANGED
@@ -12,7 +12,7 @@ import { z } from "zod";
12
12
  * @author Shay Cojocaru
13
13
  * @license MIT
14
14
  */
15
- /** Unique identifier as a string. Must be a non-empty string or number (coerced to string). */
15
+ /** Unique board-element identifier, coerced to a non-empty string. */
16
16
  declare const OBFIDSchema: z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>, z.ZodString>;
17
17
  type OBFID = z.infer<typeof OBFIDSchema>;
18
18
  /**
@@ -26,35 +26,35 @@ type OBFFormatVersion = z.infer<typeof OBFFormatVersionSchema>;
26
26
  declare const OBFLocaleCodeSchema: z.ZodString;
27
27
  type OBFLocaleCode = z.infer<typeof OBFLocaleCodeSchema>;
28
28
  /**
29
- * Mapping of string keys to localized string values.
29
+ * Key–value pairs mapping symbolic names to their translations in a single locale.
30
30
  */
31
31
  declare const OBFLocalizedStringsSchema: z.ZodRecord<z.ZodString, z.ZodString>;
32
32
  type OBFLocalizedStrings = z.infer<typeof OBFLocalizedStringsSchema>;
33
33
  /**
34
- * String translations for multiple locales.
34
+ * Locale-keyed dictionary of translated strings,
35
+ * e.g., `{ en: { greeting: "Hello" }, fr: { greeting: "Bonjour" } }`.
35
36
  */
36
37
  declare const OBFStringsSchema: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>;
37
38
  type OBFStrings = z.infer<typeof OBFStringsSchema>;
38
39
  /**
39
- * Represents custom actions for spelling.
40
- * Prefixed with '+' followed by the text to append.
40
+ * Spelling action: a `+` prefix followed by the text to append,
41
+ * e.g., `"+hello"`.
41
42
  */
42
43
  declare const OBFSpellingActionSchema: z.ZodString;
43
44
  type OBFSpellingAction = z.infer<typeof OBFSpellingActionSchema>;
44
45
  /**
45
- * Represents specialty actions.
46
- * Standard actions are prefixed with ':'.
47
- * Custom actions start with ':ext_'.
46
+ * Specialty action prefixed with `:`, e.g., `":clear"`.
47
+ * Custom extensions use the `:ext_` prefix.
48
48
  */
49
49
  declare const OBFSpecialtyActionSchema: z.ZodString;
50
50
  type OBFSpecialtyAction = z.infer<typeof OBFSpecialtyActionSchema>;
51
51
  /**
52
- * Possible actions associated with a button.
52
+ * Union of spelling and specialty actions that a button can trigger.
53
53
  */
54
54
  declare const OBFButtonActionSchema: z.ZodUnion<readonly [z.ZodString, z.ZodString]>;
55
55
  type OBFButtonAction = z.infer<typeof OBFButtonActionSchema>;
56
56
  /**
57
- * Licensing information for a resource.
57
+ * License terms and attribution for a resource.
58
58
  */
59
59
  declare const OBFLicenseSchema: z.ZodObject<{
60
60
  type: z.ZodString;
@@ -91,7 +91,7 @@ declare const OBFMediaSchema: z.ZodObject<{
91
91
  }, z.core.$strip>;
92
92
  type OBFMedia = z.infer<typeof OBFMediaSchema>;
93
93
  /**
94
- * Information about a symbol from a proprietary symbol set.
94
+ * Reference to a symbol in a proprietary symbol set (e.g., SymbolStix).
95
95
  */
96
96
  declare const OBFSymbolInfoSchema: z.ZodObject<{
97
97
  set: z.ZodString;
@@ -99,13 +99,14 @@ declare const OBFSymbolInfoSchema: z.ZodObject<{
99
99
  }, z.core.$strip>;
100
100
  type OBFSymbolInfo = z.infer<typeof OBFSymbolInfoSchema>;
101
101
  /**
102
- * Represents an image resource.
102
+ * Image resource, extending {@link OBFMediaSchema} with optional
103
+ * symbol and dimension properties.
103
104
  *
104
- * When resolving the image, if multiple references are provided, they should be used in the following order:
105
- * 1. data
106
- * 2. path
107
- * 3. url
108
- * 4. symbol
105
+ * When resolving the image, consumers should prefer sources in this order:
106
+ * 1. `data`
107
+ * 2. `path`
108
+ * 3. `url`
109
+ * 4. `symbol`
109
110
  */
110
111
  declare const OBFImageSchema: z.ZodIntersection<z.ZodObject<{
111
112
  id: z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>, z.ZodString>;
@@ -132,7 +133,7 @@ declare const OBFImageSchema: z.ZodIntersection<z.ZodObject<{
132
133
  }, z.core.$strip>>;
133
134
  type OBFImage = z.infer<typeof OBFImageSchema>;
134
135
  /**
135
- * Represents a sound resource.
136
+ * Audio resource. Identical to {@link OBFMediaSchema} — no additional properties.
136
137
  */
137
138
  declare const OBFSoundSchema: z.ZodObject<{
138
139
  id: z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>, z.ZodString>;
@@ -152,7 +153,7 @@ declare const OBFSoundSchema: z.ZodObject<{
152
153
  }, z.core.$strip>;
153
154
  type OBFSound = z.infer<typeof OBFSoundSchema>;
154
155
  /**
155
- * Information needed to load another board.
156
+ * Reference to another board, resolved by ID, path, or URL.
156
157
  */
157
158
  declare const OBFLoadBoardSchema: z.ZodObject<{
158
159
  id: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string | undefined, string | number>>>;
@@ -163,7 +164,7 @@ declare const OBFLoadBoardSchema: z.ZodObject<{
163
164
  }, z.core.$strip>;
164
165
  type OBFLoadBoard = z.infer<typeof OBFLoadBoardSchema>;
165
166
  /**
166
- * Represents a button on the board.
167
+ * Interactive element on a board, optionally linked to images, sounds, and actions.
167
168
  */
168
169
  declare const OBFButtonSchema: z.ZodObject<{
169
170
  id: z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>, z.ZodString>;
@@ -189,7 +190,7 @@ declare const OBFButtonSchema: z.ZodObject<{
189
190
  }, z.core.$strip>;
190
191
  type OBFButton = z.infer<typeof OBFButtonSchema>;
191
192
  /**
192
- * Grid layout information for the board.
193
+ * Row-and-column layout that arranges buttons by their IDs.
193
194
  */
194
195
  declare const OBFGridSchema: z.ZodObject<{
195
196
  rows: z.ZodNumber;
@@ -198,7 +199,7 @@ declare const OBFGridSchema: z.ZodObject<{
198
199
  }, z.core.$strip>;
199
200
  type OBFGrid = z.infer<typeof OBFGridSchema>;
200
201
  /**
201
- * Represents the root object of an OBF file, defining the structure and layout of a board.
202
+ * Root object of an `.obf` file: the complete definition of a single communication board.
202
203
  */
203
204
  declare const OBFBoardSchema: z.ZodObject<{
204
205
  format: z.ZodString;
@@ -285,7 +286,7 @@ declare const OBFBoardSchema: z.ZodObject<{
285
286
  }, z.core.$strip>;
286
287
  type OBFBoard = z.infer<typeof OBFBoardSchema>;
287
288
  /**
288
- * Manifest file in an .obz package.
289
+ * Table of contents for an `.obz` package, mapping resource IDs to their archive paths.
289
290
  */
290
291
  declare const OBFManifestSchema: z.ZodObject<{
291
292
  format: z.ZodString;
@@ -302,48 +303,101 @@ type OBFManifest = z.infer<typeof OBFManifestSchema>;
302
303
  /**
303
304
  * Parse a JSON string into a validated OBF board.
304
305
  *
305
- * Handles an optional UTF-8 BOM prefix and throws a descriptive
306
- * error if the input is malformed or fails schema validation.
306
+ * Strips an optional UTF-8 BOM prefix before parsing and throws a
307
+ * descriptive error if the input is malformed or fails schema validation.
308
+ *
309
+ * @param json - The JSON string to parse.
310
+ * @returns The validated board object.
311
+ *
312
+ * @throws {Error} If the JSON is malformed or does not conform to the OBF schema.
307
313
  */
308
314
  declare function parseOBF(json: string): OBFBoard;
309
315
  /**
310
- * Read a `File` handle and parse its contents as an OBF board.
316
+ * Read a `File` and parse its contents as a validated OBF board.
311
317
  *
312
318
  * This relies on the browser `File` API; for Node environments,
313
319
  * read the file to a string and pass it to {@link parseOBF} instead.
320
+ *
321
+ * @param file - A `File` handle pointing to an `.obf` file.
322
+ * @returns The validated board object.
323
+ *
324
+ * @throws {Error} If the file content is malformed or fails schema validation.
314
325
  */
315
326
  declare function loadOBF(file: File): Promise<OBFBoard>;
316
327
  /**
317
328
  * Validate an unknown value against the OBF board schema.
318
329
  *
319
- * @throws {Error} If the value does not conform to the schema.
330
+ * @param data - The value to validate.
331
+ * @returns The validated board object.
332
+ *
333
+ * @throws {Error} If the value does not conform to the OBF schema.
320
334
  */
321
335
  declare function validateOBF(data: unknown): OBFBoard;
322
336
  /**
323
- * Serialize an OBF board to a pretty-printed JSON string.
337
+ * Stringify an OBF board to a pretty-printed JSON string.
338
+ *
339
+ * @param board - The board to stringify.
340
+ * @returns A JSON string with two-space indentation.
324
341
  */
325
342
  declare function stringifyOBF(board: OBFBoard): string;
326
343
  //#endregion
327
344
  //#region src/obz.d.ts
345
+ /**
346
+ * Fully extracted contents of an `.obz` archive.
347
+ *
348
+ * @property manifest - The package table of contents.
349
+ * @property boards - Board ID → validated board object.
350
+ * @property resources - Archive path → raw binary content (images, sounds, etc.).
351
+ */
328
352
  interface ParsedOBZ {
329
353
  manifest: OBFManifest;
330
354
  boards: Map<string, OBFBoard>;
331
355
  resources: Map<string, Uint8Array>;
332
356
  }
333
357
  /**
334
- * Load an OBZ archive from a user-selected file.
358
+ * Read a `File` and extract its contents as a parsed OBZ package.
359
+ *
360
+ * This relies on the browser `File` API; for Node environments,
361
+ * read the file to an `ArrayBuffer` and pass it to {@link extractOBZ} instead.
362
+ *
363
+ * @param file - A `File` handle pointing to an `.obz` archive.
364
+ * @returns The parsed manifest, boards, and binary resources.
365
+ *
366
+ * @throws {Error} If the file is not a valid ZIP or the manifest is missing.
335
367
  */
336
368
  declare function loadOBZ(file: File): Promise<ParsedOBZ>;
337
369
  /**
338
- * Extract boards and resources from a raw OBZ archive.
370
+ * Decompress an OBZ archive and return its manifest, boards, and resources.
371
+ *
372
+ * @param archive - The OBZ archive as an `ArrayBuffer`.
373
+ * @returns The parsed manifest, a map of board IDs to validated boards,
374
+ * and a map of file paths to their binary content.
375
+ *
376
+ * @throws {Error} If the archive is not a valid ZIP or the manifest is missing.
339
377
  */
340
378
  declare function extractOBZ(archive: ArrayBuffer): Promise<ParsedOBZ>;
341
379
  /**
342
- * Parse and validate a manifest JSON string.
380
+ * Parse and validate an OBZ manifest the table of contents that maps
381
+ * board IDs to their file paths within the archive.
382
+ *
383
+ * @param json - A JSON string representing the manifest.
384
+ * @returns The validated manifest object.
385
+ *
386
+ * @throws {Error} If the JSON is malformed or fails schema validation.
343
387
  */
344
388
  declare function parseManifest(json: string): OBFManifest;
345
389
  /**
346
- * Bundle boards and optional resources into a downloadable OBZ archive.
390
+ * Bundle boards and optional resources into a compressed OBZ archive.
391
+ *
392
+ * A manifest is generated automatically from the supplied boards,
393
+ * using the `rootBoardId` to designate the entry-point board.
394
+ *
395
+ * @param boards - The boards to include in the archive.
396
+ * @param rootBoardId - The ID of the board that serves as the archive's entry point.
397
+ * @param resources - Optional map of file paths to binary content (images, sounds, etc.).
398
+ * @returns A `Blob` containing the compressed OBZ archive.
399
+ *
400
+ * @throws {Error} If `rootBoardId` does not match any of the supplied boards.
347
401
  */
348
402
  declare function createOBZ(boards: OBFBoard[], rootBoardId: string, resources?: Map<string, Uint8Array | ArrayBuffer>): Promise<Blob>;
349
403
  //#endregion
@@ -351,22 +405,31 @@ declare function createOBZ(boards: OBFBoard[], rootBoardId: string, resources?:
351
405
  /**
352
406
  * Decompress a ZIP archive into a map of file paths to raw bytes.
353
407
  *
354
- * @param archive - The raw ZIP bytes to decompress.
408
+ * @param archive - The ZIP archive as an `ArrayBuffer`.
409
+ * @returns A map of file paths to their decompressed content.
410
+ *
411
+ * @throws {Error} If decompression fails.
355
412
  */
356
413
  declare function unzip(archive: ArrayBuffer): Promise<Map<string, Uint8Array>>;
357
414
  /**
358
415
  * Compress a map of file paths and contents into a single ZIP archive.
359
416
  *
360
417
  * Accepts both `Uint8Array` and `ArrayBuffer` values so callers can
361
- * pass the output of `unzip` directly or supply raw `ArrayBuffer`s
418
+ * pass the output of {@link unzip} directly or supply raw `ArrayBuffer`s
362
419
  * without converting first.
363
420
  *
364
421
  * @param entries - A map of file paths to their content bytes.
422
+ * @returns The compressed archive as a `Uint8Array`.
423
+ *
424
+ * @throws {Error} If compression fails.
365
425
  */
366
426
  declare function zip(entries: Map<string, Uint8Array | ArrayBuffer>): Promise<Uint8Array>;
367
427
  /**
368
- * Test whether an `ArrayBuffer` begins with the 2-byte ZIP
369
- * magic prefix (`PK`).
428
+ * Test whether an `ArrayBuffer` begins with the two-byte ZIP magic
429
+ * prefix (`PK`).
430
+ *
431
+ * @param archive - The buffer to inspect.
432
+ * @returns `true` if the buffer starts with the ZIP signature.
370
433
  */
371
434
  declare function isZip(archive: ArrayBuffer): boolean;
372
435
  //#endregion
package/dist/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  import { z } from "zod";
2
2
  import { unzip as unzip$1, zip as zip$1 } from "fflate";
3
-
4
3
  //#region src/schema.ts
5
4
  /**
6
5
  * Open Board Format (OBF) Zod Schemas
@@ -22,7 +21,7 @@ const OBFOptionalIDSchema = z.union([z.string(), z.number()]).transform((val) =>
22
21
  const str = String(val);
23
22
  return str === "" ? void 0 : str;
24
23
  }).optional();
25
- /** Unique identifier as a string. Must be a non-empty string or number (coerced to string). */
24
+ /** Unique board-element identifier, coerced to a non-empty string. */
26
25
  const OBFIDSchema = z.union([z.string(), z.number()]).transform((val) => String(val)).pipe(z.string().min(1));
27
26
  /**
28
27
  * Format version of the Open Board Format, e.g., 'open-board-0.1'.
@@ -33,37 +32,43 @@ const OBFFormatVersionSchema = z.string().regex(/^open-board-.+$/);
33
32
  */
34
33
  const OBFLocaleCodeSchema = z.string();
35
34
  /**
36
- * Mapping of string keys to localized string values.
35
+ * Key–value pairs mapping symbolic names to their translations in a single locale.
37
36
  */
38
37
  const OBFLocalizedStringsSchema = z.record(z.string(), z.string());
39
38
  /**
40
- * String translations for multiple locales.
39
+ * Locale-keyed dictionary of translated strings,
40
+ * e.g., `{ en: { greeting: "Hello" }, fr: { greeting: "Bonjour" } }`.
41
41
  */
42
42
  const OBFStringsSchema = z.record(z.string(), OBFLocalizedStringsSchema);
43
43
  /**
44
- * Represents custom actions for spelling.
45
- * Prefixed with '+' followed by the text to append.
44
+ * Spelling action: a `+` prefix followed by the text to append,
45
+ * e.g., `"+hello"`.
46
46
  */
47
47
  const OBFSpellingActionSchema = z.string().regex(/^\+.+$/);
48
48
  /**
49
- * Represents specialty actions.
50
- * Standard actions are prefixed with ':'.
51
- * Custom actions start with ':ext_'.
49
+ * Specialty action prefixed with `:`, e.g., `":clear"`.
50
+ * Custom extensions use the `:ext_` prefix.
52
51
  */
53
52
  const OBFSpecialtyActionSchema = z.string().regex(/^:[a-z][a-z0-9_-]*$/i);
54
53
  /**
55
- * Possible actions associated with a button.
54
+ * Union of spelling and specialty actions that a button can trigger.
56
55
  */
57
56
  const OBFButtonActionSchema = z.union([OBFSpellingActionSchema, OBFSpecialtyActionSchema]);
58
57
  /**
59
- * Licensing information for a resource.
58
+ * License terms and attribution for a resource.
60
59
  */
61
60
  const OBFLicenseSchema = z.object({
61
+ /** Type of the license, e.g., 'CC-BY-SA'. */
62
62
  type: z.string(),
63
+ /** URL to the license terms. */
63
64
  copyright_notice_url: OBFOptionalUrlSchema,
65
+ /** Source URL of the resource. */
64
66
  source_url: OBFOptionalUrlSchema,
67
+ /** Name of the author. */
65
68
  author_name: z.string().optional(),
69
+ /** URL of the author's webpage. */
66
70
  author_url: OBFOptionalUrlSchema,
71
+ /** Email address of the author. */
67
72
  author_email: OBFOptionalEmailSchema
68
73
  });
69
74
  /**
@@ -75,106 +80,161 @@ const OBFLicenseSchema = z.object({
75
80
  * 3. url
76
81
  */
77
82
  const OBFMediaSchema = z.object({
83
+ /** Unique identifier for the media resource. */
78
84
  id: OBFIDSchema,
85
+ /** Data URI containing the media data. */
79
86
  data: z.string().optional(),
87
+ /** Path to the media file within an .obz package. */
80
88
  path: z.string().optional(),
89
+ /** Data URL to fetch the media programmatically. */
81
90
  data_url: OBFOptionalUrlSchema,
91
+ /** URL to the media resource. */
82
92
  url: OBFOptionalUrlSchema,
93
+ /** MIME type of the media, e.g., 'image/png', 'audio/mpeg'. */
83
94
  content_type: z.string().optional(),
95
+ /** Licensing information for the media. */
84
96
  license: OBFLicenseSchema.optional()
85
97
  });
86
98
  /**
87
- * Information about a symbol from a proprietary symbol set.
99
+ * Reference to a symbol in a proprietary symbol set (e.g., SymbolStix).
88
100
  */
89
101
  const OBFSymbolInfoSchema = z.object({
102
+ /** Name of the symbol set, e.g., 'symbolstix'. */
90
103
  set: z.string(),
104
+ /** Filename of the symbol within the set. */
91
105
  filename: z.string()
92
106
  });
93
107
  /**
94
- * Represents an image resource.
108
+ * Image resource, extending {@link OBFMediaSchema} with optional
109
+ * symbol and dimension properties.
95
110
  *
96
- * When resolving the image, if multiple references are provided, they should be used in the following order:
97
- * 1. data
98
- * 2. path
99
- * 3. url
100
- * 4. symbol
111
+ * When resolving the image, consumers should prefer sources in this order:
112
+ * 1. `data`
113
+ * 2. `path`
114
+ * 3. `url`
115
+ * 4. `symbol`
101
116
  */
102
117
  const OBFImageSchema = OBFMediaSchema.and(z.object({
118
+ /** Information about a symbol from a proprietary symbol set. */
103
119
  symbol: OBFSymbolInfoSchema.optional(),
120
+ /** Width of the image in pixels. */
104
121
  width: z.number().optional(),
122
+ /** Height of the image in pixels. */
105
123
  height: z.number().optional()
106
124
  }));
107
125
  /**
108
- * Represents a sound resource.
126
+ * Audio resource. Identical to {@link OBFMediaSchema} — no additional properties.
109
127
  */
110
128
  const OBFSoundSchema = OBFMediaSchema;
111
129
  /**
112
- * Information needed to load another board.
130
+ * Reference to another board, resolved by ID, path, or URL.
113
131
  */
114
132
  const OBFLoadBoardSchema = z.object({
133
+ /** Unique identifier of the board to load. */
115
134
  id: OBFOptionalIDSchema,
135
+ /** Name of the board to load. */
116
136
  name: z.string().optional(),
137
+ /** Data URL to fetch the board programmatically. */
117
138
  data_url: OBFOptionalUrlSchema,
139
+ /** URL to access the board via a web browser. */
118
140
  url: OBFOptionalUrlSchema,
141
+ /** Path to the board within an .obz package. */
119
142
  path: z.string().optional()
120
143
  });
121
144
  /**
122
- * Represents a button on the board.
145
+ * Interactive element on a board, optionally linked to images, sounds, and actions.
123
146
  */
124
147
  const OBFButtonSchema = z.object({
148
+ /** Unique identifier for the button. */
125
149
  id: OBFIDSchema,
150
+ /** Label text displayed on the button. */
126
151
  label: z.string().optional(),
152
+ /** Alternative text for vocalization when the button is activated. */
127
153
  vocalization: z.string().optional(),
154
+ /** Identifier of the image associated with the button. */
128
155
  image_id: OBFOptionalIDSchema,
156
+ /** Identifier of the sound associated with the button. */
129
157
  sound_id: OBFOptionalIDSchema,
158
+ /** Action associated with the button. */
130
159
  action: OBFButtonActionSchema.optional(),
160
+ /** List of multiple actions for the button, executed in order. */
131
161
  actions: z.array(OBFButtonActionSchema).optional(),
162
+ /** Information to load another board when this button is activated. */
132
163
  load_board: OBFLoadBoardSchema.optional(),
164
+ /** Background color of the button in 'rgb' or 'rgba' format. */
133
165
  background_color: z.string().optional(),
166
+ /** Border color of the button in 'rgb' or 'rgba' format. */
134
167
  border_color: z.string().optional(),
168
+ /** Vertical position for absolute positioning (0.0 to 1.0). */
135
169
  top: z.number().min(0).max(1).optional(),
170
+ /** Horizontal position for absolute positioning (0.0 to 1.0). */
136
171
  left: z.number().min(0).max(1).optional(),
172
+ /** Width of the button for absolute positioning (0.0 to 1.0). */
137
173
  width: z.number().min(0).max(1).optional(),
174
+ /** Height of the button for absolute positioning (0.0 to 1.0). */
138
175
  height: z.number().min(0).max(1).optional()
139
176
  });
140
177
  /**
141
- * Grid layout information for the board.
178
+ * Row-and-column layout that arranges buttons by their IDs.
142
179
  */
143
180
  const OBFGridSchema = z.object({
181
+ /** Number of rows in the grid. */
144
182
  rows: z.number().int().min(1),
183
+ /** Number of columns in the grid. */
145
184
  columns: z.number().int().min(1),
185
+ /**
186
+ * 2D array representing the order of buttons by their IDs.
187
+ * Each sub-array corresponds to a row, and each element is a button ID or null for empty slots.
188
+ */
146
189
  order: z.array(z.array(z.union([OBFIDSchema, z.null()])))
147
190
  }).refine((g) => g.order.length === g.rows, { message: "Grid order length must match rows" }).refine((g) => g.order.every((row) => row.length === g.columns), { message: "Each grid row must have length equal to columns" });
148
191
  /**
149
- * Represents the root object of an OBF file, defining the structure and layout of a board.
192
+ * Root object of an `.obf` file: the complete definition of a single communication board.
150
193
  */
151
194
  const OBFBoardSchema = z.object({
195
+ /** Format version of the Open Board Format, e.g., 'open-board-0.1'. */
152
196
  format: OBFFormatVersionSchema,
197
+ /** Unique identifier for the board. */
153
198
  id: OBFIDSchema,
199
+ /** Locale of the board as a BCP 47 language tag, e.g., 'en', 'en-US'. */
154
200
  locale: OBFLocaleCodeSchema.optional(),
201
+ /** List of buttons on the board. */
155
202
  buttons: z.array(OBFButtonSchema),
203
+ /** URL where the board can be accessed or downloaded. */
156
204
  url: OBFOptionalUrlSchema,
205
+ /** Name of the board. */
157
206
  name: z.string().optional(),
207
+ /** Description of the board in HTML format. */
158
208
  description_html: z.string().optional(),
209
+ /** Grid layout information for arranging buttons. */
159
210
  grid: OBFGridSchema,
211
+ /** List of images used in the board. */
160
212
  images: z.array(OBFImageSchema).optional(),
213
+ /** List of sounds used in the board. */
161
214
  sounds: z.array(OBFSoundSchema).optional(),
215
+ /** Licensing information for the board. */
162
216
  license: OBFLicenseSchema.optional(),
217
+ /** String translations for multiple locales. */
163
218
  strings: OBFStringsSchema.optional()
164
219
  });
165
220
  /**
166
- * Manifest file in an .obz package.
221
+ * Table of contents for an `.obz` package, mapping resource IDs to their archive paths.
167
222
  */
168
223
  const OBFManifestSchema = z.object({
224
+ /** Format version of the Open Board Format, e.g., 'open-board-0.1'. */
169
225
  format: OBFFormatVersionSchema,
226
+ /** Path to the root board within the .obz package. */
170
227
  root: z.string(),
228
+ /** Mapping of IDs to paths for boards, images, and sounds. */
171
229
  paths: z.object({
230
+ /** Mapping of board IDs to their file paths. */
172
231
  boards: z.record(z.string(), z.string()),
232
+ /** Mapping of image IDs to their file paths. */
173
233
  images: z.record(z.string(), z.string()),
234
+ /** Mapping of sound IDs to their file paths. */
174
235
  sounds: z.record(z.string(), z.string()).optional()
175
236
  })
176
237
  });
177
-
178
238
  //#endregion
179
239
  //#region src/obf.ts
180
240
  const UTF8_BOM = "";
@@ -190,8 +250,13 @@ function buildParseErrorMessage(error) {
190
250
  /**
191
251
  * Parse a JSON string into a validated OBF board.
192
252
  *
193
- * Handles an optional UTF-8 BOM prefix and throws a descriptive
194
- * error if the input is malformed or fails schema validation.
253
+ * Strips an optional UTF-8 BOM prefix before parsing and throws a
254
+ * descriptive error if the input is malformed or fails schema validation.
255
+ *
256
+ * @param json - The JSON string to parse.
257
+ * @returns The validated board object.
258
+ *
259
+ * @throws {Error} If the JSON is malformed or does not conform to the OBF schema.
195
260
  */
196
261
  function parseOBF(json) {
197
262
  const sanitized = stripBom(json);
@@ -204,10 +269,15 @@ function parseOBF(json) {
204
269
  return validateOBF(rawBoard);
205
270
  }
206
271
  /**
207
- * Read a `File` handle and parse its contents as an OBF board.
272
+ * Read a `File` and parse its contents as a validated OBF board.
208
273
  *
209
274
  * This relies on the browser `File` API; for Node environments,
210
275
  * read the file to a string and pass it to {@link parseOBF} instead.
276
+ *
277
+ * @param file - A `File` handle pointing to an `.obf` file.
278
+ * @returns The validated board object.
279
+ *
280
+ * @throws {Error} If the file content is malformed or fails schema validation.
211
281
  */
212
282
  async function loadOBF(file) {
213
283
  return parseOBF(await file.text());
@@ -215,7 +285,10 @@ async function loadOBF(file) {
215
285
  /**
216
286
  * Validate an unknown value against the OBF board schema.
217
287
  *
218
- * @throws {Error} If the value does not conform to the schema.
288
+ * @param data - The value to validate.
289
+ * @returns The validated board object.
290
+ *
291
+ * @throws {Error} If the value does not conform to the OBF schema.
219
292
  */
220
293
  function validateOBF(data) {
221
294
  const result = OBFBoardSchema.safeParse(data);
@@ -223,12 +296,14 @@ function validateOBF(data) {
223
296
  return result.data;
224
297
  }
225
298
  /**
226
- * Serialize an OBF board to a pretty-printed JSON string.
299
+ * Stringify an OBF board to a pretty-printed JSON string.
300
+ *
301
+ * @param board - The board to stringify.
302
+ * @returns A JSON string with two-space indentation.
227
303
  */
228
304
  function stringifyOBF(board) {
229
305
  return JSON.stringify(board, null, 2);
230
306
  }
231
-
232
307
  //#endregion
233
308
  //#region src/zip.ts
234
309
  /**
@@ -244,7 +319,10 @@ const COMPRESSION_LEVEL = 6;
244
319
  /**
245
320
  * Decompress a ZIP archive into a map of file paths to raw bytes.
246
321
  *
247
- * @param archive - The raw ZIP bytes to decompress.
322
+ * @param archive - The ZIP archive as an `ArrayBuffer`.
323
+ * @returns A map of file paths to their decompressed content.
324
+ *
325
+ * @throws {Error} If decompression fails.
248
326
  */
249
327
  function unzip(archive) {
250
328
  return new Promise((resolve, reject) => {
@@ -261,10 +339,13 @@ function unzip(archive) {
261
339
  * Compress a map of file paths and contents into a single ZIP archive.
262
340
  *
263
341
  * Accepts both `Uint8Array` and `ArrayBuffer` values so callers can
264
- * pass the output of `unzip` directly or supply raw `ArrayBuffer`s
342
+ * pass the output of {@link unzip} directly or supply raw `ArrayBuffer`s
265
343
  * without converting first.
266
344
  *
267
345
  * @param entries - A map of file paths to their content bytes.
346
+ * @returns The compressed archive as a `Uint8Array`.
347
+ *
348
+ * @throws {Error} If compression fails.
268
349
  */
269
350
  function zip(entries) {
270
351
  return new Promise((resolve, reject) => {
@@ -280,24 +361,40 @@ function zip(entries) {
280
361
  });
281
362
  }
282
363
  /**
283
- * Test whether an `ArrayBuffer` begins with the 2-byte ZIP
284
- * magic prefix (`PK`).
364
+ * Test whether an `ArrayBuffer` begins with the two-byte ZIP magic
365
+ * prefix (`PK`).
366
+ *
367
+ * @param archive - The buffer to inspect.
368
+ * @returns `true` if the buffer starts with the ZIP signature.
285
369
  */
286
370
  function isZip(archive) {
287
371
  const bytes = new Uint8Array(archive);
288
372
  return bytes.length >= ZIP_MAGIC.length && ZIP_MAGIC.every((byte, index) => bytes[index] === byte);
289
373
  }
290
-
291
374
  //#endregion
292
375
  //#region src/obz.ts
293
376
  /**
294
- * Load an OBZ archive from a user-selected file.
377
+ * Read a `File` and extract its contents as a parsed OBZ package.
378
+ *
379
+ * This relies on the browser `File` API; for Node environments,
380
+ * read the file to an `ArrayBuffer` and pass it to {@link extractOBZ} instead.
381
+ *
382
+ * @param file - A `File` handle pointing to an `.obz` archive.
383
+ * @returns The parsed manifest, boards, and binary resources.
384
+ *
385
+ * @throws {Error} If the file is not a valid ZIP or the manifest is missing.
295
386
  */
296
387
  async function loadOBZ(file) {
297
388
  return extractOBZ(await file.arrayBuffer());
298
389
  }
299
390
  /**
300
- * Extract boards and resources from a raw OBZ archive.
391
+ * Decompress an OBZ archive and return its manifest, boards, and resources.
392
+ *
393
+ * @param archive - The OBZ archive as an `ArrayBuffer`.
394
+ * @returns The parsed manifest, a map of board IDs to validated boards,
395
+ * and a map of file paths to their binary content.
396
+ *
397
+ * @throws {Error} If the archive is not a valid ZIP or the manifest is missing.
301
398
  */
302
399
  async function extractOBZ(archive) {
303
400
  if (!isZip(archive)) throw new Error("Invalid OBZ: not a ZIP file");
@@ -310,7 +407,13 @@ async function extractOBZ(archive) {
310
407
  };
311
408
  }
312
409
  /**
313
- * Parse and validate a manifest JSON string.
410
+ * Parse and validate an OBZ manifest the table of contents that maps
411
+ * board IDs to their file paths within the archive.
412
+ *
413
+ * @param json - A JSON string representing the manifest.
414
+ * @returns The validated manifest object.
415
+ *
416
+ * @throws {Error} If the JSON is malformed or fails schema validation.
314
417
  */
315
418
  function parseManifest(json) {
316
419
  let data;
@@ -324,7 +427,17 @@ function parseManifest(json) {
324
427
  return result.data;
325
428
  }
326
429
  /**
327
- * Bundle boards and optional resources into a downloadable OBZ archive.
430
+ * Bundle boards and optional resources into a compressed OBZ archive.
431
+ *
432
+ * A manifest is generated automatically from the supplied boards,
433
+ * using the `rootBoardId` to designate the entry-point board.
434
+ *
435
+ * @param boards - The boards to include in the archive.
436
+ * @param rootBoardId - The ID of the board that serves as the archive's entry point.
437
+ * @param resources - Optional map of file paths to binary content (images, sounds, etc.).
438
+ * @returns A `Blob` containing the compressed OBZ archive.
439
+ *
440
+ * @throws {Error} If `rootBoardId` does not match any of the supplied boards.
328
441
  */
329
442
  async function createOBZ(boards, rootBoardId, resources) {
330
443
  const entries = /* @__PURE__ */ new Map();
@@ -363,6 +476,5 @@ function extractBoards(manifest, entries) {
363
476
  }
364
477
  return boards;
365
478
  }
366
-
367
479
  //#endregion
368
- export { OBFBoardSchema, OBFButtonActionSchema, OBFButtonSchema, OBFFormatVersionSchema, OBFGridSchema, OBFIDSchema, OBFImageSchema, OBFLicenseSchema, OBFLoadBoardSchema, OBFLocaleCodeSchema, OBFLocalizedStringsSchema, OBFManifestSchema, OBFMediaSchema, OBFSoundSchema, OBFSpecialtyActionSchema, OBFSpellingActionSchema, OBFStringsSchema, OBFSymbolInfoSchema, createOBZ, extractOBZ, isZip, loadOBF, loadOBZ, parseManifest, parseOBF, stringifyOBF, unzip, validateOBF, zip };
480
+ export { OBFBoardSchema, OBFButtonActionSchema, OBFButtonSchema, OBFFormatVersionSchema, OBFGridSchema, OBFIDSchema, OBFImageSchema, OBFLicenseSchema, OBFLoadBoardSchema, OBFLocaleCodeSchema, OBFLocalizedStringsSchema, OBFManifestSchema, OBFMediaSchema, OBFSoundSchema, OBFSpecialtyActionSchema, OBFSpellingActionSchema, OBFStringsSchema, OBFSymbolInfoSchema, createOBZ, extractOBZ, isZip, loadOBF, loadOBZ, parseManifest, parseOBF, stringifyOBF, unzip, validateOBF, zip };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "open-board-format",
3
3
  "type": "module",
4
- "version": "1.0.3",
4
+ "version": "1.0.5",
5
5
  "description": "Parse, validate, and create Open Board Format (OBF/OBZ) files for AAC applications.",
6
6
  "author": "Shay Cojocaru <shayc@outlook.com>",
7
7
  "license": "MIT",
@@ -35,14 +35,14 @@
35
35
  "prepublishOnly": "npm run build"
36
36
  },
37
37
  "devDependencies": {
38
- "@types/node": "^25.3.0",
39
- "bumpp": "^10.4.1",
40
- "tsdown": "^0.20.3",
41
- "typescript": "^5.9.3",
42
- "vitest": "^4.0.18"
38
+ "@types/node": "^25.7.0",
39
+ "bumpp": "^11.1.0",
40
+ "tsdown": "^0.22.0",
41
+ "typescript": "~6.0.3",
42
+ "vitest": "^4.1.6"
43
43
  },
44
44
  "dependencies": {
45
45
  "fflate": "^0.8.2",
46
- "zod": "^4.3.6"
46
+ "zod": "^4.4.3"
47
47
  }
48
48
  }