@willwade/aac-processors 0.0.30 → 0.1.0

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 (92) hide show
  1. package/README.md +52 -852
  2. package/dist/browser/core/baseProcessor.js +241 -0
  3. package/dist/browser/core/stringCasing.js +179 -0
  4. package/dist/browser/core/treeStructure.js +255 -0
  5. package/dist/browser/index.browser.js +73 -0
  6. package/dist/browser/processors/applePanelsProcessor.js +582 -0
  7. package/dist/browser/processors/astericsGridProcessor.js +1509 -0
  8. package/dist/browser/processors/dotProcessor.js +221 -0
  9. package/dist/browser/processors/gridset/commands.js +962 -0
  10. package/dist/browser/processors/gridset/crypto.js +53 -0
  11. package/dist/browser/processors/gridset/password.js +43 -0
  12. package/dist/browser/processors/gridset/pluginTypes.js +277 -0
  13. package/dist/browser/processors/gridset/resolver.js +137 -0
  14. package/dist/browser/processors/gridset/symbolAlignment.js +276 -0
  15. package/dist/browser/processors/gridset/symbols.js +421 -0
  16. package/dist/browser/processors/gridsetProcessor.js +2002 -0
  17. package/dist/browser/processors/obfProcessor.js +705 -0
  18. package/dist/browser/processors/opmlProcessor.js +274 -0
  19. package/dist/browser/types/aac.js +38 -0
  20. package/dist/browser/utilities/analytics/utils/idGenerator.js +89 -0
  21. package/dist/browser/utilities/translation/translationProcessor.js +200 -0
  22. package/dist/browser/utils/io.js +95 -0
  23. package/dist/browser/validation/baseValidator.js +156 -0
  24. package/dist/browser/validation/gridsetValidator.js +355 -0
  25. package/dist/browser/validation/obfValidator.js +500 -0
  26. package/dist/browser/validation/validationTypes.js +46 -0
  27. package/dist/cli/index.js +5 -5
  28. package/dist/core/analyze.d.ts +2 -2
  29. package/dist/core/analyze.js +2 -2
  30. package/dist/core/baseProcessor.d.ts +5 -4
  31. package/dist/core/baseProcessor.js +22 -27
  32. package/dist/core/treeStructure.d.ts +5 -5
  33. package/dist/core/treeStructure.js +1 -4
  34. package/dist/index.browser.d.ts +37 -0
  35. package/dist/index.browser.js +99 -0
  36. package/dist/index.d.ts +1 -48
  37. package/dist/index.js +1 -136
  38. package/dist/index.node.d.ts +48 -0
  39. package/dist/index.node.js +152 -0
  40. package/dist/processors/applePanelsProcessor.d.ts +5 -4
  41. package/dist/processors/applePanelsProcessor.js +58 -62
  42. package/dist/processors/astericsGridProcessor.d.ts +7 -6
  43. package/dist/processors/astericsGridProcessor.js +31 -42
  44. package/dist/processors/dotProcessor.d.ts +5 -4
  45. package/dist/processors/dotProcessor.js +25 -33
  46. package/dist/processors/excelProcessor.d.ts +4 -3
  47. package/dist/processors/excelProcessor.js +6 -3
  48. package/dist/processors/gridset/crypto.d.ts +18 -0
  49. package/dist/processors/gridset/crypto.js +57 -0
  50. package/dist/processors/gridset/helpers.d.ts +1 -1
  51. package/dist/processors/gridset/helpers.js +18 -8
  52. package/dist/processors/gridset/password.d.ts +20 -3
  53. package/dist/processors/gridset/password.js +17 -3
  54. package/dist/processors/gridset/wordlistHelpers.d.ts +3 -3
  55. package/dist/processors/gridset/wordlistHelpers.js +21 -20
  56. package/dist/processors/gridsetProcessor.d.ts +7 -12
  57. package/dist/processors/gridsetProcessor.js +116 -77
  58. package/dist/processors/obfProcessor.d.ts +9 -7
  59. package/dist/processors/obfProcessor.js +131 -56
  60. package/dist/processors/obfsetProcessor.d.ts +5 -4
  61. package/dist/processors/obfsetProcessor.js +10 -16
  62. package/dist/processors/opmlProcessor.d.ts +5 -4
  63. package/dist/processors/opmlProcessor.js +27 -34
  64. package/dist/processors/snapProcessor.d.ts +8 -7
  65. package/dist/processors/snapProcessor.js +15 -12
  66. package/dist/processors/touchchatProcessor.d.ts +8 -7
  67. package/dist/processors/touchchatProcessor.js +22 -17
  68. package/dist/types/aac.d.ts +0 -2
  69. package/dist/types/aac.js +2 -0
  70. package/dist/utils/io.d.ts +12 -0
  71. package/dist/utils/io.js +107 -0
  72. package/dist/validation/gridsetValidator.js +7 -7
  73. package/dist/validation/snapValidator.js +28 -35
  74. package/docs/BROWSER_USAGE.md +618 -0
  75. package/examples/README.md +77 -0
  76. package/examples/browser-test-server.js +81 -0
  77. package/examples/browser-test.html +331 -0
  78. package/examples/vitedemo/QUICKSTART.md +74 -0
  79. package/examples/vitedemo/README.md +157 -0
  80. package/examples/vitedemo/index.html +376 -0
  81. package/examples/vitedemo/package-lock.json +1221 -0
  82. package/examples/vitedemo/package.json +18 -0
  83. package/examples/vitedemo/src/main.ts +519 -0
  84. package/examples/vitedemo/test-files/example.dot +14 -0
  85. package/examples/vitedemo/test-files/example.grd +1 -0
  86. package/examples/vitedemo/test-files/example.gridset +0 -0
  87. package/examples/vitedemo/test-files/example.obz +0 -0
  88. package/examples/vitedemo/test-files/example.opml +18 -0
  89. package/examples/vitedemo/test-files/simple.obf +53 -0
  90. package/examples/vitedemo/tsconfig.json +24 -0
  91. package/examples/vitedemo/vite.config.ts +34 -0
  92. package/package.json +20 -4
