@willwade/aac-processors 0.0.9 → 0.0.10

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 (56) hide show
  1. package/README.md +85 -11
  2. package/dist/cli/index.js +87 -0
  3. package/dist/core/analyze.js +1 -0
  4. package/dist/core/baseProcessor.d.ts +3 -0
  5. package/dist/core/fileProcessor.js +1 -0
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.js +3 -0
  8. package/dist/optional/symbolTools.js +4 -2
  9. package/dist/processors/gridset/helpers.d.ts +1 -1
  10. package/dist/processors/gridset/helpers.js +5 -3
  11. package/dist/processors/gridset/password.d.ts +11 -0
  12. package/dist/processors/gridset/password.js +37 -0
  13. package/dist/processors/gridset/resolver.d.ts +1 -1
  14. package/dist/processors/gridset/resolver.js +8 -4
  15. package/dist/processors/gridset/wordlistHelpers.d.ts +2 -2
  16. package/dist/processors/gridset/wordlistHelpers.js +7 -4
  17. package/dist/processors/gridsetProcessor.d.ts +15 -1
  18. package/dist/processors/gridsetProcessor.js +64 -22
  19. package/dist/processors/index.d.ts +1 -0
  20. package/dist/processors/index.js +5 -2
  21. package/dist/processors/obfProcessor.d.ts +7 -0
  22. package/dist/processors/obfProcessor.js +9 -0
  23. package/dist/processors/snapProcessor.d.ts +7 -0
  24. package/dist/processors/snapProcessor.js +9 -0
  25. package/dist/processors/touchchatProcessor.d.ts +7 -0
  26. package/dist/processors/touchchatProcessor.js +9 -0
  27. package/dist/utilities/screenshotConverter.d.ts +69 -0
  28. package/dist/utilities/screenshotConverter.js +453 -0
  29. package/dist/validation/baseValidator.d.ts +80 -0
  30. package/dist/validation/baseValidator.js +160 -0
  31. package/dist/validation/gridsetValidator.d.ts +36 -0
  32. package/dist/validation/gridsetValidator.js +288 -0
  33. package/dist/validation/index.d.ts +13 -0
  34. package/dist/validation/index.js +69 -0
  35. package/dist/validation/obfValidator.d.ts +44 -0
  36. package/dist/validation/obfValidator.js +530 -0
  37. package/dist/validation/snapValidator.d.ts +33 -0
  38. package/dist/validation/snapValidator.js +237 -0
  39. package/dist/validation/touchChatValidator.d.ts +33 -0
  40. package/dist/validation/touchChatValidator.js +229 -0
  41. package/dist/validation/validationTypes.d.ts +64 -0
  42. package/dist/validation/validationTypes.js +15 -0
  43. package/examples/README.md +7 -0
  44. package/examples/demo.js +143 -0
  45. package/examples/obf/aboutme.json +376 -0
  46. package/examples/obf/array.json +6 -0
  47. package/examples/obf/hash.json +4 -0
  48. package/examples/obf/links.obz +0 -0
  49. package/examples/obf/simple.obf +53 -0
  50. package/examples/package-lock.json +1326 -0
  51. package/examples/package.json +10 -0
  52. package/examples/styling-example.ts +316 -0
  53. package/examples/translate.js +39 -0
  54. package/examples/translate_demo.js +254 -0
  55. package/examples/typescript-demo.ts +251 -0
  56. package/package.json +3 -1
