@willwade/aac-processors 0.0.30 → 0.1.1

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 (94) 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 +49 -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 +464 -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 +356 -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 +29 -12
  54. package/dist/processors/gridset/symbols.js +63 -46
  55. package/dist/processors/gridset/wordlistHelpers.d.ts +3 -3
  56. package/dist/processors/gridset/wordlistHelpers.js +21 -20
  57. package/dist/processors/gridsetProcessor.d.ts +7 -12
  58. package/dist/processors/gridsetProcessor.js +116 -77
  59. package/dist/processors/obfProcessor.d.ts +9 -7
  60. package/dist/processors/obfProcessor.js +131 -56
  61. package/dist/processors/obfsetProcessor.d.ts +5 -4
  62. package/dist/processors/obfsetProcessor.js +10 -16
  63. package/dist/processors/opmlProcessor.d.ts +5 -4
  64. package/dist/processors/opmlProcessor.js +27 -34
  65. package/dist/processors/snapProcessor.d.ts +8 -7
  66. package/dist/processors/snapProcessor.js +15 -12
  67. package/dist/processors/touchchatProcessor.d.ts +8 -7
  68. package/dist/processors/touchchatProcessor.js +22 -17
  69. package/dist/types/aac.d.ts +0 -2
  70. package/dist/types/aac.js +2 -0
  71. package/dist/utils/io.d.ts +12 -0
  72. package/dist/utils/io.js +107 -0
  73. package/dist/validation/gridsetValidator.js +10 -9
  74. package/dist/validation/snapValidator.js +28 -35
  75. package/docs/BROWSER_USAGE.md +618 -0
  76. package/docs/PAGESET_GETTING_STARTED.md +185 -0
  77. package/examples/README.md +77 -0
  78. package/examples/browser-test-server.js +81 -0
  79. package/examples/browser-test.html +331 -0
  80. package/examples/vitedemo/QUICKSTART.md +75 -0
  81. package/examples/vitedemo/README.md +157 -0
  82. package/examples/vitedemo/index.html +531 -0
  83. package/examples/vitedemo/package-lock.json +1221 -0
  84. package/examples/vitedemo/package.json +18 -0
  85. package/examples/vitedemo/src/main.ts +871 -0
  86. package/examples/vitedemo/test-files/example.dot +14 -0
  87. package/examples/vitedemo/test-files/example.grd +1 -0
  88. package/examples/vitedemo/test-files/example.gridset +0 -0
  89. package/examples/vitedemo/test-files/example.obz +0 -0
  90. package/examples/vitedemo/test-files/example.opml +18 -0
  91. package/examples/vitedemo/test-files/simple.obf +53 -0
  92. package/examples/vitedemo/tsconfig.json +24 -0
  93. package/examples/vitedemo/vite.config.ts +34 -0
  94. package/package.json +21 -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 {};
@@ -1,12 +1,14 @@
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.resolveGridsetPassword = resolveGridsetPassword;
7
4
  exports.resolveGridsetPasswordFromEnv = resolveGridsetPasswordFromEnv;
8
5
  exports.getZipEntriesWithPassword = getZipEntriesWithPassword;
9
- const path_1 = __importDefault(require("path"));
6
+ function getExtension(source) {
7
+ const index = source.lastIndexOf('.');
8
+ if (index === -1)
9
+ return '';
10
+ return source.slice(index);
11
+ }
10
12
  /**
11
13
  * Resolve the password to use for Grid3 archives.
12
14
  * Preference order:
@@ -16,22 +18,37 @@ const path_1 = __importDefault(require("path"));
16
18
  function resolveGridsetPassword(options, source) {
17
19
  if (options?.gridsetPassword)
18
20
  return options.gridsetPassword;
19
- if (process.env.GRIDSET_PASSWORD)
20
- return process.env.GRIDSET_PASSWORD;
21
+ const envPassword = typeof process !== 'undefined' ? process.env?.GRIDSET_PASSWORD : undefined;
22
+ if (envPassword)
23
+ return envPassword;
21
24
  if (typeof source === 'string') {
22
- const ext = path_1.default.extname(source).toLowerCase();
25
+ const ext = getExtension(source).toLowerCase();
23
26
  if (ext === '.gridsetx')
24
- return process.env.GRIDSET_PASSWORD;
27
+ return envPassword;
25
28
  }
26
29
  return undefined;
27
30
  }
28
31
  function resolveGridsetPasswordFromEnv() {
29
- return process.env.GRIDSET_PASSWORD;
32
+ return typeof process !== 'undefined' ? process.env?.GRIDSET_PASSWORD : undefined;
30
33
  }
31
- // Wrapper to set the password before reading entries (typed getEntries lacks the optional arg)
32
34
  function getZipEntriesWithPassword(zip, password) {
35
+ const entries = [];
36
+ // Note: JSZip doesn't support zip-level password protection like AdmZip
37
+ // Password protection for .gridsetx files is handled at the encrypted archive level
38
+ // in crypto.ts before the zip is loaded
33
39
  if (password) {
34
- return zip.getEntries(password);
40
+ console.warn('JSZip does not support zip-level password protection. For .gridsetx encrypted files, password is handled at the archive level.');
35
41
  }
36
- return zip.getEntries();
42
+ zip.forEach((relativePath, file) => {
43
+ entries.push({
44
+ name: relativePath,
45
+ entryName: relativePath,
46
+ dir: file.dir || false,
47
+ getData: async () => {
48
+ // Use 'uint8array' which is supported everywhere
49
+ return await file.async('uint8array');
50
+ },
51
+ });
52
+ });
53
+ return entries;
37
54
  }
@@ -13,32 +13,6 @@
13
13
  *
14
14
  * This module provides symbol resolution and metadata extraction.
15
15
  */