@@ -1,16 +1,59 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
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;
4
24
  };
5
25
  Object.defineProperty(exports, "__esModule", { value: true });
6
26
  exports.ObfProcessor = void 0;
7
27
  const baseProcessor_1 = require("../core/baseProcessor");
8
28
  const treeStructure_1 = require("../core/treeStructure");
9
29
  const idGenerator_1 = require("../utilities/analytics/utils/idGenerator");
10
- const adm_zip_1 = __importDefault(require("adm-zip"));
11
- const fs_1 = __importDefault(require("fs"));
12
- const obfValidator_1 = require("../validation/obfValidator");
13
30
  const translationProcessor_1 = require("../utilities/translation/translationProcessor");
31
+ const io_1 = require("../utils/io");
32
+ let JSZipModuleObf;
33
+ async function getJSZipObf() {
34
+ if (!JSZipModuleObf) {
35
+ try {
36
+ // Try ES module import first (browser/Vite)
37
+ const module = await Promise.resolve().then(() => __importStar(require('jszip')));
38
+ JSZipModuleObf = module.default || module;
39
+ }
40
+ catch (error) {
41
+ // Fall back to CommonJS require (Node.js)
42
+ try {
43
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
44
+ const module = require('jszip');
45
+ JSZipModuleObf = module.default || module;
46
+ }
47
+ catch (err2) {
48
+ throw new Error('Zip handling requires JSZip in this environment.');
49
+ }
50
+ }
51
+ }
52
+ if (!JSZipModuleObf) {
53
+ throw new Error('Zip handling requires JSZip in this environment.');
54
+ }
55
+ return JSZipModuleObf;
56
+ }
14
57
  const OBF_FORMAT_VERSION = 'open-board-0.1';
15
58
  /**
16
59
  * Map OBF hidden value to AAC standard visibility
@@ -31,7 +74,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
31
74
  /**
32
75
  * Extract an image from the ZIP file as a Buffer
33
76
  */
