@willwade/aac-processors 0.0.29 → 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 +118 -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,19 +1,36 @@
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.GridsetProcessor = void 0;
7
27
  const baseProcessor_1 = require("../core/baseProcessor");
8
28
  const treeStructure_1 = require("../core/treeStructure");
9
- const adm_zip_1 = __importDefault(require("adm-zip"));
10
- const fs_1 = __importDefault(require("fs"));
11
29
  const fast_xml_parser_1 = require("fast-xml-parser");
12
30
  const resolver_1 = require("./gridset/resolver");
13
31
  const translationProcessor_1 = require("../utilities/translation/translationProcessor");
14
32
  const password_1 = require("./gridset/password");
15
- const crypto_1 = __importDefault(require("crypto"));
16
- const zlib_1 = __importDefault(require("zlib"));
33
+ const crypto_1 = require("./gridset/crypto");
17
34
  const gridsetValidator_1 = require("../validation/gridsetValidator");
18
35
  // New imports for enhanced Grid 3 support
19
36
  const pluginTypes_1 = require("./gridset/pluginTypes");
@@ -22,33 +39,35 @@ const symbols_1 = require("./gridset/symbols");
22
39
  const resolver_2 = require("./gridset/resolver");
23
40
  const idGenerator_1 = require("../utilities/analytics/utils/idGenerator");
24
41
  const symbolAlignment_1 = require("./gridset/symbolAlignment");