16
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- var desc = Object.getOwnPropertyDescriptor(m, k);
19
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
- desc = { enumerable: true, get: function() { return m[k]; } };
21
- }
22
- Object.defineProperty(o, k2, desc);
23
- }) : (function(o, m, k, k2) {
24
- if (k2 === undefined) k2 = k;
25
- o[k2] = m[k];
26
- }));
27
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
- Object.defineProperty(o, "default", { enumerable: true, value: v });
29
- }) : function(o, v) {
30
- o["default"] = v;
31
- });
32
- var __importStar = (this && this.__importStar) || function (mod) {
33
- if (mod && mod.__esModule) return mod;
34
- var result = {};
35
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
36
- __setModuleDefault(result, mod);
37
- return result;
38
- };
39
- var __importDefault = (this && this.__importDefault) || function (mod) {
40
- return (mod && mod.__esModule) ? mod : { "default": mod };
41
- };
42
16
  Object.defineProperty(exports, "__esModule", { value: true });
43
17
  exports.DEFAULT_LOCALE = exports.SYMBOL_LIBRARIES = void 0;
44
18
  exports.parseSymbolReference = parseSymbolReference;
@@ -59,9 +33,7 @@ exports.analyzeSymbolUsage = analyzeSymbolUsage;
59
33
  exports.symbolReferenceToFilename = symbolReferenceToFilename;
60
34
  exports.getSymbolsDir = getSymbolsDir;
61
35
  exports.getSymbolSearchDir = getSymbolSearchDir;
62
- const fs = __importStar(require("fs"));
63
- const path = __importStar(require("path"));
64
- const adm_zip_1 = __importDefault(require("adm-zip"));
36
+ const io_1 = require("../../utils/io");
65
37
  /**
66
38
  * Default Grid 3 installation paths by platform
67
39
  */
