@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,15 +1,11 @@
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.DotProcessor = 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
- const fs_1 = __importDefault(require("fs"));
11
- const path_1 = __importDefault(require("path"));
12
- const validation_1 = require("../validation");
7
+ const validationTypes_1 = require("../validation/validationTypes");
8
+ const io_1 = require("../utils/io");
13
9
  class DotProcessor extends baseProcessor_1.BaseProcessor {
14
10
  constructor(options) {
15
11
  super(options);
@@ -55,10 +51,9 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
55
51
  }
56
52
  return { nodes: Array.from(nodes.values()), edges };
57
53
  }
58
- extractTexts(filePathOrBuffer) {
59
- const content = typeof filePathOrBuffer === 'string'
60
- ? fs_1.default.readFileSync(filePathOrBuffer, 'utf8')
61
- : filePathOrBuffer.toString('utf8');
54
+ async extractTexts(filePathOrBuffer) {
55
+ await Promise.resolve();
56
+ const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
62
57
  const { nodes, edges } = this.parseDotFile(content);
63
58
  const texts = [];
64
59
  // Collect node labels
@@ -73,16 +68,15 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
73
68
  }
74
69
  return texts;
75
70
  }
76
- loadIntoTree(filePathOrBuffer) {
77
- const filename = typeof filePathOrBuffer === 'string' ? path_1.default.basename(filePathOrBuffer) : 'upload.dot';
78
- const buffer = Buffer.isBuffer(filePathOrBuffer)
79
- ? filePathOrBuffer
80
- : fs_1.default.readFileSync(filePathOrBuffer);
71
+ async loadIntoTree(filePathOrBuffer) {
72
+ await Promise.resolve();
73
+ const filename = typeof filePathOrBuffer === 'string' ? (0, io_1.getBasename)(filePathOrBuffer) : 'upload.dot';
74
+ const buffer = (0, io_1.readBinaryFromInput)(filePathOrBuffer);
81
75
  const filesize = buffer.byteLength;
82
76
  try {
83
- const content = buffer.toString('utf8');
77
+ const content = (0, io_1.readTextFromInput)(buffer);
84
78
  if (!content || content.trim().length === 0) {
85
- const validation = (0, validation_1.buildValidationResultFromMessage)({
79
+ const validation = (0, validationTypes_1.buildValidationResultFromMessage)({
86
80
  filename,
87
81
  filesize,
88
82
  format: 'dot',
@@ -90,14 +84,14 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
90
84
  type: 'content',
91
85
  description: 'DOT file content',
92
86
  });
93
- throw new validation_1.ValidationFailureError('Empty DOT content', validation);
87
+ throw new validationTypes_1.ValidationFailureError('Empty DOT content', validation);
94
88
  }
95
89
  // Check for binary data (contains null bytes or non-printable characters)
96
90
  const head = content.substring(0, 100);
97
91
  for (let i = 0; i < head.length; i++) {
98
92
  const code = head.charCodeAt(i);
99
93
  if (code === 0 || (code >= 0 && code <= 8) || (code >= 14 && code <= 31)) {
100
- const validation = (0, validation_1.buildValidationResultFromMessage)({
94
+ const validation = (0, validationTypes_1.buildValidationResultFromMessage)({
101
95
  filename,
102
96
  filesize,
103
97
  format: 'dot',
@@ -105,7 +99,7 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
105
99
  type: 'content',
106
100
  description: 'DOT file content',
107
101
  });
108
- throw new validation_1.ValidationFailureError('Invalid DOT content', validation);
102
+ throw new validationTypes_1.ValidationFailureError('Invalid DOT content', validation);
109
103
  }
110
104
  }
111
105
  const { nodes, edges } = this.parseDotFile(content);
@@ -149,10 +143,10 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
149
143
  return tree;
150
144
  }
151
145
  catch (error) {
152
- if (error instanceof validation_1.ValidationFailureError) {
146
+ if (error instanceof validationTypes_1.ValidationFailureError) {
153
147
  throw error;
154
148
  }
155
- const validation = (0, validation_1.buildValidationResultFromMessage)({
149
+ const validation = (0, validationTypes_1.buildValidationResultFromMessage)({
156
150
  filename,
157
151
  filesize,
158
152
  format: 'dot',
@@ -160,14 +154,12 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
160
154
  type: 'parse',
161
155
  description: 'Parse DOT graph',
162
156
  });
163
- throw new validation_1.ValidationFailureError('Failed to load DOT file', validation, error);
157
+ throw new validationTypes_1.ValidationFailureError('Failed to load DOT file', validation, error);
164
158
  }
165
159
  }
166
- processTexts(filePathOrBuffer, translations, outputPath) {
167
- const safeBuffer = Buffer.isBuffer(filePathOrBuffer)
168
- ? filePathOrBuffer
169
- : fs_1.default.readFileSync(filePathOrBuffer);
170
- const content = safeBuffer.toString('utf8');
160
+ async processTexts(filePathOrBuffer, translations, outputPath) {
161
+ await Promise.resolve();
162
+ const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
171
163
  let translatedContent = content;
172
164
  translations.forEach((translation, text) => {
173
165
  if (typeof text === 'string' && typeof translation === 'string') {
@@ -177,12 +169,12 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
177
169
  translatedContent = translatedContent.replace(new RegExp(`label="${escapedText}"`, 'g'), `label="${escapedTranslation}"`);
178
170
  }
179
171
  });
180
- const resultBuffer = Buffer.from(translatedContent || '', 'utf8');
181
- // Save to output path
182
- fs_1.default.writeFileSync(outputPath, resultBuffer);
172
+ const resultBuffer = (0, io_1.encodeText)(translatedContent || '');
173
+ (0, io_1.writeBinaryToPath)(outputPath, resultBuffer);
183
174
  return resultBuffer;
184
175
  }
185
- saveFromTree(tree, _outputPath) {
176
+ async saveFromTree(tree, _outputPath) {
177
+ await Promise.resolve();
186
178
  let dotContent = `digraph "${tree.metadata?.name || 'AACBoard'}" {\n`;
187
179
  // Helper to escape DOT string
188
180
  const escapeDotString = (str) => {
@@ -212,7 +204,7 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
212
204
  });
213
205
  }
214
206
  dotContent += '}\n';
215
- fs_1.default.writeFileSync(_outputPath, dotContent);
207
+ (0, io_1.writeTextToPath)(_outputPath, dotContent);
216
208
  }
217
209
  /**
218
210
  * Extract strings with metadata for aac-tools-platform compatibility
@@ -1,3 +1,4 @@
1
+ import { ProcessorInput } from '../utils/io';
1
2
  import { BaseProcessor, ExtractStringsResult, TranslatedString, SourceString } from '../core/baseProcessor';
2
3
  import { AACTree } from '../core/treeStructure';
3
4
  /**
@@ -12,13 +13,13 @@ export declare class ExcelProcessor extends BaseProcessor {
12
13
  * @param filePathOrBuffer - Path to Excel file or Buffer containing Excel data
13
14
  * @returns Array of all text content found in the Excel file
14
15
  */
15
- extractTexts(_filePathOrBuffer: string | Buffer): string[];
16
+ extractTexts(_filePathOrBuffer: ProcessorInput): Promise<string[]>;
16
17
  /**
17
18
  * Load Excel file into AACTree structure
18
19
  * @param filePathOrBuffer - Path to Excel file or Buffer containing Excel data
19
20
  * @returns AACTree representation of the Excel file
20
21
  */
21
- loadIntoTree(_filePathOrBuffer: string | Buffer): AACTree;
22
+ loadIntoTree(_filePathOrBuffer: ProcessorInput): Promise<AACTree>;
22
23
  /**
23
24
  * Process texts in Excel file (apply translations)
24
25
  * @param filePathOrBuffer - Path to Excel file or Buffer containing Excel data
@@ -26,7 +27,7 @@ export declare class ExcelProcessor extends BaseProcessor {
26
27
  * @param outputPath - Path where translated Excel file should be saved
27
28
  * @returns Buffer containing the translated Excel file
28
29
  */
29
- processTexts(_filePathOrBuffer: string | Buffer, _translations: Map<string, string>, outputPath: string): Buffer;
30
+ processTexts(_filePathOrBuffer: ProcessorInput, _translations: Map<string, string>, outputPath: string): Promise<Uint8Array>;
30
31
  /**
31
32
  * Convert an AAC page to an Excel worksheet
32
33
  * @param workbook - Excel workbook to add worksheet to
@@ -43,7 +43,8 @@ class ExcelProcessor extends baseProcessor_1.BaseProcessor {
43
43
  * @param filePathOrBuffer - Path to Excel file or Buffer containing Excel data
44
44
  * @returns Array of all text content found in the Excel file
45
45
  */
46
- extractTexts(_filePathOrBuffer) {
46
+ async extractTexts(_filePathOrBuffer) {
47
+ await Promise.resolve();
47
48
  console.warn('ExcelProcessor.extractTexts is not implemented yet.');
48
49
  return [];
49
50
  }
@@ -52,7 +53,8 @@ class ExcelProcessor extends baseProcessor_1.BaseProcessor {
52
53
  * @param filePathOrBuffer - Path to Excel file or Buffer containing Excel data
53
54
  * @returns AACTree representation of the Excel file
54
55
  */
55
- loadIntoTree(_filePathOrBuffer) {
56
+ async loadIntoTree(_filePathOrBuffer) {
57
+ await Promise.resolve();
56
58
  console.warn('ExcelProcessor.loadIntoTree is not implemented yet.');
57
59
  const tree = new treeStructure_1.AACTree();
58
60
  tree.metadata.format = 'excel';
@@ -65,7 +67,8 @@ class ExcelProcessor extends baseProcessor_1.BaseProcessor {
65
67
  * @param outputPath - Path where translated Excel file should be saved
66
68
  * @returns Buffer containing the translated Excel file
67
69
  */
68
- processTexts(_filePathOrBuffer, _translations, outputPath) {
70
+ async processTexts(_filePathOrBuffer, _translations, outputPath) {
71
+ await Promise.resolve();
69
72
  console.warn('ExcelProcessor.processTexts is not implemented yet.');
70
73
  const outputDir = path_1.default.dirname(outputPath);
71
74
  if (!fs_1.default.existsSync(outputDir)) {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Crypto utilities for Gridsetx (encrypted Grid3 files)
3
+ * This module is only needed for .gridsetx files and uses Node-only crypto/zlib
4
+ */
5
+ /**
6
+ * Decrypt and inflate a Grid3 encrypted payload (DesktopContentEncrypter).
7
+ * Uses AES-256-CBC with key/IV derived from the password padded with spaces
8
+ * and then Deflate decompression.
9
+ *
10
+ * @param buffer - Encrypted buffer
11
+ * @param password - Password (defaults to 'Chocolate')
12
+ * @returns Decrypted and inflated buffer
13
+ */
14
+ export declare function decryptGridsetEntry(buffer: Buffer, password?: string): Buffer;
15
+ /**
16
+ * Check if crypto operations are available in the current environment
17
+ */
18
+ export declare function isCryptoAvailable(): boolean;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ /**
3
+ * Crypto utilities for Gridsetx (encrypted Grid3 files)
4
+ * This module is only needed for .gridsetx files and uses Node-only crypto/zlib
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.decryptGridsetEntry = decryptGridsetEntry;
8
+ exports.isCryptoAvailable = isCryptoAvailable;
9
+ /**
10
+ * Decrypt and inflate a Grid3 encrypted payload (DesktopContentEncrypter).
11
+ * Uses AES-256-CBC with key/IV derived from the password padded with spaces
12
+ * and then Deflate decompression.
13
+ *
14
+ * @param buffer - Encrypted buffer
15
+ * @param password - Password (defaults to 'Chocolate')
16
+ * @returns Decrypted and inflated buffer
17
+ */
18
+ function decryptGridsetEntry(buffer, password) {
19
+ // Dynamic require to avoid breaking in browser environments
20
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-return
21
+ const crypto = require('crypto');
22
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-return
23
+ const zlib = require('zlib');
24
+ const pwd = (password || 'Chocolate').padEnd(32, ' ');
25
+ const key = Buffer.from(pwd.slice(0, 32), 'utf8');
26
+ const iv = Buffer.from(pwd.slice(0, 16), 'utf8');
27
+ try {
28
+ const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
29
+ const decrypted = Buffer.concat([decipher.update(buffer), decipher.final()]);
30
+ try {
31
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
32
+ return zlib.inflateSync(decrypted);
33
+ }
34
+ catch {
35
+ // If data isn't deflated, return raw decrypted bytes
36
+ return decrypted;
37
+ }
38
+ }
39
+ catch {
40
+ return buffer;
41
+ }
42
+ }
43
+ /**
44
+ * Check if crypto operations are available in the current environment
45
+ */
46
+ function isCryptoAvailable() {
47
+ try {
48
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
49
+ require('crypto');
50
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
51
+ require('zlib');
52
+ return true;
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
@@ -15,7 +15,7 @@ export declare function getAllowedImageEntries(tree: AACTree): Set<string>;
15
15
  * @param entryPath Entry name inside the zip
16
16
  * @returns Image data buffer or null if not found
17
17
  */
18
- export declare function openImage(gridsetBuffer: Buffer, entryPath: string, password?: string | undefined): Buffer | null;
18
+ export declare function openImage(gridsetBuffer: Uint8Array, entryPath: string, password?: string | undefined): Promise<Uint8Array | null>;
19
19
  /**
20
20
  * Generate a random GUID for Grid3 elements
21
21
  * Grid3 uses GUIDs for grid identification
@@ -42,7 +42,6 @@ exports.isGrid3Installed = isGrid3Installed;
42
42
  exports.readGrid3History = readGrid3History;
43
43
  exports.readGrid3HistoryForUser = readGrid3HistoryForUser;
44
44
  exports.readAllGrid3History = readAllGrid3History;
45
- const adm_zip_1 = __importDefault(require("adm-zip"));
46
45
  const fast_xml_parser_1 = require("fast-xml-parser");
47
46
  const treeStructure_1 = require("../../core/treeStructure");
48
47
  const fs = __importStar(require("fs"));
@@ -96,14 +95,25 @@ function getAllowedImageEntries(tree) {
96
95
  * @param entryPath Entry name inside the zip
97
96
  * @returns Image data buffer or null if not found
98
97
  */
99
- function openImage(gridsetBuffer, entryPath, password = (0, password_1.resolveGridsetPasswordFromEnv)()) {
100
- const zip = new adm_zip_1.default(gridsetBuffer);
101
- const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
102
- const want = normalizeZipPath(entryPath);
103
- const entry = entries.find((e) => normalizeZipPath(e.entryName) === want);
104
- if (!entry)
98
+ async function openImage(gridsetBuffer, entryPath, password = (0, password_1.resolveGridsetPasswordFromEnv)()) {
99
+ try {
100
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
101
+ const JSZip = require('jszip');
102
+ const zip = await JSZip.loadAsync(gridsetBuffer);
103
+ const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
104
+ const want = normalizeZipPath(entryPath);
105
+ const entry = entries.find((e) => normalizeZipPath(e.entryName) === want);
106
+ if (!entry)
107
+ return null;
108
+ const data = await entry.getData();
109
+ if (typeof Buffer !== 'undefined' && typeof Buffer.from === 'function') {
110
+ return Buffer.from(data);
111
+ }
112
+ return data;
113
+ }
114
+ catch (error) {
105
115
  return null;
106
- return entry.getData();
116
+ }
107
117
  }
108
118
  /**
109
119
  * Generate a random GUID for Grid3 elements
@@ -1,11 +1,28 @@
1
+ import type JSZip from 'jszip';
1
2
  import { ProcessorOptions } from '../../core/baseProcessor';
2
- import AdmZip from 'adm-zip';
3
+ import { ProcessorInput } from '../../utils/io';
3
4
  /**
4
5
  * Resolve the password to use for Grid3 archives.
5
6
  * Preference order:
6
7
  * 1. Explicit processor option
7
8
  * 2. GRIDSET_PASSWORD env var
8
9
  */
9
- export declare function resolveGridsetPassword(options?: ProcessorOptions, source?: string | Buffer): string | undefined;
10
+ export declare function resolveGridsetPassword(options?: ProcessorOptions, source?: ProcessorInput): string | undefined;
10
11
  export declare function resolveGridsetPasswordFromEnv(): string | undefined;
11
- export declare function getZipEntriesWithPassword(zip: AdmZip, password?: string): AdmZip.IZipEntry[];
12
+ /**
13
+ * Get zip entries as an array from JSZip instance.
14
+ * JSZip doesn't have password protection at the entry level like AdmZip.
15
+ * Password protection for .gridsetx is handled at the archive level in crypto.ts.
16
+ *
17
+ * @param zip - JSZip instance
18
+ * @param password - Optional password (kept for API compatibility, not used with JSZip)
19
+ * @returns Array of entry objects with name and data
20
+ */
21
+ type ZipEntry = {
22
+ name: string;
23
+ entryName: string;
24
+ dir: boolean;
25
+ getData: () => Promise<Uint8Array>;
26
+ };
27
+ export declare function getZipEntriesWithPassword(zip: JSZip, password?: string): ZipEntry[];
28
+ export {};
@@ -28,10 +28,24 @@ function resolveGridsetPassword(options, source) {
28
28
  function resolveGridsetPasswordFromEnv() {
29
29
  return process.env.GRIDSET_PASSWORD;
30
30
  }
31
- // Wrapper to set the password before reading entries (typed getEntries lacks the optional arg)
32
31
  function getZipEntriesWithPassword(zip, password) {
32
+ const entries = [];
33
+ // Note: JSZip doesn't support zip-level password protection like AdmZip
34
+ // Password protection for .gridsetx files is handled at the encrypted archive level
35
+ // in crypto.ts before the zip is loaded
33
36
  if (password) {
34
- return zip.getEntries(password);
37
+ console.warn('JSZip does not support zip-level password protection. For .gridsetx encrypted files, password is handled at the archive level.');
35
38
  }
36
- return zip.getEntries();
39
+ zip.forEach((relativePath, file) => {
40
+ entries.push({
41
+ name: relativePath,
42
+ entryName: relativePath,
43
+ dir: file.dir || false,
44
+ getData: async () => {
45
+ // Use 'uint8array' which is supported everywhere
46
+ return await file.async('uint8array');
47
+ },
48
+ });
49
+ });
50
+ return entries;
37
51
  }
@@ -59,12 +59,12 @@ export declare function wordlistToXml(wordlist: WordList): string;
59
59
  * @returns Map of grid names to their wordlists (if they have any)
60
60
  *
61
61
  * @example
62
- * const wordlists = extractWordlists(gridsetBuffer);
62
+ * const wordlists = await extractWordlists(gridsetBuffer);
63
63
  * wordlists.forEach((wordlist, gridName) => {
64
64
  * console.log(`Grid "${gridName}" has ${wordlist.items.length} items`);
65
65
  * });
66
66
  */
67
- export declare function extractWordlists(gridsetBuffer: Buffer, password?: string | undefined): Map<string, WordList>;
67
+ export declare function extractWordlists(gridsetBuffer: Uint8Array, password?: string | undefined): Promise<Map<string, WordList>>;
68
68
  /**
69
69
  * Updates or adds a wordlist to a specific grid in a gridset
70
70
  *
@@ -79,4 +79,4 @@ export declare function extractWordlists(gridsetBuffer: Buffer, password?: strin
79
79
  * const updatedGridset = updateWordlist(gridsetBuffer, 'Greetings', newWordlist);
80
80
  * fs.writeFileSync('updated-gridset.gridset', updatedGridset);
81
81
  */
82
- export declare function updateWordlist(gridsetBuffer: Buffer, gridName: string, wordlist: WordList, password?: string | undefined): Buffer;
82
+ export declare function updateWordlist(gridsetBuffer: Uint8Array, gridName: string, wordlist: WordList, password?: string | undefined): Promise<Uint8Array>;
@@ -9,17 +9,14 @@
9
9
  * Note: Wordlists are only supported in Grid3 format. Other AAC formats
10
10
  * do not have equivalent wordlist functionality.
11
11
  */
12
- var __importDefault = (this && this.__importDefault) || function (mod) {
13
- return (mod && mod.__esModule) ? mod : { "default": mod };
14
- };
15
12
  Object.defineProperty(exports, "__esModule", { value: true });
16
13
  exports.createWordlist = createWordlist;
17
14
  exports.wordlistToXml = wordlistToXml;
18
15
  exports.extractWordlists = extractWordlists;
19
16
  exports.updateWordlist = updateWordlist;
20
- const adm_zip_1 = __importDefault(require("adm-zip"));
21
17
  const fast_xml_parser_1 = require("fast-xml-parser");
22
18
  const password_1 = require("./password");
19
+ const io_1 = require("../../utils/io");
23
20
  /**
24
21
  * Creates a WordList object from an array of words/phrases or a dictionary
25
22
  *
@@ -100,31 +97,33 @@ function wordlistToXml(wordlist) {
100
97
  * @returns Map of grid names to their wordlists (if they have any)
101
98
  *
102
99
  * @example
103
- * const wordlists = extractWordlists(gridsetBuffer);
100
+ * const wordlists = await extractWordlists(gridsetBuffer);
104
101
  * wordlists.forEach((wordlist, gridName) => {
105
102
  * console.log(`Grid "${gridName}" has ${wordlist.items.length} items`);
106
103
  * });
107
104
  */
108
- function extractWordlists(gridsetBuffer, password = (0, password_1.resolveGridsetPasswordFromEnv)()) {
105
+ async function extractWordlists(gridsetBuffer, password = (0, password_1.resolveGridsetPasswordFromEnv)()) {
109
106
  const wordlists = new Map();
110
107
  const parser = new fast_xml_parser_1.XMLParser();
111
108
  let zip;
112
109
  try {
113
- zip = new adm_zip_1.default(gridsetBuffer);
110
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
111
+ const JSZip = require('jszip');
112
+ zip = await JSZip.loadAsync(gridsetBuffer);
114
113
  }
115
114
  catch (error) {
116
115
  throw new Error(`Invalid gridset buffer: ${error.message}`);
117
116
  }
118
117
  const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
119
118
  // Process each grid file
120
- entries.forEach((entry) => {
119
+ for (const entry of entries) {
121
120
  if (entry.entryName.startsWith('Grids/') && entry.entryName.endsWith('grid.xml')) {
122
121
  try {
123
- const xmlContent = entry.getData().toString('utf8');
122
+ const xmlContent = (0, io_1.decodeText)(await entry.getData());
124
123
  const data = parser.parse(xmlContent);
125
124
  const grid = data.Grid || data.grid;
126
125
  if (!grid || !grid.WordList) {
127
- return;
126
+ continue;
128
127
  }
129
128
  // Extract grid name from path (e.g., "Grids/MyGrid/grid.xml" -> "MyGrid")
130
129
  const match = entry.entryName.match(/^Grids\/([^/]+)\//);
@@ -133,7 +132,7 @@ function extractWordlists(gridsetBuffer, password = (0, password_1.resolveGridse
133
132
  const wordlistData = grid.WordList;
134
133
  const itemsContainer = wordlistData.Items || wordlistData.items;
135
134
  if (!itemsContainer) {
136
- return;
135
+ continue;
137
136
  }
138
137
  const itemArray = Array.isArray(itemsContainer.WordListItem)
139
138
  ? itemsContainer.WordListItem
@@ -154,7 +153,7 @@ function extractWordlists(gridsetBuffer, password = (0, password_1.resolveGridse
154
153
  console.warn(`Failed to extract wordlist from ${entry.entryName}:`, error);
155
154
  }
156
155
  }
157
- });
156
+ }
158
157
  return wordlists;
159
158
  }
160
159
  /**
@@ -171,7 +170,7 @@ function extractWordlists(gridsetBuffer, password = (0, password_1.resolveGridse
171
170
  * const updatedGridset = updateWordlist(gridsetBuffer, 'Greetings', newWordlist);
172
171
  * fs.writeFileSync('updated-gridset.gridset', updatedGridset);
173
172
  */
174
- function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0, password_1.resolveGridsetPasswordFromEnv)()) {
173
+ async function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0, password_1.resolveGridsetPasswordFromEnv)()) {
175
174
  const parser = new fast_xml_parser_1.XMLParser();
176
175
  const builder = new fast_xml_parser_1.XMLBuilder({
177
176
  ignoreAttributes: false,
@@ -181,7 +180,9 @@ function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0, passwo
181
180
  });
182
181
  let zip;
183
182
  try {
184
- zip = new adm_zip_1.default(gridsetBuffer);
183
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
184
+ const JSZip = require('jszip');
185
+ zip = await JSZip.loadAsync(gridsetBuffer);
185
186
  }
186
187
  catch (error) {
187
188
  throw new Error(`Invalid gridset buffer: ${error.message}`);
@@ -189,17 +190,17 @@ function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0, passwo
189
190
  const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
190
191
  let found = false;
191
192
  // Find and update the grid
192
- entries.forEach((entry) => {
193
+ for (const entry of entries) {
193
194
  if (entry.entryName.startsWith('Grids/') && entry.entryName.endsWith('grid.xml')) {
194
195
  const match = entry.entryName.match(/^Grids\/([^/]+)\//);
195
196
  const currentGridName = match ? match[1] : null;
196
197
  if (currentGridName === gridName) {
197
198
  try {
198
- const xmlContent = entry.getData().toString('utf8');
199
+ const xmlContent = (0, io_1.decodeText)(await entry.getData());
199
200
  const data = parser.parse(xmlContent);
200
201
  const grid = data.Grid || data.grid;
201
202
  if (!grid) {
202
- return;
203
+ continue;
203
204
  }
204
205
  // Build the new wordlist XML structure
205
206
  const items = wordlist.items.map((item) => ({
@@ -221,7 +222,7 @@ function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0, passwo
221
222
  };
222
223
  // Rebuild the XML
223
224
  const updatedXml = builder.build(data);
224
- zip.updateFile(entry, Buffer.from(updatedXml, 'utf8'));
225
+ zip.file(entry.entryName, updatedXml, { binary: false });
225
226
  found = true;
226
227
  }
227
228
  catch (error) {
@@ -230,9 +231,9 @@ function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0, passwo
230
231
  }
231
232
  }
232
233
  }
233
- });
234
+ }
234
235
  if (!found) {
235
236
  throw new Error(`Grid "${gridName}" not found in gridset`);
236
237
  }
237
- return zip.toBuffer();
238
+ return await zip.generateAsync({ type: 'uint8array' });
238
239
  }
@@ -2,14 +2,9 @@ import { BaseProcessor, ProcessorOptions, ExtractStringsResult, TranslatedString
2
2
  import { AACTree } from '../core/treeStructure';
3
3
  import { type ButtonForTranslation, type LLMLTranslationResult } from '../utilities/translation/translationProcessor';
4
4
  import { ValidationResult } from '../validation/validationTypes';
5
+ import { ProcessorInput } from '../utils/io';
5
6
  declare class GridsetProcessor extends BaseProcessor {
6
7
  constructor(options?: ProcessorOptions);
7
- /**
8
- * Decrypt and inflate a Grid3 encrypted payload (DesktopContentEncrypter).
9
- * Uses AES-256-CBC with key/IV derived from the password padded with spaces
10
- * and then Deflate decompression.
11
- */
12
- private decryptGridsetEntry;
13
8
  private getGridsetPassword;
14
9
  private ensureAlphaChannel;
15
10
  /**
@@ -25,9 +20,9 @@ declare class GridsetProcessor extends BaseProcessor {
25
20
  private convertGrid3StyleToAACStyle;
26
21
  private getStyleById;
27
22
  private textOf;
28
- extractTexts(filePathOrBuffer: string | Buffer): string[];
29
- loadIntoTree(filePathOrBuffer: string | Buffer): AACTree;
30
- processTexts(filePathOrBuffer: string | Buffer, translations: Map<string, string>, outputPath: string): Buffer;
23
+ extractTexts(filePathOrBuffer: ProcessorInput): Promise<string[]>;
24
+ loadIntoTree(filePathOrBuffer: ProcessorInput): Promise<AACTree>;
25
+ processTexts(filePathOrBuffer: ProcessorInput, translations: Map<string, string>, outputPath: string): Promise<Uint8Array>;
31
26
  /**
32
27
  * Extract symbol information from a gridset for LLM-based translation.
33
28
  * Returns a structured format showing which buttons have symbols and their context.
@@ -37,7 +32,7 @@ declare class GridsetProcessor extends BaseProcessor {
37
32
  * @param filePathOrBuffer - Path to gridset file or buffer
38
33
  * @returns Array of symbol information for LLM processing
39
34
  */
40
- extractSymbolsForLLM(filePathOrBuffer: string | Buffer): ButtonForTranslation[];
35
+ extractSymbolsForLLM(filePathOrBuffer: string | Buffer): Promise<ButtonForTranslation[]>;
41
36
  /**
42
37
  * Apply LLM translations with symbol information.
43
38
  * The LLM should provide translations with symbol attachments in the correct positions.
@@ -52,8 +47,8 @@ declare class GridsetProcessor extends BaseProcessor {
52
47
  */
53
48
  processLLMTranslations(filePathOrBuffer: string | Buffer, llmTranslations: LLMLTranslationResult[], outputPath: string, options?: {
54
49
  allowPartial?: boolean;
55
- }): Buffer;
56
- saveFromTree(tree: AACTree, outputPath: string): void;
50
+ }): Promise<Uint8Array>;
51
+ saveFromTree(tree: AACTree, outputPath: string): Promise<void>;
57
52
  private calculateColumnDefinitions;
58
53
  private calculateRowDefinitions;
59
54
  private findButtonPosition;