@@ -0,0 +1,530 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.ObfValidator = void 0;
30
+ /* eslint-disable @typescript-eslint/require-await */
31
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
32
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
33
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
34
+ /* eslint-disable @typescript-eslint/restrict-template-expressions */
35
+ const jszip_1 = __importDefault(require("jszip"));
36
+ const baseValidator_1 = require("./baseValidator");
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const OBF_FORMAT = 'open-board-0.1';
40
+ const OBF_FORMAT_CURRENT_VERSION = 0.1;
41
+ /**
42
+ * Validator for Open Board Format (OBF/OBZ) files
43
+ */
44
+ class ObfValidator extends baseValidator_1.BaseValidator {
45
+ constructor() {
46
+ super();
47
+ }
48
+ /**
49
+ * Validate an OBF file from disk
50
+ */
51
+ static async validateFile(filePath) {
52
+ const validator = new ObfValidator();
53
+ const content = fs.readFileSync(filePath);
54
+ const stats = fs.statSync(filePath);
55
+ return validator.validate(content, path.basename(filePath), stats.size);
56
+ }
57
+ /**
58
+ * Check if content is OBF format
59
+ */
60
+ static async identifyFormat(content, filename) {
61
+ const name = filename.toLowerCase();
62
+ if (name.endsWith('.obf') || name.endsWith('.obz')) {
63
+ return true;
64
+ }
65
+ // Try to parse as JSON and check format
66
+ try {
67
+ const contentStr = Buffer.isBuffer(content) ? content.toString() : content;
68
+ const json = JSON.parse(contentStr);
69
+ return json && json.format && json.format.startsWith('open-board-');
70
+ }
71
+ catch {
72
+ return false;
73
+ }
74
+ }
75
+ /**
76
+ * Main validation method
77
+ */
78
+ async validate(content, filename, filesize) {
79
+ this.reset();
80
+ // Determine if it's OBF or OBZ
81
+ const isObz = filename.toLowerCase().endsWith('.obz');
82
+ if (isObz) {
83
+ return await this.validateObz(content, filename, filesize);
84
+ }
85
+ else {
86
+ return await this.validateObf(content, filename, filesize);
87
+ }
88
+ }
89
+ /**
90
+ * Validate OBF content
91
+ */
92
+ async validateObf(content, filename, filesize) {
93
+ await this.add_check('filename', 'file name', async () => {
94
+ if (!filename.match(/\.obf$/)) {
95
+ this.warn('filename should end with .obf');
96
+ }
97
+ });
98
+ let json = null;
99
+ await this.add_check('valid_json', 'JSON file', async () => {
100
+ try {
101
+ json = JSON.parse(content.toString());
102
+ }
103
+ catch {
104
+ this.err("Couldn't parse as JSON", true);
105
+ }
106
+ });
107
+ if (!json) {
108
+ return this.buildResult(filename, filesize, 'obf');
109
+ }
110
+ await this.validateBoardStructure(json);
111
+ return this.buildResult(filename, filesize, 'obf');
112
+ }
113
+ /**
114
+ * Validate OBZ (zip) content
115
+ */
116
+ async validateObz(content, filename, filesize) {
117
+ await this.add_check('filename', 'file name', async () => {
118
+ if (!filename.match(/\.obz$/)) {
119
+ this.warn('filename should end with .obz');
120
+ }
121
+ });
122
+ let zip = null;
123
+ let validZip = false;
124
+ await this.add_check('zip', 'valid zip', async () => {
125
+ try {
126
+ zip = await jszip_1.default.loadAsync(content);
127
+ validZip = true;
128
+ }
129
+ catch {
130
+ this.err('file is not a valid zip package');
131
+ }
132
+ });
133
+ if (validZip && zip) {
134
+ await this.validateObzStructure(zip);
135
+ }
136
+ return this.buildResult(filename, filesize, 'obz');
137
+ }
138
+ /**
139
+ * Validate OBF board structure
140
+ */
141
+ async validateBoardStructure(board) {
142
+ await this.add_check('format_version', 'format version', async () => {
143
+ if (!board.format) {
144
+ this.err(`format attribute is required, set to ${OBF_FORMAT}`);
145
+ return;
146
+ }
147
+ const version = parseFloat(board.format.split('-').pop() || '0');
148
+ if (version > OBF_FORMAT_CURRENT_VERSION) {
149
+ this.err(`format version (${version}) is invalid, current version is ${OBF_FORMAT_CURRENT_VERSION}`);
150
+ }
151
+ else if (version < OBF_FORMAT_CURRENT_VERSION) {
152
+ this.warn(`format version (${version}) is old, consider updating to ${OBF_FORMAT_CURRENT_VERSION}`);
153
+ }
154
+ });
155
+ await this.add_check('id', 'board ID', async () => {
156
+ if (!board.id) {
157
+ this.err('id attribute is required');
158
+ }
159
+ });
160
+ await this.add_check('locale', 'locale', async () => {
161
+ if (!board.locale) {
162
+ this.err('locale attribute is required, please set to "en" for English');
163
+ }
164
+ });
165
+ await this.add_check('extras', 'extra attributes', async () => {
166
+ const attrs = [
167
+ 'format',
168
+ 'id',
169
+ 'locale',
170
+ 'url',
171
+ 'data_url',
172
+ 'name',
173
+ 'description_html',
174
+ 'default_layout',
175
+ 'buttons',
176
+ 'images',
177
+ 'sounds',
178
+ 'grid',
179
+ 'license',
180
+ ];
181
+ Object.keys(board).forEach((key) => {
182
+ if (!attrs.includes(key) && !key.startsWith('ext_')) {
183
+ this.warn(`${key} attribute is not defined in the spec, should be prefixed with ext_yourapp_`);
184
+ }
185
+ });
186
+ });
187
+ await this.add_check('description', 'descriptive attributes', async () => {
188
+ if (!board.name) {
189
+ this.warn('name attribute is strongly recommended');
190
+ }
191
+ if (!board.description_html) {
192
+ this.warn('description_html attribute is recommended');
193
+ }
194
+ });
195
+ await this.add_check('background', 'background attribute', async () => {
196
+ if (board.background && typeof board.background !== 'object') {
197
+ this.err('background attribute must be a hash');
198
+ }
199
+ });
200
+ await this.add_check('buttons', 'buttons attribute', async () => {
201
+ if (!board.buttons) {
202
+ this.err('buttons attribute is required');
203
+ }
204
+ else if (!Array.isArray(board.buttons)) {
205
+ this.err('buttons attribute must be an array');
206
+ }
207
+ });
208
+ await this.add_check('grid', 'grid attribute', async () => {
209
+ if (!board.grid) {
210
+ this.err('grid attribute is required');
211
+ return;
212
+ }
213
+ if (typeof board.grid !== 'object') {
214
+ this.err('grid attribute must be a hash');
215
+ return;
216
+ }
217
+ if (typeof board.grid.rows !== 'number' || board.grid.rows < 1) {
218
+ this.err('grid.rows must be a positive number');
219
+ }
220
+ if (typeof board.grid.columns !== 'number' || board.grid.columns < 1) {
221
+ this.err('grid.columns must be a positive number');
222
+ }
223
+ if (!board.grid.order || !Array.isArray(board.grid.order)) {
224
+ this.err('grid.order must be an array of arrays');
225
+ return;
226
+ }
227
+ if (board.grid.order.length !== board.grid.rows) {
228
+ this.err(`grid.order length (${board.grid.order.length}) must match grid.rows (${board.grid.rows})`);
229
+ }
230
+ if (!board.grid.order.every((r) => Array.isArray(r) && r.length === board.grid.columns)) {
231
+ this.err(`grid.order must contain ${board.grid.rows} arrays each of size ${board.grid.columns}`);
232
+ }
233
+ });
234
+ await this.add_check('grid_ids', 'button IDs in grid.order attribute', async () => {
235
+ const buttonIds = (board.buttons || []).map((b) => b.id);
236
+ const usedButtonIds = [];
237
+ if (board.grid && board.grid.order) {
238
+ board.grid.order.forEach((row) => {
239
+ if (Array.isArray(row)) {
240
+ row.forEach((id) => {
241
+ if (id !== null && id !== undefined) {
242
+ usedButtonIds.push(id);
243
+ if (!buttonIds.includes(id)) {
244
+ this.err(`grid.order references button with id ${id} but no button with that id found in buttons attribute`);
245
+ }
246
+ }
247
+ });
248
+ }
249
+ });
250
+ }
251
+ if (usedButtonIds.length === 0) {
252
+ this.warn('board has no buttons defined in the grid');
253
+ }
254
+ const unusedIds = buttonIds.filter((id) => !usedButtonIds.includes(id));
255
+ if (unusedIds.length > 0) {
256
+ this.warn(`not all defined buttons were included in the grid order (${unusedIds.join(',')})`);
257
+ }
258
+ });
259
+ await this.add_check('images', 'images attribute', async () => {
260
+ if (!board.images) {
261
+ this.err('images attribute is required');
262
+ }
263
+ else if (!Array.isArray(board.images)) {
264
+ this.err('images attribute must be an array');
265
+ }
266
+ });
267
+ if (Array.isArray(board.images)) {
268
+ for (let i = 0; i < board.images.length; i++) {
269
+ const image = board.images[i];
270
+ await this.add_check(`image[${i}]`, `image at images[${i}]`, async () => {
271
+ if (typeof image !== 'object') {
272
+ this.err('image must be a hash');
273
+ return;
274
+ }
275
+ if (!image.id) {
276
+ this.err('image.id is required');
277
+ }
278
+ if (!image.width || typeof image.width !== 'number' || image.width < 1) {
279
+ this.warn('image.width should be a valid positive number');
280
+ }
281
+ if (!image.height || typeof image.height !== 'number' || image.height < 1) {
282
+ this.warn('image.height should be a valid positive number');
283
+ }
284
+ if (!image.content_type || !image.content_type.match(/^image\/.+$/)) {
285
+ this.err('image.content_type must be a valid image mime type');
286
+ }
287
+ if (!image.url && !image.data && !image.symbol && !image.path) {
288
+ this.err('image must have data, url, path or symbol attribute defined');
289
+ }
290
+ const imageAttrs = [
291
+ 'id',
292
+ 'width',
293
+ 'height',
294
+ 'content_type',
295
+ 'data',
296
+ 'url',
297
+ 'symbol',
298
+ 'path',
299
+ 'data_url',
300
+ 'license',
301
+ ];
302
+ Object.keys(image).forEach((key) => {
303
+ if (!imageAttrs.includes(key) && !key.startsWith('ext_')) {
304
+ this.warn(`image.${key} attribute is not defined in the spec, should be prefixed with ext_yourapp_`);
305
+ }
306
+ });
307
+ });
308
+ }
309
+ }
310
+ await this.add_check('sounds', 'sounds attribute', async () => {
311
+ if (!board.sounds) {
312
+ this.err('sounds attribute is required');
313
+ }
314
+ else if (!Array.isArray(board.sounds)) {
315
+ this.err('sounds attribute must be an array');
316
+ }
317
+ });
318
+ if (Array.isArray(board.sounds)) {
319
+ for (let i = 0; i < board.sounds.length; i++) {
320
+ const sound = board.sounds[i];
321
+ await this.add_check(`sounds[${i}]`, `sound at sounds[${i}]`, async () => {
322
+ if (typeof sound !== 'object') {
323
+ this.err('sound must be a hash');
324
+ return;
325
+ }
326
+ if (!sound.id) {
327
+ this.err('sound.id is required');
328
+ }
329
+ if (sound.duration !== undefined &&
330
+ (typeof sound.duration !== 'number' || sound.duration < 0)) {
331
+ this.err('sound.duration must be a valid positive number');
332
+ }
333
+ if (!sound.content_type || !sound.content_type.match(/^audio\/.+$/)) {
334
+ this.err('sound.content_type must be a valid audio mime type');
335
+ }
336
+ if (!sound.url && !sound.data && !sound.path) {
337
+ this.err('sound must have data, url, or path attribute defined');
338
+ }
339
+ });
340
+ }
341
+ }
342
+ if (Array.isArray(board.buttons)) {
343
+ for (let i = 0; i < board.buttons.length; i++) {
344
+ const button = board.buttons[i];
345
+ await this.add_check(`buttons[${i}]`, `button at buttons[${i}]`, async () => {
346
+ await this.validateButton(button);
347
+ });
348
+ }
349
+ }
350
+ }
351
+ /**
352
+ * Validate a single button
353
+ */
354
+ async validateButton(button) {
355
+ if (typeof button !== 'object') {
356
+ this.err('button must be a hash');
357
+ return;
358
+ }
359
+ if (!button.id) {
360
+ this.err('button.id is required');
361
+ }
362
+ if (!button.label) {
363
+ this.err('button.label is required');
364
+ }
365
+ ['top', 'left', 'width', 'height'].forEach((attr) => {
366
+ if (button[attr] !== undefined && (typeof button[attr] !== 'number' || button[attr] < 0)) {
367
+ this.warn(`button.${attr} should be a positive number`);
368
+ }
369
+ });
370
+ ['background_color', 'border_color'].forEach((color) => {
371
+ if (button[color]) {
372
+ if (!button[color].match(/^\s*rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[01]?\.?\d*)?\)\s*/)) {
373
+ this.err(`button.${color} must be a valid rgb or rgba value if defined ("${button[color]}" is invalid)`);
374
+ }
375
+ }
376
+ });
377
+ if (button.hidden !== undefined && typeof button.hidden !== 'boolean') {
378
+ this.err('button.hidden must be a boolean if defined');
379
+ }
380
+ if (!button.image_id) {
381
+ this.warn('button.image_id is recommended');
382
+ }
383
+ if (button.action && typeof button.action === 'string' && !button.action.match(/^(:|\+)/)) {
384
+ this.err('button.action must start with either : or + if defined');
385
+ }
386
+ if (button.actions && !Array.isArray(button.actions)) {
387
+ this.err('button.actions must be an array of strings');
388
+ }
389
+ const buttonAttrs = [
390
+ 'id',
391
+ 'label',
392
+ 'vocalization',
393
+ 'image_id',
394
+ 'sound_id',
395
+ 'hidden',
396
+ 'background_color',
397
+ 'border_color',
398
+ 'action',
399
+ 'actions',
400
+ 'load_board',
401
+ 'top',
402
+ 'left',
403
+ 'width',
404
+ 'height',
405
+ ];
406
+ Object.keys(button).forEach((key) => {
407
+ if (!buttonAttrs.includes(key) && !key.startsWith('ext_')) {
408
+ this.warn(`button.${key} attribute is not defined in the spec, should be prefixed with ext_yourapp_`);
409
+ }
410
+ });
411
+ }
412
+ /**
413
+ * Validate OBZ structure
414
+ */
415
+ async validateObzStructure(zip) {
416
+ let json = null;
417
+ await this.add_check('manifest', 'manifest.json', async () => {
418
+ const manifestFile = zip.file('manifest.json');
419
+ if (!manifestFile) {
420
+ this.err('manifest.json is required in the zip package');
421
+ return;
422
+ }
423
+ try {
424
+ const manifestStr = await manifestFile.async('string');
425
+ json = JSON.parse(manifestStr);
426
+ }
427
+ catch {
428
+ json = null;
429
+ }
430
+ if (!json) {
431
+ this.err('manifest.json must contain a valid JSON structure');
432
+ }
433
+ });
434
+ if (json) {
435
+ await this.validateManifest(json, zip);
436
+ }
437
+ }
438
+ /**
439
+ * Validate manifest structure
440
+ */
441
+ async validateManifest(manifest, zip) {
442
+ await this.add_check('manifest_format', 'manifest.json format version', async () => {
443
+ if (!manifest.format) {
444
+ this.err(`format attribute is required, set to ${OBF_FORMAT}`);
445
+ return;
446
+ }
447
+ const version = parseFloat(manifest.format.split('-').pop());
448
+ if (version > OBF_FORMAT_CURRENT_VERSION) {
449
+ this.err(`format version (${version}) is invalid, current version is ${OBF_FORMAT_CURRENT_VERSION}`);
450
+ }
451
+ else if (version < OBF_FORMAT_CURRENT_VERSION) {
452
+ this.warn(`format version (${version}) is old, consider updating to ${OBF_FORMAT_CURRENT_VERSION}`);
453
+ }
454
+ });
455
+ await this.add_check('manifest_root', 'manifest.json root attribute', async () => {
456
+ if (!manifest.root) {
457
+ this.err('root attribute is required');
458
+ }
459
+ if (!zip.file(manifest.root)) {
460
+ this.err('root attribute must reference a file in the package');
461
+ }
462
+ });
463
+ await this.add_check('manifest_paths', 'manifest.json paths attribute', async () => {
464
+ if (!manifest.paths || typeof manifest.paths !== 'object') {
465
+ this.err('paths attribute must be a valid hash');
466
+ }
467
+ if (!manifest.paths.boards || typeof manifest.paths.boards !== 'object') {
468
+ this.err('paths.boards must be a valid hash');
469
+ }
470
+ });
471
+ await this.add_check('manifest_extras', 'manifest.json extra attributes', async () => {
472
+ const attrs = ['format', 'root', 'paths'];
473
+ Object.keys(manifest).forEach((key) => {
474
+ if (!attrs.includes(key) && !key.startsWith('ext_')) {
475
+ this.warn(`${key} attribute is not defined in the spec, should be prefixed with ext_yourapp_`);
476
+ }
477
+ });
478
+ const pathAttrs = ['boards', 'images', 'sounds'];
479
+ Object.keys(manifest.paths || {}).forEach((key) => {
480
+ if (!pathAttrs.includes(key) && !key.startsWith('ext_')) {
481
+ this.warn(`paths.${key} attribute is not defined in the spec, should be prefixed with ext_yourapp_`);
482
+ }
483
+ });
484
+ });
485
+ // Validate boards referenced in manifest
486
+ if (manifest.paths && manifest.paths.boards) {
487
+ for (const [id, boardPath] of Object.entries(manifest.paths.boards)) {
488
+ await this.add_check(`manifest_boards[${id}]`, `manifest.json path.boards.${id}`, async () => {
489
+ const bFile = zip.file(boardPath);
490
+ if (!bFile) {
491
+ this.err(`board path (${boardPath}) not found in the zip package`);
492
+ return;
493
+ }
494
+ try {
495
+ const boardStr = await bFile.async('string');
496
+ const boardJson = JSON.parse(boardStr);
497
+ if (!boardJson || boardJson.id !== id) {
498
+ const boardId = (boardJson && boardJson.id) || 'null';
499
+ this.err(`board at path (${boardPath}) defined in manifest with id "${id}" but actually has id "${boardId}"`);
500
+ }
501
+ }
502
+ catch {
503
+ this.err(`could not parse board at path (${boardPath})`);
504
+ }
505
+ });
506
+ }
507
+ }
508
+ // Validate images referenced in manifest
509
+ if (manifest.paths && manifest.paths.images) {
510
+ for (const [id, imgPath] of Object.entries(manifest.paths.images)) {
511
+ await this.add_check(`manifest_images[${id}]`, `manifest.json path.images.${id}`, async () => {
512
+ if (!zip.file(imgPath)) {
513
+ this.err(`image path (${imgPath}) not found in the zip package`);
514
+ }
515
+ });
516
+ }
517
+ }
518
+ // Validate sounds referenced in manifest
519
+ if (manifest.paths && manifest.paths.sounds) {
520
+ for (const [id, soundPath] of Object.entries(manifest.paths.sounds)) {
521
+ await this.add_check(`manifest_sounds[${id}]`, `manifest.json path.sounds.${id}`, async () => {
522
+ if (!zip.file(soundPath)) {
523
+ this.err(`sound path (${soundPath}) not found in the zip package`);
524
+ }
525
+ });
526
+ }
527
+ }
528
+ }
529
+ }
530
+ exports.ObfValidator = ObfValidator;
@@ -0,0 +1,33 @@
1
+ import { BaseValidator } from './baseValidator';
2
+ import { ValidationResult } from './validationTypes';
3
+ /**
4
+ * Validator for Snap files (.spb, .sps)
5
+ * Snap files are zipped packages containing XML configuration
6
+ */
7
+ export declare class SnapValidator extends BaseValidator {
8
+ constructor();
9
+ /**
10
+ * Validate a Snap file from disk
11
+ */
12
+ static validateFile(filePath: string): Promise<ValidationResult>;
13
+ /**
14
+ * Check if content is Snap format
15
+ */
16
+ static identifyFormat(content: any, filename: string): Promise<boolean>;
17
+ /**
18
+ * Main validation method
19
+ */
20
+ validate(content: Buffer | Uint8Array, filename: string, filesize: number): Promise<ValidationResult>;
21
+ /**
22
+ * Validate Snap package structure
23
+ */
24
+ private validateSnapStructure;
25
+ /**
26
+ * Validate the main settings file
27
+ */
28
+ private validateSettingsFile;
29
+ /**
30
+ * Validate a page file
31
+ */
32
+ private validatePageFile;
33
+ }