@@ -104,6 +76,37 @@ exports.SYMBOL_LIBRARIES = {
104
76
  * Default locale to use
105
77
  */
106
78
  exports.DEFAULT_LOCALE = 'en-GB';
79
+ function getNodeFs() {
80
+ try {
81
+ return (0, io_1.getFs)();
82
+ }
83
+ catch {
84
+ throw new Error('Symbol library access is not available in this environment.');
85
+ }
86
+ }
87
+ function getNodePath() {
88
+ try {
89
+ return (0, io_1.getPath)();
90
+ }
91
+ catch {
92
+ throw new Error('Path utilities are not available in this environment.');
93
+ }
94
+ }
95
+ let cachedAdmZip = null;
96
+ function getAdmZip() {
97
+ if (cachedAdmZip)
98
+ return cachedAdmZip;
99
+ try {
100
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
101
+ const module = require('adm-zip');
102
+ const resolved = module.default || module;
103
+ cachedAdmZip = resolved;
104
+ return resolved;
105
+ }
106
+ catch {
107
+ throw new Error('Symbol library access requires AdmZip in this environment.');
108
+ }
109
+ }
107
110
  /**
108
111
  * Parse a symbol reference string
109
112
  * @param reference - Symbol reference like "[widgit]/food/apple.png"
@@ -142,23 +145,29 @@ function isSymbolReference(reference) {
142
145
  * @returns Default Grid 3 path or empty string if not found
143
146
  */
144
147
  function getDefaultGrid3Path() {
145
- const platform = process.platform;
148
+ const platform = (typeof process !== 'undefined' && process.platform ? process.platform : 'unknown');
146
149
  const defaultPath = DEFAULT_GRID3_PATHS[platform] || '';
147
- if (defaultPath && fs.existsSync(defaultPath)) {
148
- return defaultPath;
149
- }
150
- // Try to find Grid 3 in common locations
151
- const commonPaths = [
152
- 'C:\\Program Files (x86)\\Smartbox\\Grid 3',
153
- 'C:\\Program Files\\Smartbox\\Grid 3',
154
- 'C:\\Program Files\\Smartbox\\Grid 3',
155
- '/Applications/Grid 3.app',
156
- '/opt/smartbox/grid3',
157
- ];
158
- for (const testPath of commonPaths) {
159
- if (fs.existsSync(testPath)) {
160
- return testPath;
150
+ try {
151
+ const fs = getNodeFs();
152
+ if (defaultPath && fs.existsSync(defaultPath)) {
153
+ return defaultPath;
161
154
  }
155
+ // Try to find Grid 3 in common locations
156
+ const commonPaths = [
157
+ 'C:\\Program Files (x86)\\Smartbox\\Grid 3',
158
+ 'C:\\Program Files\\Smartbox\\Grid 3',
159
+ 'C:\\Program Files\\Smartbox\\Grid 3',
160
+ '/Applications/Grid 3.app',
161
+ '/opt/smartbox/grid3',
162
+ ];
163
+ for (const testPath of commonPaths) {
164
+ if (fs.existsSync(testPath)) {
165
+ return testPath;
166
+ }
167
+ }
168
+ }
169
+ catch {
170
+ return '';
162
171
  }
163
172
  return '';
164
173
  }
@@ -169,6 +178,7 @@ function getDefaultGrid3Path() {
169
178
  * @returns Path to Symbol Libraries directory (e.g., "C:\...\Grid 3\Resources\Symbols")
170
179
  */
171
180
  function getSymbolLibrariesDir(grid3Path) {
181
+ const path = getNodePath();
172
182
  return path.join(grid3Path, SYMBOLS_SUBDIR);
173
183
  }
174
184
  /**
@@ -179,6 +189,7 @@ function getSymbolLibrariesDir(grid3Path) {
179
189
  * @returns Path to symbol search indexes directory (e.g., "C:\...\Grid 3\Locale\en-GB\symbolsearch")
180
190
  */
181
191
  function getSymbolSearchIndexesDir(grid3Path, locale = exports.DEFAULT_LOCALE) {
192
+ const path = getNodePath();
182
193
  return path.join(grid3Path, SYMBOLSEARCH_SUBDIR, locale, 'symbolsearch');
183
194
  }
184
195
  /**
@@ -192,6 +203,7 @@ function getAvailableSymbolLibraries(options = {}) {
192
203
  return [];
193
204
  }
194
205
  const symbolsDir = getSymbolLibrariesDir(grid3Path);
206
+ const fs = getNodeFs();
195
207
  if (!fs.existsSync(symbolsDir)) {
196
208
  return [];
197
209
  }
@@ -199,6 +211,7 @@ function getAvailableSymbolLibraries(options = {}) {
199
211
  const files = fs.readdirSync(symbolsDir);
200
212
  for (const file of files) {
201
213
  if (file.endsWith('.symbols')) {
214
+ const path = getNodePath();
202
215
  const fullPath = path.join(symbolsDir, file);
203
216
  const stats = fs.statSync(fullPath);
204
217
  const libraryName = path.basename(file, '.symbols');
@@ -233,7 +246,9 @@ function getSymbolLibraryInfo(libraryName, options = {}) {
233
246
  libraryName + '.symbols',
234
247
  ];
235
248
  for (const file of variations) {
249
+ const path = getNodePath();
236
250
  const fullPath = path.join(symbolsDir, file);
251
+ const fs = getNodeFs();
237
252
  if (fs.existsSync(fullPath)) {
238
253
  const stats = fs.statSync(fullPath);
239
254
  return {
@@ -280,7 +295,8 @@ function resolveSymbolReference(reference, options = {}) {
280
295
  }
281
296
  try {
282
297
  // .symbols files are ZIP archives
283
- const zip = new adm_zip_1.default(libraryInfo.pixFile);
298
+ const AdmZip = getAdmZip();
299
+ const zip = new AdmZip(libraryInfo.pixFile);
284
300
  // The path in the symbol reference becomes the path within the symbols/ folder
285
301
  // e.g., [tawasl]/above bw.png becomes symbols/above bw.png
286
302
  const symbolPath = `symbols/${parsed.path}`;
@@ -445,7 +461,8 @@ function analyzeSymbolUsage(tree) {
445
461
  */
446
462
  function symbolReferenceToFilename(reference, cellX, cellY) {
447
463
  const parsed = parseSymbolReference(reference);
448
- const ext = path.extname(parsed.path) || '.png';
464
+ const dotIndex = parsed.path.lastIndexOf('.');
465
+ const ext = dotIndex >= 0 ? parsed.path.slice(dotIndex) : '.png';
449
466
  // Grid 3 format: {x}-{y}-0-text-0.{ext}
450
467
  return `${cellX}-${cellY}-0-text-0${ext}`;
451
468
  }
@@ -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>;