25
- class GridsetProcessor extends baseProcessor_1.BaseProcessor {
26
- constructor(options) {
27
- super(options);
28
- }
29
- /**
30
- * Decrypt and inflate a Grid3 encrypted payload (DesktopContentEncrypter).
31
- * Uses AES-256-CBC with key/IV derived from the password padded with spaces
32
- * and then Deflate decompression.
33
- */
34
- decryptGridsetEntry(buffer, password) {
35
- const pwd = (password || 'Chocolate').padEnd(32, ' ');
36
- const key = Buffer.from(pwd.slice(0, 32), 'utf8');
37
- const iv = Buffer.from(pwd.slice(0, 16), 'utf8');
42
+ const io_1 = require("../utils/io");
43
+ let JSZipModule;
44
+ async function getJSZip() {
45
+ if (!JSZipModule) {
38
46
  try {
39
- const decipher = crypto_1.default.createDecipheriv('aes-256-cbc', key, iv);
40
- const decrypted = Buffer.concat([decipher.update(buffer), decipher.final()]);
47
+ // Try ES module import first (browser/Vite)
48
+ const module = await Promise.resolve().then(() => __importStar(require('jszip')));
49
+ JSZipModule = module.default || module;
50
+ }
51
+ catch (error) {
52
+ // Fall back to CommonJS require (Node.js)
41
53
  try {
42
- return zlib_1.default.inflateSync(decrypted);
54
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
55
+ const module = require('jszip');
56
+ JSZipModule = module.default || module;
43
57
  }
44
- catch {
45
- // If data isn't deflated, return raw decrypted bytes
46
- return decrypted;
58
+ catch (err2) {
59
+ throw new Error('Zip handling requires JSZip in this environment.');
47
60
  }
48
61
  }
49
- catch {
50
- return buffer;
51
- }
62
+ }
63
+ if (!JSZipModule) {
64
+ throw new Error('Zip handling requires JSZip in this environment.');
65
+ }
66
+ return JSZipModule;
67
+ }
68
+ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
69
+ constructor(options) {
70
+ super(options);
52
71
  }
53
72
  // Determine password to use when opening encrypted gridset archives (.gridsetx)
54
73
  getGridsetPassword(source) {
@@ -394,8 +413,8 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
394
413
  }
395
414
  return undefined;
396
415
  }
397
- extractTexts(filePathOrBuffer) {
398
- const tree = this.loadIntoTree(filePathOrBuffer);
416
+ async extractTexts(filePathOrBuffer) {
417
+ const tree = await this.loadIntoTree(filePathOrBuffer);
399
418
  const texts = [];
400
419
  for (const pageId in tree.pages) {
401
420
  const page = tree.pages[pageId];
@@ -410,11 +429,13 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
410
429
  }
411
430
  return texts;
412
431
  }
413
- loadIntoTree(filePathOrBuffer) {
432
+ async loadIntoTree(filePathOrBuffer) {
414
433
  const tree = new treeStructure_1.AACTree();
415
434
  let zip;
416
435
  try {
417
- zip = new adm_zip_1.default(filePathOrBuffer);
436
+ const JSZip = await getJSZip();
437
+ const zipInput = (0, io_1.readBinaryFromInput)(filePathOrBuffer);
438
+ zip = await JSZip.loadAsync(zipInput);
418
439
  }
419
440
  catch (error) {
420
441
  throw new Error(`Invalid ZIP file format: ${error.message}`);
@@ -430,18 +451,22 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
430
451
  isSmartBox: isEncryptedArchive, // SmartBox files are .gridsetx encrypted archives
431
452
  passwordProtected: !!password,
432
453
  };
433
- const readEntryBuffer = (entry) => {
434
- const raw = entry.getData();
435
- if (!isEncryptedArchive)
454
+ const readEntryBuffer = async (entry) => {
455
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument
456
+ const raw = await entry.getData();
457
+ if (!isEncryptedArchive) {
458
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
436
459
  return raw;
437
- return this.decryptGridsetEntry(raw, encryptedContentPassword);
460
+ }
461
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return
462
+ return (0, crypto_1.decryptGridsetEntry)(raw, encryptedContentPassword);
438
463
  };
439
464
  // Parse FileMap.xml if present to index dynamic files per grid
440
465
  const fileMapIndex = new Map();
441
466
  try {
442
467
  const fmEntry = entries.find((e) => e.entryName.endsWith('FileMap.xml'));
443
468
  if (fmEntry) {
444
- const fmXml = readEntryBuffer(fmEntry).toString('utf8');
469
+ const fmXml = (0, io_1.decodeText)(await readEntryBuffer(fmEntry));
445
470
  const fmData = parser.parse(fmXml);
446
471
  const entries = fmData?.FileMap?.Entries?.Entry || fmData?.fileMap?.entries?.entry;
447
472
  if (entries) {
@@ -476,7 +501,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
476
501
  const styleEntry = entries.find((entry) => entry.entryName.endsWith('styles.xml') || entry.entryName.endsWith('style.xml'));
477
502
  if (styleEntry) {
478
503
  try {
479
- const styleXmlContent = readEntryBuffer(styleEntry).toString('utf8');
504
+ const styleXmlContent = (0, io_1.decodeText)(await readEntryBuffer(styleEntry));
480
505
  const styleData = parser.parse(styleXmlContent);
481
506
  // Parse styles and store them in the map
482
507
  // Grid3 uses StyleData.Styles.Style with Key attribute
@@ -507,18 +532,23 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
507
532
  }
508
533
  }
509
534
  // Debug: log all entry names
510
- // console.log('Gridset zip entries:', entries.map(e => e.entryName));
535
+ console.log('[Gridset] Total zip entries:', entries.length);
536
+ const gridEntries = entries.filter((e) => e.entryName.startsWith('Grids/') && e.entryName.endsWith('grid.xml'));
537
+ console.log('[Gridset] Grid XML entries found:', gridEntries.length);
538
+ if (gridEntries.length > 0) {
539
+ console.log('[Gridset] First few grid entries:', gridEntries.slice(0, 3).map((e) => e.entryName));
540
+ }
511
541
  // First pass: collect all grid names and IDs for navigation resolution
512
542
  const gridNameToIdMap = new Map();
513
543
  const gridIdToNameMap = new Map();
514
- entries.forEach((entry) => {
544
+ for (const entry of entries) {
515
545
  if (entry.entryName.startsWith('Grids/') && entry.entryName.endsWith('grid.xml')) {
516
546
  try {
517
- const xmlContent = readEntryBuffer(entry).toString('utf8');
547
+ const xmlContent = (0, io_1.decodeText)(await readEntryBuffer(entry));
518
548
  const data = parser.parse(xmlContent);
519
549
  const grid = data.Grid || data.grid;
520
550
  if (!grid)
521
- return;
551
+ continue;
522
552
  const gridId = this.textOf(grid.GridGuid || grid.gridGuid || grid.id);
523
553
  const gridName = this.textOf(grid.Name) || this.textOf(grid.name) || this.textOf(grid['@_Name']);
524
554
  const folderMatch = entry.entryName.match(/^Grids\/([^/]+)\//);
@@ -541,32 +571,36 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
541
571
  // Skip errors in first pass
542
572
  }
543
573
  }
544
- });
574
+ }
545
575
  // Second pass: process each grid file in the gridset
546
- entries.forEach((entry) => {
576
+ for (const entry of entries) {
547
577
  // Only process files named grid.xml under Grids/ (any subdir)
548
578
  if (entry.entryName.startsWith('Grids/') && entry.entryName.endsWith('grid.xml')) {
549
579
  let xmlContent;
550
580
  try {
551
- xmlContent = readEntryBuffer(entry).toString('utf8');
581
+ const buffer = await readEntryBuffer(entry);
582
+ xmlContent = (0, io_1.decodeText)(buffer);
583
+ console.log(`[Gridset] Raw XML content (first 200 chars) for ${entry.entryName}:`, xmlContent.substring(0, 200));
552
584
  }
553
585
  catch (e) {
554
586
  // Skip unreadable files
555
- return;
587
+ continue;
556
588
  }
557
589
  let data;
558
590
  try {
559
591
  data = parser.parse(xmlContent);
592
+ console.log(`[Gridset] Parsed ${entry.entryName}, root keys:`, Object.keys(data));
560
593
  }
561
594
  catch (error) {
562
595
  // Skip malformed XML but log the specific error
563
596
  console.warn(`Malformed XML in ${entry.entryName}: ${error.message}`);
564
- return;
597
+ continue;
565
598
  }
566
599
  // Grid3 XML: <Grid> root
567
600
  const grid = data.Grid || data.grid;
568
601
  if (!grid) {
569
- return;
602
+ console.warn(`[Gridset] No Grid/grid found in ${entry.entryName}`);
603
+ continue;
570
604
  }
571
605
  // Defensive: GridGuid and Name required
572
606
  const gridId = this.textOf(grid.GridGuid || grid.gridGuid || grid.id);
@@ -578,7 +612,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
578
612
  gridName = match[1];
579
613
  }
580
614
  if (!gridId || !gridName) {
581
- return;
615
+ continue;
582
616
  }
583
617
  const page = new treeStructure_1.AACPage({
584
618
  id: String(gridId),
@@ -1291,6 +1325,8 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1291
1325
  pluginMetadata.autoContentType === 'Prediction'
1292
1326
  ? predictionCellCounter
1293
1327
  : undefined,
1328
+ // Store page name for Grid3 image lookup
1329
+ gridPageName: gridName,
1294
1330
  },
1295
1331
  });
1296
1332
  // Add button to page
@@ -1332,7 +1368,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1332
1368
  }
1333
1369
  tree.addPage(page);
1334
1370
  }
1335
- });
1371
+ }
1336
1372
  // After all pages are loaded, set parentId for navigation targets
1337
1373
  for (const pageId in tree.pages) {
1338
1374
  const page = tree.pages[pageId];
@@ -1349,7 +1385,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1349
1385
  try {
1350
1386
  const settingsEntry = entries.find((e) => e.entryName.endsWith('settings.xml'));
1351
1387
  if (settingsEntry) {
1352
- const settingsXml = readEntryBuffer(settingsEntry).toString('utf8');
1388
+ const settingsXml = (0, io_1.decodeText)(await readEntryBuffer(settingsEntry));
1353
1389
  const settingsData = parser.parse(settingsXml);
1354
1390
  const gsName = settingsData?.GridSetSettings?.Name ||
1355
1391
  settingsData?.gridSetSettings?.name ||
@@ -1443,9 +1479,9 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1443
1479
  tree.metadata = metadata;
1444
1480
  return tree;
1445
1481
  }
1446
- processTexts(filePathOrBuffer, translations, outputPath) {
1482
+ async processTexts(filePathOrBuffer, translations, outputPath) {
1447
1483
  // Load the tree, apply translations, and save to new file
1448
- const tree = this.loadIntoTree(filePathOrBuffer);
1484
+ const tree = await this.loadIntoTree(filePathOrBuffer);
1449
1485
  // Apply translations to all text content
1450
1486
  Object.values(tree.pages).forEach((page) => {
1451
1487
  // Translate page names
@@ -1503,8 +1539,8 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1503
1539
  });
1504
1540
  });
1505
1541
  // Save the translated tree and return its content
1506
- this.saveFromTree(tree, outputPath);
1507
- return fs_1.default.readFileSync(outputPath);
1542
+ await this.saveFromTree(tree, outputPath);
1543
+ return (0, io_1.readBinaryFromInput)(outputPath);
1508
1544
  }
1509
1545
  /**
1510
1546
  * Extract symbol information from a gridset for LLM-based translation.
@@ -1515,8 +1551,8 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1515
1551
  * @param filePathOrBuffer - Path to gridset file or buffer
1516
1552
  * @returns Array of symbol information for LLM processing
1517
1553
  */
1518
- extractSymbolsForLLM(filePathOrBuffer) {
1519
- const tree = this.loadIntoTree(filePathOrBuffer);
1554
+ async extractSymbolsForLLM(filePathOrBuffer) {
1555
+ const tree = await this.loadIntoTree(filePathOrBuffer);
1520
1556
  // Collect all buttons from all pages
1521
1557
  const allButtons = [];
1522
1558
  Object.values(tree.pages).forEach((page) => {
@@ -1545,8 +1581,8 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1545
1581
  * @param options - Translation options (e.g., allowPartial for testing)
1546
1582
  * @returns Buffer of the translated gridset
1547
1583
  */
1548
- processLLMTranslations(filePathOrBuffer, llmTranslations, outputPath, options) {
1549
- const tree = this.loadIntoTree(filePathOrBuffer);
1584
+ async processLLMTranslations(filePathOrBuffer, llmTranslations, outputPath, options) {
1585
+ const tree = await this.loadIntoTree(filePathOrBuffer);
1550
1586
  // Validate translations using shared utility
1551
1587
  const buttonIds = Object.values(tree.pages).flatMap((page) => page.buttons.map((b) => b.id));
1552
1588
  (0, translationProcessor_1.validateTranslationResults)(llmTranslations, buttonIds, options);
@@ -1583,14 +1619,17 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1583
1619
  });
1584
1620
  });
1585
1621
  // Save and return
1586
- this.saveFromTree(tree, outputPath);
1587
- return fs_1.default.readFileSync(outputPath);
1622
+ await this.saveFromTree(tree, outputPath);
1623
+ return (0, io_1.readBinaryFromInput)(outputPath);
1588
1624
  }
1589
- saveFromTree(tree, outputPath) {
1590
- const zip = new adm_zip_1.default();
1625
+ async saveFromTree(tree, outputPath) {
1626
+ const JSZip = await getJSZip();
1627
+ const zip = new JSZip();
1591
1628
  if (Object.keys(tree.pages).length === 0) {
1592
1629
  // Create empty zip for empty tree
1593
- zip.writeZip(outputPath);
1630
+ const zipBuffer = await zip.generateAsync({ type: 'uint8array' });
1631
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
1632
+ require('fs').writeFileSync(outputPath, zipBuffer);
1594
1633
  return;
1595
1634
  }
1596
1635
  // Collect all unique styles from pages and buttons
@@ -1662,7 +1701,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1662
1701
  suppressEmptyNode: true,
1663
1702
  });
1664
1703
  const settingsXmlContent = settingsBuilder.build(settingsData);
1665
- zip.addFile('Settings0/settings.xml', Buffer.from(settingsXmlContent, 'utf8'));
1704
+ zip.file('Settings0/settings.xml', settingsXmlContent, { binary: false });
1666
1705
  // Create Settings0/Styles/style.xml if there are styles
1667
1706
  if (uniqueStyles.size > 0) {
1668
1707
  const stylesArray = Array.from(uniqueStyles.values()).map(({ id, style }) => {
@@ -1695,7 +1734,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1695
1734
  indentBy: ' ',
1696
1735
  });
1697
1736
  const styleXmlContent = styleBuilder.build(styleData);
1698
- zip.addFile('Settings0/Styles/styles.xml', Buffer.from(styleXmlContent, 'utf8'));
1737
+ zip.file('Settings0/Styles/styles.xml', styleXmlContent, { binary: false });
1699
1738
  }
1700
1739
  // Collect grid file paths for FileMap.xml
1701
1740
  const gridFilePaths = [];
@@ -1778,8 +1817,8 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1778
1817
  }
1779
1818
  }
1780
1819
  const cellData = {
1781
- '@_X': position.x, // Grid3 uses 0-based X coordinates (defaults to 0 when omitted)
1782
- '@_Y': position.y + yOffset, // Grid3 uses 0-based Y coordinates with workspace offset
1820
+ '@_X': position.x + 1, // Grid3 uses 1-based X coordinates
1821
+ '@_Y': position.y + yOffset + 1, // Grid3 uses 1-based Y coordinates with workspace offset
1783
1822
  '@_ColumnSpan': position.columnSpan,
1784
1823
  '@_RowSpan': position.rowSpan,
1785
1824
  Content: {
@@ -1834,16 +1873,16 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1834
1873
  });
1835
1874
  const xmlContent = builder.build(gridData);
1836
1875
  // Add to zip in Grids folder with proper Grid3 naming
1837
- const gridPath = `Grids\\${page.name || page.id}\\grid.xml`;
1876
+ const gridPath = `Grids/${page.name || page.id}/grid.xml`;
1838
1877
  gridFilePaths.push(gridPath);
1839
- zip.addFile(gridPath, Buffer.from(xmlContent, 'utf8'));
1878
+ zip.file(gridPath, xmlContent, { binary: false });
1840
1879
  });
1841
1880
  // Write image files to ZIP
1842
1881
  buttonImages.forEach((imgData) => {
1843
1882
  if (imgData.imageData && imgData.imageData.length > 0) {
1844
1883
  // Create image path in the grid's directory
1845
- const imagePath = `Grids\\${imgData.pageName}\\${imgData.x}-${imgData.y}-0-text-0.${imgData.ext}`;
1846
- zip.addFile(imagePath, imgData.imageData);
1884
+ const imagePath = `Grids/${imgData.pageName}/${imgData.x}-${imgData.y}-0-text-0.${imgData.ext}`;
1885
+ zip.file(imagePath, imgData.imageData);
1847
1886
  }
1848
1887
  });
1849
1888
  // Create FileMap.xml to map all grid files with their dynamic image files
@@ -1854,13 +1893,13 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1854
1893
  Entries: {
1855
1894
  Entry: gridFilePaths.map((gridPath) => {
1856
1895
  // Find all image files for this grid
1857
- const gridName = gridPath.match(/Grids\\([^\\]+)\\grid\.xml$/)?.[1] || '';
1896
+ const gridName = gridPath.match(/Grids\/([^/]+)\/grid\.xml$/)?.[1] || '';
1858
1897
  const imageFiles = [];
1859
1898
  // Collect image filenames for buttons on this page
1860
- // IMPORTANT: FileMap.xml requires full paths like "Grids\PageName\1-5-0-text-0.png"
1899
+ // IMPORTANT: FileMap.xml requires full paths like "Grids/PageName/1-5-0-text-0.png"
1861
1900
  buttonImages.forEach((imgData) => {
1862
1901
  if (imgData.pageName === gridName && imgData.imageData.length > 0) {
1863
- const imagePath = `Grids\\${gridName}\\${imgData.x}-${imgData.y}-0-text-0.${imgData.ext}`;
1902
+ const imagePath = `Grids/${gridName}/${imgData.x}-${imgData.y}-0-text-0.${imgData.ext}`;
1864
1903
  imageFiles.push(imagePath);
1865
1904
  }
1866
1905
  });
@@ -1882,9 +1921,11 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1882
1921
  indentBy: ' ',
1883
1922
  });
1884
1923
  const fileMapXmlContent = fileMapBuilder.build(fileMapData);
1885
- zip.addFile('FileMap.xml', Buffer.from(fileMapXmlContent, 'utf8'));
1924
+ zip.file('FileMap.xml', fileMapXmlContent, { binary: false });
1886
1925
  // Write the zip file
1887
- zip.writeZip(outputPath);
1926
+ const zipBuffer = await zip.generateAsync({ type: 'uint8array' });
1927
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
1928
+ require('fs').writeFileSync(outputPath, zipBuffer);
1888
1929
  }
1889
1930
  // Helper method to calculate column definitions based on page layout
1890
1931
  calculateColumnDefinitions(page) {
@@ -2,6 +2,7 @@ import { BaseProcessor, ProcessorOptions, ExtractStringsResult, TranslatedString
2
2
  import { AACTree } from '../core/treeStructure';
3
3
  import { ValidationResult } from '../validation/validationTypes';
4
4
  import { type ButtonForTranslation, type LLMLTranslationResult } from '../utilities/translation/translationProcessor';
5
+ import { ProcessorInput } from '../utils/io';
5
6
  declare class ObfProcessor extends BaseProcessor {
6
7
  private zipFile?;
7
8
  private imageCache;
@@ -16,12 +17,12 @@ declare class ObfProcessor extends BaseProcessor {
16
17
  private extractImageAsDataUrl;
17
18
  private getMimeTypeFromFilename;
18
19
  private processBoard;
19
- extractTexts(filePathOrBuffer: string | Buffer): string[];
20
- loadIntoTree(filePathOrBuffer: string | Buffer): AACTree;
20
+ extractTexts(filePathOrBuffer: ProcessorInput): Promise<string[]>;
21
+ loadIntoTree(filePathOrBuffer: ProcessorInput): Promise<AACTree>;
21
22
  private buildGridMetadata;
22
23
  private createObfBoardFromPage;
23
- processTexts(filePathOrBuffer: string | Buffer, translations: Map<string, string>, outputPath: string): Buffer;
24
- saveFromTree(tree: AACTree, outputPath: string): void;
24
+ processTexts(filePathOrBuffer: ProcessorInput, translations: Map<string, string>, outputPath: string): Promise<Uint8Array>;
25
+ saveFromTree(tree: AACTree, outputPath: string): Promise<void>;
25
26
  /**
26
27
  * Extract strings with metadata for aac-tools-platform compatibility
27
28
  * Uses the generic implementation from BaseProcessor
@@ -47,7 +48,7 @@ declare class ObfProcessor extends BaseProcessor {
47
48
  * @param filePathOrBuffer - Path to OBF/OBZ file or buffer
48
49
  * @returns Array of symbol information for LLM processing
49
50
  */
50
- extractSymbolsForLLM(filePathOrBuffer: string | Buffer): ButtonForTranslation[];
51
+ extractSymbolsForLLM(filePathOrBuffer: ProcessorInput): Promise<ButtonForTranslation[]>;
51
52
  /**
52
53
  * Apply LLM translations with symbol information.
53
54
  * The LLM should provide translations with symbol attachments in the correct positions.
@@ -60,8 +61,9 @@ declare class ObfProcessor extends BaseProcessor {
60
61
  * @param options - Translation options (e.g., allowPartial for testing)
61
62
  * @returns Buffer of the translated OBF/OBZ file
62
63
  */
63
- processLLMTranslations(filePathOrBuffer: string | Buffer, llmTranslations: LLMLTranslationResult[], outputPath: string, options?: {
64
+ processLLMTranslations(filePathOrBuffer: ProcessorInput, llmTranslations: LLMLTranslationResult[], outputPath: string, options?: {
64
65
  allowPartial?: boolean;
65
- }): Buffer;
66
+ }): Promise<Uint8Array>;
67
+ private getObfValidator;
66
68
  }
67
69
  export { ObfProcessor };