@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.
- package/README.md +52 -852
- package/dist/browser/core/baseProcessor.js +241 -0
- package/dist/browser/core/stringCasing.js +179 -0
- package/dist/browser/core/treeStructure.js +255 -0
- package/dist/browser/index.browser.js +73 -0
- package/dist/browser/processors/applePanelsProcessor.js +582 -0
- package/dist/browser/processors/astericsGridProcessor.js +1509 -0
- package/dist/browser/processors/dotProcessor.js +221 -0
- package/dist/browser/processors/gridset/commands.js +962 -0
- package/dist/browser/processors/gridset/crypto.js +53 -0
- package/dist/browser/processors/gridset/password.js +49 -0
- package/dist/browser/processors/gridset/pluginTypes.js +277 -0
- package/dist/browser/processors/gridset/resolver.js +137 -0
- package/dist/browser/processors/gridset/symbolAlignment.js +276 -0
- package/dist/browser/processors/gridset/symbols.js +464 -0
- package/dist/browser/processors/gridsetProcessor.js +2002 -0
- package/dist/browser/processors/obfProcessor.js +705 -0
- package/dist/browser/processors/opmlProcessor.js +274 -0
- package/dist/browser/types/aac.js +38 -0
- package/dist/browser/utilities/analytics/utils/idGenerator.js +89 -0
- package/dist/browser/utilities/translation/translationProcessor.js +200 -0
- package/dist/browser/utils/io.js +95 -0
- package/dist/browser/validation/baseValidator.js +156 -0
- package/dist/browser/validation/gridsetValidator.js +356 -0
- package/dist/browser/validation/obfValidator.js +500 -0
- package/dist/browser/validation/validationTypes.js +46 -0
- package/dist/cli/index.js +5 -5
- package/dist/core/analyze.d.ts +2 -2
- package/dist/core/analyze.js +2 -2
- package/dist/core/baseProcessor.d.ts +5 -4
- package/dist/core/baseProcessor.js +22 -27
- package/dist/core/treeStructure.d.ts +5 -5
- package/dist/core/treeStructure.js +1 -4
- package/dist/index.browser.d.ts +37 -0
- package/dist/index.browser.js +99 -0
- package/dist/index.d.ts +1 -48
- package/dist/index.js +1 -136
- package/dist/index.node.d.ts +48 -0
- package/dist/index.node.js +152 -0
- package/dist/processors/applePanelsProcessor.d.ts +5 -4
- package/dist/processors/applePanelsProcessor.js +58 -62
- package/dist/processors/astericsGridProcessor.d.ts +7 -6
- package/dist/processors/astericsGridProcessor.js +31 -42
- package/dist/processors/dotProcessor.d.ts +5 -4
- package/dist/processors/dotProcessor.js +25 -33
- package/dist/processors/excelProcessor.d.ts +4 -3
- package/dist/processors/excelProcessor.js +6 -3
- package/dist/processors/gridset/crypto.d.ts +18 -0
- package/dist/processors/gridset/crypto.js +57 -0
- package/dist/processors/gridset/helpers.d.ts +1 -1
- package/dist/processors/gridset/helpers.js +18 -8
- package/dist/processors/gridset/password.d.ts +20 -3
- package/dist/processors/gridset/password.js +29 -12
- package/dist/processors/gridset/symbols.js +63 -46
- package/dist/processors/gridset/wordlistHelpers.d.ts +3 -3
- package/dist/processors/gridset/wordlistHelpers.js +21 -20
- package/dist/processors/gridsetProcessor.d.ts +7 -12
- package/dist/processors/gridsetProcessor.js +116 -77
- package/dist/processors/obfProcessor.d.ts +9 -7
- package/dist/processors/obfProcessor.js +131 -56
- package/dist/processors/obfsetProcessor.d.ts +5 -4
- package/dist/processors/obfsetProcessor.js +10 -16
- package/dist/processors/opmlProcessor.d.ts +5 -4
- package/dist/processors/opmlProcessor.js +27 -34
- package/dist/processors/snapProcessor.d.ts +8 -7
- package/dist/processors/snapProcessor.js +15 -12
- package/dist/processors/touchchatProcessor.d.ts +8 -7
- package/dist/processors/touchchatProcessor.js +22 -17
- package/dist/types/aac.d.ts +0 -2
- package/dist/types/aac.js +2 -0
- package/dist/utils/io.d.ts +12 -0
- package/dist/utils/io.js +107 -0
- package/dist/validation/gridsetValidator.js +10 -9
- package/dist/validation/snapValidator.js +28 -35
- package/docs/BROWSER_USAGE.md +618 -0
- package/docs/PAGESET_GETTING_STARTED.md +185 -0
- package/examples/README.md +77 -0
- package/examples/browser-test-server.js +81 -0
- package/examples/browser-test.html +331 -0
- package/examples/vitedemo/QUICKSTART.md +75 -0
- package/examples/vitedemo/README.md +157 -0
- package/examples/vitedemo/index.html +531 -0
- package/examples/vitedemo/package-lock.json +1221 -0
- package/examples/vitedemo/package.json +18 -0
- package/examples/vitedemo/src/main.ts +871 -0
- package/examples/vitedemo/test-files/example.dot +14 -0
- package/examples/vitedemo/test-files/example.grd +1 -0
- package/examples/vitedemo/test-files/example.gridset +0 -0
- package/examples/vitedemo/test-files/example.obz +0 -0
- package/examples/vitedemo/test-files/example.opml +18 -0
- package/examples/vitedemo/test-files/simple.obf +53 -0
- package/examples/vitedemo/tsconfig.json +24 -0
- package/examples/vitedemo/vite.config.ts +34 -0
- 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
|
|
11
|
-
const
|
|
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
|
-
|
|
60
|
-
|
|
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
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
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 =
|
|
77
|
+
const content = (0, io_1.readTextFromInput)(buffer);
|
|
84
78
|
if (!content || content.trim().length === 0) {
|
|
85
|
-
const validation = (0,
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
146
|
+
if (error instanceof validationTypes_1.ValidationFailureError) {
|
|
153
147
|
throw error;
|
|
154
148
|
}
|
|
155
|
-
const validation = (0,
|
|
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
|
|
157
|
+
throw new validationTypes_1.ValidationFailureError('Failed to load DOT file', validation, error);
|
|
164
158
|
}
|
|
165
159
|
}
|
|
166
|
-
processTexts(filePathOrBuffer, translations, outputPath) {
|
|
167
|
-
|
|
168
|
-
|
|
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 =
|
|
181
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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
|
|
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?:
|
|
10
|
+
export declare function resolveGridsetPassword(options?: ProcessorOptions, source?: ProcessorInput): string | undefined;
|
|
10
11
|
export declare function resolveGridsetPasswordFromEnv(): string | undefined;
|
|
11
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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 =
|
|
25
|
+
const ext = getExtension(source).toLowerCase();
|
|
23
26
|
if (ext === '.gridsetx')
|
|
24
|
-
return
|
|
27
|
+
return envPassword;
|
|
25
28
|
}
|
|
26
29
|
return undefined;
|
|
27
30
|
}
|
|
28
31
|
function resolveGridsetPasswordFromEnv() {
|
|
29
|
-
return process.env
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
82
|
+
export declare function updateWordlist(gridsetBuffer: Uint8Array, gridName: string, wordlist: WordList, password?: string | undefined): Promise<Uint8Array>;
|