34
- extractImageAsBuffer(imageId, images) {
77
+ async extractImageAsBuffer(imageId, images) {
35
78
  if (!this.zipFile || !images) {
36
79
  return null;
37
80
  }
@@ -48,9 +91,10 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
48
91
  ].filter(Boolean);
49
92
  for (const imagePath of possiblePaths) {
50
93
  try {
51
- const entry = this.zipFile.getEntry(imagePath);
52
- if (entry) {
53
- return entry.getData(); // Return raw Buffer
94
+ const file = this.zipFile.file(imagePath);
95
+ if (file) {
96
+ const buffer = await file.async('nodebuffer');
97
+ return buffer;
54
98
  }
55
99
  }
56
100
  catch (err) {
@@ -62,7 +106,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
62
106
  /**
63
107
  * Extract an image from the ZIP file and convert to data URL
64
108
  */
65
- extractImageAsDataUrl(imageId, images) {
109
+ async extractImageAsDataUrl(imageId, images) {
66
110
  // Check cache first
67
111
  if (this.imageCache.has(imageId)) {
68
112
  return this.imageCache.get(imageId) ?? null;
@@ -84,12 +128,12 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
84
128
  ].filter(Boolean);
85
129
  for (const imagePath of possiblePaths) {
86
130
  try {
87
- const entry = this.zipFile.getEntry(imagePath);
88
- if (entry) {
89
- const buffer = entry.getData();
131
+ const file = this.zipFile.file(imagePath);
132
+ if (file) {
133
+ const buffer = await file.async('uint8array');
90
134
  const contentType = imageData.content_type ||
91
135
  this.getMimeTypeFromFilename(imagePath);
92
- const dataUrl = `data:${contentType};base64,${buffer.toString('base64')}`;
136
+ const dataUrl = `data:${contentType};base64,${(0, io_1.encodeBase64)(buffer)}`;
93
137
  this.imageCache.set(imageId, dataUrl);
94
138
  return dataUrl;
95
139
  }
@@ -125,7 +169,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
125
169
  return 'image/png';
126
170
  }
127
171
  }
128
- processBoard(boardData, _boardPath) {
172
+ async processBoard(boardData, _boardPath) {
129
173
  const sourceButtons = boardData.buttons || [];
130
174
  // Calculate page ID first (used to make button IDs unique)
131
175
  const pageId = _boardPath && _boardPath.endsWith('.obf') && !_boardPath.includes('/')
@@ -133,7 +177,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
133
177
  : boardData?.id
134
178
  ? String(boardData.id)
135
179
  : _boardPath?.split('/').pop() || '';
136
- const buttons = sourceButtons.map((btn) => {
180
+ const buttons = await Promise.all(sourceButtons.map(async (btn) => {
137
181
  const semanticAction = btn.load_board
138
182
  ? {
139
183
  category: treeStructure_1.AACSemanticCategory.NAVIGATION,
@@ -157,8 +201,10 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
157
201
  let resolvedImage;
158
202
  let imageBuffer;
159
203
  if (btn.image_id && boardData.images) {
160
- resolvedImage = this.extractImageAsDataUrl(btn.image_id, boardData.images) || undefined;
161
- imageBuffer = this.extractImageAsBuffer(btn.image_id, boardData.images) || undefined;
204
+ resolvedImage =
205
+ (await this.extractImageAsDataUrl(btn.image_id, boardData.images)) || undefined;
206
+ imageBuffer =
207
+ (await this.extractImageAsBuffer(btn.image_id, boardData.images)) || undefined;
162
208
  }
163
209
  // Build parameters object for Grid3 export compatibility
164
210
  const buttonParameters = {};
@@ -186,7 +232,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
186
232
  targetPageId: btn.load_board?.path,
187
233
  semantic_id: btn.semantic_id, // Extract semantic_id if present
188
234
  });
189
- });
235
+ }));
190
236
  const buttonMap = new Map(buttons.map((btn) => [btn.id, btn]));
191
237
  const page = new treeStructure_1.AACPage({
192
238
  id: pageId, // Use the page ID we calculated earlier
@@ -269,8 +315,8 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
269
315
  }
270
316
  return page;
271
317
  }
272
- extractTexts(filePathOrBuffer) {
273
- const tree = this.loadIntoTree(filePathOrBuffer);
318
+ async extractTexts(filePathOrBuffer) {
319
+ const tree = await this.loadIntoTree(filePathOrBuffer);
274
320
  const texts = [];
275
321
  for (const pageId in tree.pages) {
276
322
  const page = tree.pages[pageId];
@@ -285,20 +331,23 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
285
331
  }
286
332
  return texts;
287
333
  }
288
- loadIntoTree(filePathOrBuffer) {
334
+ async loadIntoTree(filePathOrBuffer) {
289
335
  // Detailed logging for debugging input
336
+ const bufferLength = typeof filePathOrBuffer === 'string'
337
+ ? null
338
+ : (0, io_1.readBinaryFromInput)(filePathOrBuffer).byteLength;
290
339
  console.log('[OBF] loadIntoTree called with:', {
291
340
  type: typeof filePathOrBuffer,
292
- isBuffer: Buffer.isBuffer(filePathOrBuffer),
341
+ isBuffer: typeof Buffer !== 'undefined' && Buffer.isBuffer(filePathOrBuffer),
293
342
  value: typeof filePathOrBuffer === 'string'
294
343
  ? filePathOrBuffer
295
- : '[Buffer of length ' + filePathOrBuffer.length + ']',
344
+ : `[Buffer of length ${bufferLength ?? 0}]`,
296
345
  });
297
346
  const tree = new treeStructure_1.AACTree();
298
347
  // Helper: try to parse JSON OBF
299
348
  function tryParseObfJson(data) {
300
349
  try {
301
- const str = typeof data === 'string' ? data : data.toString('utf8');
350
+ const str = typeof data === 'string' ? data : (0, io_1.readTextFromInput)(data);
302
351
  // Check for empty or whitespace-only content
303
352
  if (!str.trim()) {
304
353
  return null;
@@ -320,11 +369,11 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
320
369
  // If input is a string path and ends with .obf, treat as JSON
321
370
  if (typeof filePathOrBuffer === 'string' && filePathOrBuffer.endsWith('.obf')) {
322
371
  try {
323
- const content = fs_1.default.readFileSync(filePathOrBuffer, 'utf8');
372
+ const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
324
373
  const boardData = tryParseObfJson(content);
325
374
  if (boardData) {
326
375
  console.log('[OBF] Detected .obf file, parsed as JSON');
327
- const page = this.processBoard(boardData, filePathOrBuffer);
376
+ const page = await this.processBoard(boardData, filePathOrBuffer);
328
377
  tree.addPage(page);
329
378
  // Set metadata from root board
330
379
  tree.metadata.format = 'obf';
@@ -352,7 +401,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
352
401
  const asJson = tryParseObfJson(filePathOrBuffer);
353
402
  if (asJson) {
354
403
  console.log('[OBF] Detected buffer/string as OBF JSON');
355
- const page = this.processBoard(asJson, '[bufferOrString]');
404
+ const page = await this.processBoard(asJson, '[bufferOrString]');
356
405
  tree.addPage(page);
357
406
  // Set metadata from root board
358
407
  tree.metadata.format = 'obf';
@@ -372,32 +421,42 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
372
421
  function isLikelyZip(input) {
373
422
  if (typeof input === 'string')
374
423
  return input.endsWith('.zip') || input.endsWith('.obz');
375
- if (Buffer.isBuffer(input) && input.length >= 2) {
376
- return input[0] === 0x50 && input[1] === 0x4b; // 'PK'
377
- }
378
- return false;
424
+ const bytes = (0, io_1.readBinaryFromInput)(input);
425
+ return bytes.length >= 2 && bytes[0] === 0x50 && bytes[1] === 0x4b;
379
426
  }
380
427
  if (!isLikelyZip(filePathOrBuffer)) {
381
428
  throw new Error('Invalid OBF content: not JSON and not ZIP');
382
429
  }
430
+ const JSZip = await getJSZipObf();
383
431
  let zip;
384
432
  try {
385
- zip = new adm_zip_1.default(filePathOrBuffer);
433
+ const zipInput = (0, io_1.readBinaryFromInput)(filePathOrBuffer);
434
+ zip = await JSZip.loadAsync(zipInput);
386
435
  }
387
436
  catch (err) {
388
- console.error('[OBF] Error instantiating AdmZip with input:', err);
437
+ console.error('[OBF] Error loading ZIP with JSZip:', err);
389
438
  throw err;
390
439
  }
391
440
  // Store the ZIP file reference for image extraction
392
441
  this.zipFile = zip;
393
442
  this.imageCache.clear(); // Clear cache for new file
394
443
  console.log('[OBF] Detected zip archive, extracting .obf files');
395
- zip.getEntries().forEach((entry) => {
396
- if (entry.entryName.endsWith('.obf')) {
397
- const content = entry.getData().toString('utf8');
444
+ // Collect all .obf entries
445
+ const obfEntries = [];
446
+ zip.forEach((relativePath, file) => {
447
+ if (file.dir)
448
+ return;
449
+ if (relativePath.endsWith('.obf')) {
450
+ obfEntries.push({ name: relativePath, file });
451
+ }
452
+ });
453
+ // Process each .obf entry
454
+ for (const entry of obfEntries) {
455
+ try {
456
+ const content = await entry.file.async('string');
398
457
  const boardData = tryParseObfJson(content);
399
458
  if (boardData) {
400
- const page = this.processBoard(boardData, entry.entryName);
459
+ const page = await this.processBoard(boardData, entry.name);
401
460
  tree.addPage(page);
402
461
  // Set metadata if not already set (use first board as reference)
403
462
  if (!tree.metadata.format) {
@@ -414,10 +473,13 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
414
473
  }
415
474
  }
416
475
  else {
417
- console.warn('[OBF] Skipped entry (not valid OBF JSON):', entry.entryName);
476
+ console.warn('[OBF] Skipped entry (not valid OBF JSON):', entry.name);
418
477
  }
419
478
  }
420
- });
479
+ catch (err) {
480
+ console.warn('[OBF] Error processing entry:', entry.name, err);
481
+ }
482
+ }
421
483
  return tree;
422
484
  }
423
485
  buildGridMetadata(page) {
@@ -497,9 +559,9 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
497
559
  sounds: Array.isArray(page.sounds) ? page.sounds : [],
498
560
  };
499
561
  }
500
- processTexts(filePathOrBuffer, translations, outputPath) {
562
+ async processTexts(filePathOrBuffer, translations, outputPath) {
501
563
  // Load the tree, apply translations, and save to new file
502
- const tree = this.loadIntoTree(filePathOrBuffer);
564
+ const tree = await this.loadIntoTree(filePathOrBuffer);
503
565
  // Apply translations to all text content
504
566
  Object.values(tree.pages).forEach((page) => {
505
567
  // Translate page names
@@ -526,10 +588,10 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
526
588
  });
527
589
  });
528
590
  // Save the translated tree and return its content
529
- this.saveFromTree(tree, outputPath);
530
- return fs_1.default.readFileSync(outputPath);
591
+ await this.saveFromTree(tree, outputPath);
592
+ return (0, io_1.readBinaryFromInput)(outputPath);
531
593
  }
532
- saveFromTree(tree, outputPath) {
594
+ async saveFromTree(tree, outputPath) {
533
595
  if (outputPath.endsWith('.obf')) {
534
596
  // Save as single OBF JSON file
535
597
  const rootPage = tree.rootId ? tree.getPage(tree.rootId) : Object.values(tree.pages)[0];
@@ -537,17 +599,20 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
537
599
  throw new Error('No pages to save');
538
600
  }
539
601
  const obfBoard = this.createObfBoardFromPage(rootPage, 'Exported Board', tree.metadata);
540
- fs_1.default.writeFileSync(outputPath, JSON.stringify(obfBoard, null, 2));
602
+ (0, io_1.writeTextToPath)(outputPath, JSON.stringify(obfBoard, null, 2));
541
603
  }
542
604
  else {
543
605
  // Save as OBZ (zip with multiple OBF files)
544
- const zip = new adm_zip_1.default();
606
+ const JSZip = await getJSZipObf();
607
+ const zip = new JSZip();
545
608
  Object.values(tree.pages).forEach((page) => {
546
609
  const obfBoard = this.createObfBoardFromPage(page, 'Board', tree.metadata);
547
610
  const obfContent = JSON.stringify(obfBoard, null, 2);
548
- zip.addFile(`${page.id}.obf`, Buffer.from(obfContent, 'utf8'));
611
+ zip.file(`${page.id}.obf`, obfContent);
549
612
  });
550
- zip.writeZip(outputPath);
613
+ const zipBuffer = await zip.generateAsync({ type: 'uint8array' });
614
+ const { writeBinaryToPath } = await Promise.resolve().then(() => __importStar(require('../utils/io')));
615
+ writeBinaryToPath(outputPath, zipBuffer);
551
616
  }
552
617
  }
553
618
  /**
@@ -570,7 +635,8 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
570
635
  * @returns Promise with validation result
571
636
  */
572
637
  async validate(filePath) {
573
- return obfValidator_1.ObfValidator.validateFile(filePath);
638
+ const ObfValidator = this.getObfValidator();
639
+ return ObfValidator.validateFile(filePath);
574
640
  }
575
641
  /**
576
642
  * Extract symbol information from an OBF/OBZ file for LLM-based translation.
@@ -581,8 +647,8 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
581
647
  * @param filePathOrBuffer - Path to OBF/OBZ file or buffer
582
648
  * @returns Array of symbol information for LLM processing
583
649
  */
584
- extractSymbolsForLLM(filePathOrBuffer) {
585
- const tree = this.loadIntoTree(filePathOrBuffer);
650
+ async extractSymbolsForLLM(filePathOrBuffer) {
651
+ const tree = await this.loadIntoTree(filePathOrBuffer);
586
652
  // Collect all buttons from all pages
587
653
  const allButtons = [];
588
654
  Object.values(tree.pages).forEach((page) => {
@@ -611,8 +677,8 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
611
677
  * @param options - Translation options (e.g., allowPartial for testing)
612
678
  * @returns Buffer of the translated OBF/OBZ file
613
679
  */
614
- processLLMTranslations(filePathOrBuffer, llmTranslations, outputPath, options) {
615
- const tree = this.loadIntoTree(filePathOrBuffer);
680
+ async processLLMTranslations(filePathOrBuffer, llmTranslations, outputPath, options) {
681
+ const tree = await this.loadIntoTree(filePathOrBuffer);
616
682
  // Validate translations using shared utility
617
683
  const buttonIds = Object.values(tree.pages).flatMap((page) => page.buttons.map((b) => b.id));
618
684
  (0, translationProcessor_1.validateTranslationResults)(llmTranslations, buttonIds, options);
@@ -649,8 +715,17 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
649
715
  });
650
716
  });
651
717
  // Save and return
652
- this.saveFromTree(tree, outputPath);
653
- return fs_1.default.readFileSync(outputPath);
718
+ await this.saveFromTree(tree, outputPath);
719
+ return (0, io_1.readBinaryFromInput)(outputPath);
720
+ }
721
+ getObfValidator() {
722
+ try {
723
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-return
724
+ return require('../validation/obfValidator').ObfValidator;
725
+ }
726
+ catch (error) {
727
+ throw new Error('Validation utilities are not available in this environment.');
728
+ }
654
729
  }
655
730
  }
656
731
  exports.ObfProcessor = ObfProcessor;
@@ -4,23 +4,24 @@
4
4
  */
5
5
  import { AACTree } from '../core/treeStructure';
6
6
  import { BaseProcessor, ProcessorOptions } from '../core/baseProcessor';
7
+ import { ProcessorInput } from '../utils/io';
7
8
  export declare class ObfsetProcessor extends BaseProcessor {
8
9
  constructor(options?: ProcessorOptions);
9
10
  /**
10
11
  * Extract all text content
11
12
  */
12
- extractTexts(filePathOrBuffer: string | Buffer): string[];
13
+ extractTexts(filePathOrBuffer: ProcessorInput): Promise<string[]>;
13
14
  /**
14
15
  * Load an .obfset file (JSON array of boards)
15
16
  */
16
- loadIntoTree(filePathOrBuffer: string | Buffer): AACTree;
17
+ loadIntoTree(filePathOrBuffer: ProcessorInput): Promise<AACTree>;
17
18
  /**
18
19
  * Process texts (not supported for .obfset currently)
19
20
  */
20
- processTexts(_filePathOrBuffer: string | Buffer, _translations: Map<string, string>, _outputPath: string): Buffer;
21
+ processTexts(_filePathOrBuffer: ProcessorInput, _translations: Map<string, string>, _outputPath: string): Promise<Uint8Array>;
21
22
  /**
22
23
  * Save tree structure back to file
23
24
  */
24
- saveFromTree(_tree: AACTree, _outputPath: string): void;
25
+ saveFromTree(_tree: AACTree, _outputPath: string): Promise<void>;
25
26
  supportsExtension(extension: string): boolean;
26
27
  }
@@ -3,15 +3,12 @@
3
3
  * OBF Set Processor - Handles JSON-formatted .obfset files
4
4
  * These are pre-extracted board sets in JSON array format
5
5
  */
6
- var __importDefault = (this && this.__importDefault) || function (mod) {
7
- return (mod && mod.__esModule) ? mod : { "default": mod };
8
- };
9
6
  Object.defineProperty(exports, "__esModule", { value: true });
10
7
  exports.ObfsetProcessor = void 0;
11
8
  const treeStructure_1 = require("../core/treeStructure");
12
9
  const treeStructure_2 = require("../core/treeStructure");
13
- const fs_1 = __importDefault(require("fs"));
14
10
  const baseProcessor_1 = require("../core/baseProcessor");
11
+ const io_1 = require("../utils/io");
15
12
  class ObfsetProcessor extends baseProcessor_1.BaseProcessor {
16
13
  constructor(options = {}) {
17
14
  super(options);
@@ -19,8 +16,8 @@ class ObfsetProcessor extends baseProcessor_1.BaseProcessor {
19
16
  /**
20
17
  * Extract all text content
21
18
  */
22
- extractTexts(filePathOrBuffer) {
23
- const tree = this.loadIntoTree(filePathOrBuffer);
19
+ async extractTexts(filePathOrBuffer) {
20
+ const tree = await this.loadIntoTree(filePathOrBuffer);
24
21
  const texts = new Set();
25
22
  Object.values(tree.pages).forEach((page) => {
26
23
  if (page.name)
@@ -35,16 +32,11 @@ class ObfsetProcessor extends baseProcessor_1.BaseProcessor {
35
32
  /**
36
33
  * Load an .obfset file (JSON array of boards)
37
34
  */
38
- loadIntoTree(filePathOrBuffer) {
35
+ async loadIntoTree(filePathOrBuffer) {
36
+ await Promise.resolve();
39
37
  const tree = new treeStructure_1.AACTree();
40
38
  tree.metadata.format = 'obfset';
41
- let content;
42
- if (Buffer.isBuffer(filePathOrBuffer)) {
43
- content = filePathOrBuffer.toString('utf-8');
44
- }
45
- else {
46
- content = fs_1.default.readFileSync(filePathOrBuffer, 'utf-8');
47
- }
39
+ const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
48
40
  const boards = JSON.parse(content);
49
41
  // Track board ID mappings
50
42
  const boardMap = new Map();
@@ -164,13 +156,15 @@ class ObfsetProcessor extends baseProcessor_1.BaseProcessor {
164
156
  /**
165
157
  * Process texts (not supported for .obfset currently)
166
158
  */
167
- processTexts(_filePathOrBuffer, _translations, _outputPath) {
159
+ async processTexts(_filePathOrBuffer, _translations, _outputPath) {
160
+ await Promise.resolve();
168
161
  throw new Error('processTexts is not supported for .obfset currently');
169
162
  }
170
163
  /**
171
164
  * Save tree structure back to file
172
165
  */
173
- saveFromTree(_tree, _outputPath) {
166
+ async saveFromTree(_tree, _outputPath) {
167
+ await Promise.resolve();
174
168
  throw new Error('saveFromTree is not supported for .obfset currently');
175
169
  }
176
170
  supportsExtension(extension) {
@@ -1,12 +1,13 @@
1
1
  import { BaseProcessor, ProcessorOptions, ExtractStringsResult, TranslatedString, SourceString } from '../core/baseProcessor';
2
2
  import { AACTree } from '../core/treeStructure';
3
+ import { ProcessorInput } from '../utils/io';
3
4
  declare class OpmlProcessor extends BaseProcessor {
4
5
  constructor(options?: ProcessorOptions);
5
6
  private processOutline;
6
- extractTexts(filePathOrBuffer: string | Buffer): string[];
7
- loadIntoTree(filePathOrBuffer: string | Buffer): AACTree;
8
- processTexts(filePathOrBuffer: string | Buffer, translations: Map<string, string>, outputPath: string): Buffer;
9
- saveFromTree(tree: AACTree, outputPath: string): void;
7
+ extractTexts(filePathOrBuffer: ProcessorInput): Promise<string[]>;
8
+ loadIntoTree(filePathOrBuffer: ProcessorInput): Promise<AACTree>;
9
+ processTexts(filePathOrBuffer: ProcessorInput, translations: Map<string, string>, outputPath: string): Promise<Uint8Array>;
10
+ saveFromTree(tree: AACTree, outputPath: string): Promise<void>;
10
11
  /**
11
12
  * Extract strings with metadata for aac-tools-platform compatibility
12
13
  * Uses the generic implementation from BaseProcessor
@@ -1,16 +1,12 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.OpmlProcessor = void 0;
7
4
  const baseProcessor_1 = require("../core/baseProcessor");
8
5
  const treeStructure_1 = require("../core/treeStructure");
9
6
  // Removed unused import: FileProcessor
10
7
  const fast_xml_parser_1 = require("fast-xml-parser");
11
- const fs_1 = __importDefault(require("fs"));
12
- const path_1 = __importDefault(require("path"));
13
- const validation_1 = require("../validation");
8
+ const validationTypes_1 = require("../validation/validationTypes");
9
+ const io_1 = require("../utils/io");
14
10
  class OpmlProcessor extends baseProcessor_1.BaseProcessor {
15
11
  constructor(options) {
16
12
  super(options);
@@ -56,10 +52,9 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
56
52
  return { page: null, childPages: [] };
57
53
  return { page, childPages };
58
54
  }
59
- extractTexts(filePathOrBuffer) {
60
- const content = typeof filePathOrBuffer === 'string'
61
- ? fs_1.default.readFileSync(filePathOrBuffer, 'utf8')
62
- : filePathOrBuffer.toString('utf8');
55
+ async extractTexts(filePathOrBuffer) {
56
+ await Promise.resolve();
57
+ const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
63
58
  const parser = new fast_xml_parser_1.XMLParser({ ignoreAttributes: false });
64
59
  const data = parser.parse(content);
65
60
  const texts = [];
@@ -89,15 +84,14 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
89
84
  outlines.forEach(processNode);
90
85
  return texts;
91
86
  }
92
- loadIntoTree(filePathOrBuffer) {
93
- const filename = typeof filePathOrBuffer === 'string' ? path_1.default.basename(filePathOrBuffer) : 'upload.opml';
94
- const buffer = Buffer.isBuffer(filePathOrBuffer)
95
- ? filePathOrBuffer
96
- : fs_1.default.readFileSync(filePathOrBuffer);
97
- const content = buffer.toString('utf8');
87
+ async loadIntoTree(filePathOrBuffer) {
88
+ await Promise.resolve();
89
+ const filename = typeof filePathOrBuffer === 'string' ? (0, io_1.getBasename)(filePathOrBuffer) : 'upload.opml';
90
+ const buffer = (0, io_1.readBinaryFromInput)(filePathOrBuffer);
91
+ const content = (0, io_1.readTextFromInput)(buffer);
98
92
  try {
99
93
  if (!content || !content.trim()) {
100
- const validationResult = (0, validation_1.buildValidationResultFromMessage)({
94
+ const validationResult = (0, validationTypes_1.buildValidationResultFromMessage)({
101
95
  filename,
102
96
  filesize: buffer.byteLength,
103
97
  format: 'opml',
@@ -105,13 +99,13 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
105
99
  type: 'content',
106
100
  description: 'OPML content is empty',
107
101
  });
108
- throw new validation_1.ValidationFailureError('Empty OPML content', validationResult);
102
+ throw new validationTypes_1.ValidationFailureError('Empty OPML content', validationResult);
109
103
  }
110
104
  // Validate XML before parsing, fast-xml-parser is permissive by default
111
105
  const validationResult = fast_xml_parser_1.XMLValidator.validate(content);
112
106
  if (validationResult !== true) {
113
107
  const reason = validationResult?.err?.msg || JSON.stringify(validationResult);
114
- const structured = (0, validation_1.buildValidationResultFromMessage)({
108
+ const structured = (0, validationTypes_1.buildValidationResultFromMessage)({
115
109
  filename,
116
110
  filesize: buffer.byteLength,
117
111
  format: 'opml',
@@ -119,7 +113,7 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
119
113
  type: 'xml',
120
114
  description: 'OPML XML validation',
121
115
  });
122
- throw new validation_1.ValidationFailureError('Invalid OPML XML', structured);
116
+ throw new validationTypes_1.ValidationFailureError('Invalid OPML XML', structured);
123
117
  }
124
118
  const parser = new fast_xml_parser_1.XMLParser({ ignoreAttributes: false });
125
119
  const data = parser.parse(content);
@@ -128,7 +122,7 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
128
122
  // Handle case where body.outline might not exist or be in different formats
129
123
  const bodyOutline = data.opml?.body?.outline;
130
124
  if (!bodyOutline) {
131
- const structured = (0, validation_1.buildValidationResultFromMessage)({
125
+ const structured = (0, validationTypes_1.buildValidationResultFromMessage)({
132
126
  filename,
133
127
  filesize: buffer.byteLength,
134
128
  format: 'opml',
@@ -136,7 +130,7 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
136
130
  type: 'structure',
137
131
  description: 'OPML outline root',
138
132
  });
139
- throw new validation_1.ValidationFailureError('Invalid OPML structure', structured);
133
+ throw new validationTypes_1.ValidationFailureError('Invalid OPML structure', structured);
140
134
  }
141
135
  const outlines = Array.isArray(bodyOutline) ? bodyOutline : [bodyOutline];
142
136
  let firstRootId = null;
@@ -162,10 +156,10 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
162
156
  return tree;
163
157
  }
164
158
  catch (err) {
165
- if (err instanceof validation_1.ValidationFailureError) {
159
+ if (err instanceof validationTypes_1.ValidationFailureError) {
166
160
  throw err;
167
161
  }
168
- const validationResult = (0, validation_1.buildValidationResultFromMessage)({
162
+ const validationResult = (0, validationTypes_1.buildValidationResultFromMessage)({
169
163
  filename,
170
164
  filesize: buffer.byteLength,
171
165
  format: 'opml',
@@ -173,13 +167,12 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
173
167
  type: 'parse',
174
168
  description: 'Parse OPML XML',
175
169
  });
176
- throw new validation_1.ValidationFailureError('Failed to load OPML file', validationResult, err);
170
+ throw new validationTypes_1.ValidationFailureError('Failed to load OPML file', validationResult, err);
177
171
  }
178
172
  }
179
- processTexts(filePathOrBuffer, translations, outputPath) {
180
- const content = typeof filePathOrBuffer === 'string'
181
- ? fs_1.default.readFileSync(filePathOrBuffer, 'utf8')
182
- : filePathOrBuffer.toString('utf8');
173
+ async processTexts(filePathOrBuffer, translations, outputPath) {
174
+ await Promise.resolve();
175
+ const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
183
176
  let translatedContent = content;
184
177
  // Apply translations to text attributes in OPML outline elements
185
178
  translations.forEach((translation, originalText) => {
@@ -189,12 +182,12 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
189
182
  translatedContent = translatedContent.replace(textAttrRegex, `text="${translation}"`);
190
183
  }
191
184
  });
192
- const resultBuffer = Buffer.from(translatedContent, 'utf8');
193
- // Save to output path
194
- fs_1.default.writeFileSync(outputPath, resultBuffer);
185
+ const resultBuffer = (0, io_1.encodeText)(translatedContent);
186
+ (0, io_1.writeBinaryToPath)(outputPath, resultBuffer);
195
187
  return resultBuffer;
196
188
  }
197
- saveFromTree(tree, outputPath) {
189
+ async saveFromTree(tree, outputPath) {
190
+ await Promise.resolve();
198
191
  // Helper to recursively build outline nodes with cycle detection
199
192
  function buildOutline(page, visited = new Set()) {
200
193
  // Prevent infinite recursion by tracking visited pages
@@ -264,7 +257,7 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
264
257
  attributeNamePrefix: '@_',
265
258
  });
266
259
  const xml = '<?xml version="1.0" encoding="UTF-8"?>\n' + builder.build(opmlObj);
267
- fs_1.default.writeFileSync(outputPath, xml, 'utf8');
260
+ (0, io_1.writeTextToPath)(outputPath, xml);
268
261
  }
269
262
  /**
270
263
  * Extract strings with metadata for aac-tools-platform compatibility