@willwade/aac-processors 0.0.9 → 0.0.10

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 (56) hide show
  1. package/README.md +85 -11
  2. package/dist/cli/index.js +87 -0
  3. package/dist/core/analyze.js +1 -0
  4. package/dist/core/baseProcessor.d.ts +3 -0
  5. package/dist/core/fileProcessor.js +1 -0
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.js +3 -0
  8. package/dist/optional/symbolTools.js +4 -2
  9. package/dist/processors/gridset/helpers.d.ts +1 -1
  10. package/dist/processors/gridset/helpers.js +5 -3
  11. package/dist/processors/gridset/password.d.ts +11 -0
  12. package/dist/processors/gridset/password.js +37 -0
  13. package/dist/processors/gridset/resolver.d.ts +1 -1
  14. package/dist/processors/gridset/resolver.js +8 -4
  15. package/dist/processors/gridset/wordlistHelpers.d.ts +2 -2
  16. package/dist/processors/gridset/wordlistHelpers.js +7 -4
  17. package/dist/processors/gridsetProcessor.d.ts +15 -1
  18. package/dist/processors/gridsetProcessor.js +64 -22
  19. package/dist/processors/index.d.ts +1 -0
  20. package/dist/processors/index.js +5 -2
  21. package/dist/processors/obfProcessor.d.ts +7 -0
  22. package/dist/processors/obfProcessor.js +9 -0
  23. package/dist/processors/snapProcessor.d.ts +7 -0
  24. package/dist/processors/snapProcessor.js +9 -0
  25. package/dist/processors/touchchatProcessor.d.ts +7 -0
  26. package/dist/processors/touchchatProcessor.js +9 -0
  27. package/dist/utilities/screenshotConverter.d.ts +69 -0
  28. package/dist/utilities/screenshotConverter.js +453 -0
  29. package/dist/validation/baseValidator.d.ts +80 -0
  30. package/dist/validation/baseValidator.js +160 -0
  31. package/dist/validation/gridsetValidator.d.ts +36 -0
  32. package/dist/validation/gridsetValidator.js +288 -0
  33. package/dist/validation/index.d.ts +13 -0
  34. package/dist/validation/index.js +69 -0
  35. package/dist/validation/obfValidator.d.ts +44 -0
  36. package/dist/validation/obfValidator.js +530 -0
  37. package/dist/validation/snapValidator.d.ts +33 -0
  38. package/dist/validation/snapValidator.js +237 -0
  39. package/dist/validation/touchChatValidator.d.ts +33 -0
  40. package/dist/validation/touchChatValidator.js +229 -0
  41. package/dist/validation/validationTypes.d.ts +64 -0
  42. package/dist/validation/validationTypes.js +15 -0
  43. package/examples/README.md +7 -0
  44. package/examples/demo.js +143 -0
  45. package/examples/obf/aboutme.json +376 -0
  46. package/examples/obf/array.json +6 -0
  47. package/examples/obf/hash.json +4 -0
  48. package/examples/obf/links.obz +0 -0
  49. package/examples/obf/simple.obf +53 -0
  50. package/examples/package-lock.json +1326 -0
  51. package/examples/package.json +10 -0
  52. package/examples/styling-example.ts +316 -0
  53. package/examples/translate.js +39 -0
  54. package/examples/translate_demo.js +254 -0
  55. package/examples/typescript-demo.ts +251 -0
  56. package/package.json +3 -1
@@ -10,10 +10,42 @@ const adm_zip_1 = __importDefault(require("adm-zip"));
10
10
  const fs_1 = __importDefault(require("fs"));
11
11
  const fast_xml_parser_1 = require("fast-xml-parser");
12
12
  const resolver_1 = require("./gridset/resolver");
13
+ const password_1 = require("./gridset/password");
14
+ const crypto_1 = __importDefault(require("crypto"));
15
+ const zlib_1 = __importDefault(require("zlib"));
16
+ const gridsetValidator_1 = require("../validation/gridsetValidator");
13
17
  class GridsetProcessor extends baseProcessor_1.BaseProcessor {
14
18
  constructor(options) {
15
19
  super(options);
16
20
  }
21
+ /**
22
+ * Decrypt and inflate a Grid3 encrypted payload (DesktopContentEncrypter).
23
+ * Uses AES-256-CBC with key/IV derived from the password padded with spaces
24
+ * and then Deflate decompression.
25
+ */
26
+ decryptGridsetEntry(buffer, password) {
27
+ const pwd = (password || 'Chocolate').padEnd(32, ' ');
28
+ const key = Buffer.from(pwd.slice(0, 32), 'utf8');
29
+ const iv = Buffer.from(pwd.slice(0, 16), 'utf8');
30
+ try {
31
+ const decipher = crypto_1.default.createDecipheriv('aes-256-cbc', key, iv);
32
+ const decrypted = Buffer.concat([decipher.update(buffer), decipher.final()]);
33
+ try {
34
+ return zlib_1.default.inflateSync(decrypted);
35
+ }
36
+ catch {
37
+ // If data isn't deflated, return raw decrypted bytes
38
+ return decrypted;
39
+ }
40
+ }
41
+ catch {
42
+ return buffer;
43
+ }
44
+ }
45
+ // Determine password to use when opening encrypted gridset archives (.gridsetx)
46
+ getGridsetPassword(source) {
47
+ return (0, password_1.resolveGridsetPassword)(this.options, source);
48
+ }
17
49
  // Helper function to ensure color has alpha channel (Grid3 format)
18
50
  ensureAlphaChannel(color) {
19
51
  if (!color)
@@ -242,10 +274,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
242
274
  return undefined;
243
275
  }
244
276
  extractTexts(filePathOrBuffer) {
245
- const buffer = Buffer.isBuffer(filePathOrBuffer)
246
- ? filePathOrBuffer
247
- : fs_1.default.readFileSync(filePathOrBuffer);
248
- const tree = this.loadIntoTree(buffer);
277
+ const tree = this.loadIntoTree(filePathOrBuffer);
249
278
  const texts = [];
250
279
  for (const pageId in tree.pages) {
251
280
  const page = tree.pages[pageId];
@@ -269,13 +298,23 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
269
298
  catch (error) {
270
299
  throw new Error(`Invalid ZIP file format: ${error.message}`);
271
300
  }
301
+ const password = this.getGridsetPassword(filePathOrBuffer);
302
+ const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
272
303
  const parser = new fast_xml_parser_1.XMLParser({ ignoreAttributes: false });
304
+ const isEncryptedArchive = typeof filePathOrBuffer === 'string' && filePathOrBuffer.toLowerCase().endsWith('.gridsetx');
305
+ const encryptedContentPassword = this.getGridsetPassword(filePathOrBuffer);
306
+ const readEntryBuffer = (entry) => {
307
+ const raw = entry.getData();
308
+ if (!isEncryptedArchive)
309
+ return raw;
310
+ return this.decryptGridsetEntry(raw, encryptedContentPassword);
311
+ };
273
312
  // Parse FileMap.xml if present to index dynamic files per grid
274
313
  const fileMapIndex = new Map();
275
314
  try {
276
- const fmEntry = zip.getEntries().find((e) => e.entryName.endsWith('FileMap.xml'));
315
+ const fmEntry = entries.find((e) => e.entryName.endsWith('FileMap.xml'));
277
316
  if (fmEntry) {
278
- const fmXml = fmEntry.getData().toString('utf8');
317
+ const fmXml = readEntryBuffer(fmEntry).toString('utf8');
279
318
  const fmData = parser.parse(fmXml);
280
319
  const entries = fmData?.FileMap?.Entries?.Entry || fmData?.fileMap?.entries?.entry;
281
320
  if (entries) {
@@ -307,12 +346,10 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
307
346
  }
308
347
  // First, load styles from Settings0/Styles/styles.xml (Grid3 format)
309
348
  const styles = new Map();
310
- const styleEntry = zip
311
- .getEntries()
312
- .find((entry) => entry.entryName.endsWith('styles.xml') || entry.entryName.endsWith('style.xml'));
349
+ const styleEntry = entries.find((entry) => entry.entryName.endsWith('styles.xml') || entry.entryName.endsWith('style.xml'));
313
350
  if (styleEntry) {
314
351
  try {
315
- const styleXmlContent = styleEntry.getData().toString('utf8');
352
+ const styleXmlContent = readEntryBuffer(styleEntry).toString('utf8');
316
353
  const styleData = parser.parse(styleXmlContent);
317
354
  // Parse styles and store them in the map
318
355
  // Grid3 uses StyleData.Styles.Style with Key attribute
@@ -343,14 +380,14 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
343
380
  }
344
381
  }
345
382
  // Debug: log all entry names
346
- // console.log('Gridset zip entries:', zip.getEntries().map(e => e.entryName));
383
+ // console.log('Gridset zip entries:', entries.map(e => e.entryName));
347
384
  // First pass: collect all grid names and IDs for navigation resolution
348
385
  const gridNameToIdMap = new Map();
349
386
  const gridIdToNameMap = new Map();
350
- zip.getEntries().forEach((entry) => {
387
+ entries.forEach((entry) => {
351
388
  if (entry.entryName.startsWith('Grids/') && entry.entryName.endsWith('grid.xml')) {
352
389
  try {
353
- const xmlContent = entry.getData().toString('utf8');
390
+ const xmlContent = readEntryBuffer(entry).toString('utf8');
354
391
  const data = parser.parse(xmlContent);
355
392
  const grid = data.Grid || data.grid;
356
393
  if (!grid)
@@ -373,12 +410,12 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
373
410
  }
374
411
  });
375
412
  // Second pass: process each grid file in the gridset
376
- zip.getEntries().forEach((entry) => {
413
+ entries.forEach((entry) => {
377
414
  // Only process files named grid.xml under Grids/ (any subdir)
378
415
  if (entry.entryName.startsWith('Grids/') && entry.entryName.endsWith('grid.xml')) {
379
416
  let xmlContent;
380
417
  try {
381
- xmlContent = entry.getData().toString('utf8');
418
+ xmlContent = readEntryBuffer(entry).toString('utf8');
382
419
  }
383
420
  catch (e) {
384
421
  // Skip unreadable files
@@ -482,7 +519,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
482
519
  x: cellX + 1,
483
520
  y: cellY + 1,
484
521
  dynamicFiles,
485
- }) || undefined;
522
+ }, entries) || undefined;
486
523
  if (commands) {
487
524
  const commandArr = Array.isArray(commands) ? commands : [commands];
488
525
  for (const command of commandArr) {
@@ -910,9 +947,9 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
910
947
  }
911
948
  // Read settings.xml to get the StartGrid (home page)
912
949
  try {
913
- const settingsEntry = zip.getEntries().find((e) => e.entryName.endsWith('settings.xml'));
950
+ const settingsEntry = entries.find((e) => e.entryName.endsWith('settings.xml'));
914
951
  if (settingsEntry) {
915
- const settingsXml = settingsEntry.getData().toString('utf8');
952
+ const settingsXml = readEntryBuffer(settingsEntry).toString('utf8');
916
953
  const settingsData = parser.parse(settingsXml);
917
954
  const startGridName = settingsData?.GridSetSettings?.StartGrid ||
918
955
  settingsData?.gridSetSettings?.startGrid ||
@@ -933,10 +970,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
933
970
  }
934
971
  processTexts(filePathOrBuffer, translations, outputPath) {
935
972
  // Load the tree, apply translations, and save to new file
936
- const buffer = Buffer.isBuffer(filePathOrBuffer)
937
- ? filePathOrBuffer
938
- : fs_1.default.readFileSync(filePathOrBuffer);
939
- const tree = this.loadIntoTree(buffer);
973
+ const tree = this.loadIntoTree(filePathOrBuffer);
940
974
  // Apply translations to all text content
941
975
  Object.values(tree.pages).forEach((page) => {
942
976
  // Translate page names
@@ -1327,5 +1361,13 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1327
1361
  generateTranslatedDownload(filePath, translatedStrings, sourceStrings) {
1328
1362
  return this.generateTranslatedDownloadGeneric(filePath, translatedStrings, sourceStrings);
1329
1363
  }
1364
+ /**
1365
+ * Validate Gridset file format
1366
+ * @param filePath - Path to the file to validate
1367
+ * @returns Promise with validation result
1368
+ */
1369
+ async validate(filePath) {
1370
+ return gridsetValidator_1.GridsetValidator.validateFile(filePath);
1371
+ }
1330
1372
  }
1331
1373
  exports.GridsetProcessor = GridsetProcessor;
@@ -11,6 +11,7 @@ export { getPageTokenImageMap, getAllowedImageEntries, openImage, generateGrid3G
11
11
  export { getPageTokenImageMap as getGridsetPageTokenImageMap, getAllowedImageEntries as getGridsetAllowedImageEntries, openImage as openGridsetImage, generateGrid3Guid as generateGridsetGuid, createSettingsXml as createGridsetSettingsXml, createFileMapXml as createGridsetFileMapXml, getCommonDocumentsPath as getGridsetCommonDocumentsPath, findGrid3UserPaths as findGridsetUserPaths, findGrid3HistoryDatabases as findGridsetHistoryDatabases, findGrid3Users as findGridsetUsers, findGrid3Vocabularies as findGridsetVocabularies, findGrid3UserHistory as findGridsetUserHistory, isGrid3Installed as isGridsetInstalled, readGrid3History as readGridsetHistory, readGrid3HistoryForUser as readGridsetHistoryForUser, readAllGrid3History as readAllGridsetHistory, } from './gridset/helpers';
12
12
  export { resolveGrid3CellImage } from './gridset/resolver';
13
13
  export { createWordlist, extractWordlists, updateWordlist, wordlistToXml, type WordList, type WordListItem, } from './gridset/wordlistHelpers';
14
+ export { resolveGridsetPassword, resolveGridsetPasswordFromEnv } from './gridset/password';
14
15
  export { getNamedColor, rgbaToHex, channelToHex, clampColorChannel, clampAlpha, toHexColor, darkenColor, normalizeColor, ensureAlphaChannel, } from './gridset/colorUtils';
15
16
  export { DEFAULT_GRID3_STYLES, CATEGORY_STYLES, createDefaultStylesXml, createCategoryStyle, } from './gridset/styleHelpers';
16
17
  export { ensureAlphaChannel as ensureAlphaChannelFromStyles } from './gridset/styleHelpers';
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.clampColorChannel = exports.channelToHex = exports.rgbaToHex = exports.getNamedColor = exports.wordlistToXml = exports.updateWordlist = exports.extractWordlists = exports.createWordlist = exports.resolveGrid3CellImage = exports.readAllGridsetHistory = exports.readGridsetHistoryForUser = exports.readGridsetHistory = exports.isGridsetInstalled = exports.findGridsetUserHistory = exports.findGridsetVocabularies = exports.findGridsetUsers = exports.findGridsetHistoryDatabases = exports.findGridsetUserPaths = exports.getGridsetCommonDocumentsPath = exports.createGridsetFileMapXml = exports.createGridsetSettingsXml = exports.generateGridsetGuid = exports.openGridsetImage = exports.getGridsetAllowedImageEntries = exports.getGridsetPageTokenImageMap = exports.readAllGrid3History = exports.readGrid3HistoryForUser = exports.readGrid3History = exports.isGrid3Installed = exports.findGrid3UserHistory = exports.findGrid3Vocabularies = exports.findGrid3Users = exports.findGrid3HistoryDatabases = exports.findGrid3UserPaths = exports.getCommonDocumentsPath = exports.createFileMapXml = exports.createSettingsXml = exports.generateGrid3Guid = exports.openImage = exports.getAllowedImageEntries = exports.getPageTokenImageMap = exports.AstericsGridProcessor = exports.TouchChatProcessor = exports.SnapProcessor = exports.OpmlProcessor = exports.ObfProcessor = exports.GridsetProcessor = exports.ExcelProcessor = exports.DotProcessor = exports.ApplePanelsProcessor = void 0;
4
- exports.openTouchChatImage = exports.getTouchChatAllowedImageEntries = exports.getTouchChatPageTokenImageMap = exports.readSnapUsageForUser = exports.readSnapUsage = exports.isSnapInstalled = exports.findSnapUserHistory = exports.findSnapUserVocabularies = exports.findSnapUsers = exports.findSnapPackagePath = exports.findSnapPackages = exports.openSnapImage = exports.getSnapAllowedImageEntries = exports.getSnapPageTokenImageMap = exports.ensureAlphaChannelFromStyles = exports.createCategoryStyle = exports.createDefaultStylesXml = exports.CATEGORY_STYLES = exports.DEFAULT_GRID3_STYLES = exports.ensureAlphaChannel = exports.normalizeColor = exports.darkenColor = exports.toHexColor = exports.clampAlpha = void 0;
3
+ exports.rgbaToHex = exports.getNamedColor = exports.resolveGridsetPasswordFromEnv = exports.resolveGridsetPassword = exports.wordlistToXml = exports.updateWordlist = exports.extractWordlists = exports.createWordlist = exports.resolveGrid3CellImage = exports.readAllGridsetHistory = exports.readGridsetHistoryForUser = exports.readGridsetHistory = exports.isGridsetInstalled = exports.findGridsetUserHistory = exports.findGridsetVocabularies = exports.findGridsetUsers = exports.findGridsetHistoryDatabases = exports.findGridsetUserPaths = exports.getGridsetCommonDocumentsPath = exports.createGridsetFileMapXml = exports.createGridsetSettingsXml = exports.generateGridsetGuid = exports.openGridsetImage = exports.getGridsetAllowedImageEntries = exports.getGridsetPageTokenImageMap = exports.readAllGrid3History = exports.readGrid3HistoryForUser = exports.readGrid3History = exports.isGrid3Installed = exports.findGrid3UserHistory = exports.findGrid3Vocabularies = exports.findGrid3Users = exports.findGrid3HistoryDatabases = exports.findGrid3UserPaths = exports.getCommonDocumentsPath = exports.createFileMapXml = exports.createSettingsXml = exports.generateGrid3Guid = exports.openImage = exports.getAllowedImageEntries = exports.getPageTokenImageMap = exports.AstericsGridProcessor = exports.TouchChatProcessor = exports.SnapProcessor = exports.OpmlProcessor = exports.ObfProcessor = exports.GridsetProcessor = exports.ExcelProcessor = exports.DotProcessor = exports.ApplePanelsProcessor = void 0;
4
+ exports.openTouchChatImage = exports.getTouchChatAllowedImageEntries = exports.getTouchChatPageTokenImageMap = exports.readSnapUsageForUser = exports.readSnapUsage = exports.isSnapInstalled = exports.findSnapUserHistory = exports.findSnapUserVocabularies = exports.findSnapUsers = exports.findSnapPackagePath = exports.findSnapPackages = exports.openSnapImage = exports.getSnapAllowedImageEntries = exports.getSnapPageTokenImageMap = exports.ensureAlphaChannelFromStyles = exports.createCategoryStyle = exports.createDefaultStylesXml = exports.CATEGORY_STYLES = exports.DEFAULT_GRID3_STYLES = exports.ensureAlphaChannel = exports.normalizeColor = exports.darkenColor = exports.toHexColor = exports.clampAlpha = exports.clampColorChannel = exports.channelToHex = void 0;
5
5
  var applePanelsProcessor_1 = require("./applePanelsProcessor");
6
6
  Object.defineProperty(exports, "ApplePanelsProcessor", { enumerable: true, get: function () { return applePanelsProcessor_1.ApplePanelsProcessor; } });
7
7
  var dotProcessor_1 = require("./dotProcessor");
@@ -63,6 +63,9 @@ Object.defineProperty(exports, "createWordlist", { enumerable: true, get: functi
63
63
  Object.defineProperty(exports, "extractWordlists", { enumerable: true, get: function () { return wordlistHelpers_1.extractWordlists; } });
64
64
  Object.defineProperty(exports, "updateWordlist", { enumerable: true, get: function () { return wordlistHelpers_1.updateWordlist; } });
65
65
  Object.defineProperty(exports, "wordlistToXml", { enumerable: true, get: function () { return wordlistHelpers_1.wordlistToXml; } });
66
+ var password_1 = require("./gridset/password");
67
+ Object.defineProperty(exports, "resolveGridsetPassword", { enumerable: true, get: function () { return password_1.resolveGridsetPassword; } });
68
+ Object.defineProperty(exports, "resolveGridsetPasswordFromEnv", { enumerable: true, get: function () { return password_1.resolveGridsetPasswordFromEnv; } });
66
69
  // Gridset (Grid 3) color utilities
67
70
  var colorUtils_1 = require("./gridset/colorUtils");
68
71
  Object.defineProperty(exports, "getNamedColor", { enumerable: true, get: function () { return colorUtils_1.getNamedColor; } });
@@ -1,5 +1,6 @@
1
1
  import { BaseProcessor, ProcessorOptions, ExtractStringsResult, TranslatedString, SourceString } from '../core/baseProcessor';
2
2
  import { AACTree } from '../core/treeStructure';
3
+ import { ValidationResult } from '../validation/validationTypes';
3
4
  declare class ObfProcessor extends BaseProcessor {
4
5
  constructor(options?: ProcessorOptions);
5
6
  private processBoard;
@@ -19,5 +20,11 @@ declare class ObfProcessor extends BaseProcessor {
19
20
  * Uses the generic implementation from BaseProcessor
20
21
  */
21
22
  generateTranslatedDownload(filePath: string, translatedStrings: TranslatedString[], sourceStrings: SourceString[]): Promise<string>;
23
+ /**
24
+ * Validate OBF/OBZ file format
25
+ * @param filePath - Path to the file to validate
26
+ * @returns Promise with validation result
27
+ */
28
+ validate(filePath: string): Promise<ValidationResult>;
22
29
  }
23
30
  export { ObfProcessor };
@@ -10,6 +10,7 @@ const treeStructure_1 = require("../core/treeStructure");
10
10
  const adm_zip_1 = __importDefault(require("adm-zip"));
11
11
  const fs_1 = __importDefault(require("fs"));
12
12
  // Removed unused import: path
13
+ const obfValidator_1 = require("../validation/obfValidator");
13
14
  const OBF_FORMAT_VERSION = 'open-board-0.1';
14
15
  class ObfProcessor extends baseProcessor_1.BaseProcessor {
15
16
  constructor(options) {
@@ -359,5 +360,13 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
359
360
  async generateTranslatedDownload(filePath, translatedStrings, sourceStrings) {
360
361
  return this.generateTranslatedDownloadGeneric(filePath, translatedStrings, sourceStrings);
361
362
  }
363
+ /**
364
+ * Validate OBF/OBZ file format
365
+ * @param filePath - Path to the file to validate
366
+ * @returns Promise with validation result
367
+ */
368
+ async validate(filePath) {
369
+ return obfValidator_1.ObfValidator.validateFile(filePath);
370
+ }
362
371
  }
363
372
  exports.ObfProcessor = ObfProcessor;
@@ -1,5 +1,6 @@
1
1
  import { BaseProcessor, ProcessorOptions, ExtractStringsResult, TranslatedString, SourceString } from '../core/baseProcessor';
2
2
  import { AACTree } from '../core/treeStructure';
3
+ import { ValidationResult } from '../validation/validationTypes';
3
4
  declare class SnapProcessor extends BaseProcessor {
4
5
  private symbolResolver;
5
6
  private loadAudio;
@@ -40,5 +41,11 @@ declare class SnapProcessor extends BaseProcessor {
40
41
  * Uses the generic implementation from BaseProcessor
41
42
  */
42
43
  generateTranslatedDownload(filePath: string, translatedStrings: TranslatedString[], sourceStrings: SourceString[]): Promise<string>;
44
+ /**
45
+ * Validate Snap file format
46
+ * @param filePath - Path to the file to validate
47
+ * @returns Promise with validation result
48
+ */
49
+ validate(filePath: string): Promise<ValidationResult>;
43
50
  }
44
51
  export { SnapProcessor };
@@ -11,6 +11,7 @@ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
11
11
  const path_1 = __importDefault(require("path"));
12
12
  const fs_1 = __importDefault(require("fs"));
13
13
  const crypto_1 = __importDefault(require("crypto"));
14
+ const snapValidator_1 = require("../validation/snapValidator");
14
15
  class SnapProcessor extends baseProcessor_1.BaseProcessor {
15
16
  constructor(symbolResolver = null, options = {}) {
16
17
  super(options);
@@ -612,5 +613,13 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
612
613
  async generateTranslatedDownload(filePath, translatedStrings, sourceStrings) {
613
614
  return this.generateTranslatedDownloadGeneric(filePath, translatedStrings, sourceStrings);
614
615
  }
616
+ /**
617
+ * Validate Snap file format
618
+ * @param filePath - Path to the file to validate
619
+ * @returns Promise with validation result
620
+ */
621
+ async validate(filePath) {
622
+ return snapValidator_1.SnapValidator.validateFile(filePath);
623
+ }
615
624
  }
616
625
  exports.SnapProcessor = SnapProcessor;
@@ -1,5 +1,6 @@
1
1
  import { BaseProcessor, ProcessorOptions, ExtractStringsResult, TranslatedString, SourceString } from '../core/baseProcessor';
2
2
  import { AACTree } from '../core/treeStructure';
3
+ import { ValidationResult } from '../validation/validationTypes';
3
4
  declare class TouchChatProcessor extends BaseProcessor {
4
5
  private tree;
5
6
  private sourceFile;
@@ -23,5 +24,11 @@ declare class TouchChatProcessor extends BaseProcessor {
23
24
  * @returns Promise with path to the generated translated file
24
25
  */
25
26
  generateTranslatedDownload(filePath: string, translatedStrings: TranslatedString[], sourceStrings: SourceString[]): Promise<string>;
27
+ /**
28
+ * Validate TouchChat file format
29
+ * @param filePath - Path to the file to validate
30
+ * @returns Promise with validation result
31
+ */
32
+ validate(filePath: string): Promise<ValidationResult>;
26
33
  }
27
34
  export { TouchChatProcessor };
@@ -12,6 +12,7 @@ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
12
12
  const path_1 = __importDefault(require("path"));
13
13
  const fs_1 = __importDefault(require("fs"));
14
14
  const os_1 = __importDefault(require("os"));
15
+ const touchChatValidator_1 = require("../validation/touchChatValidator");
15
16
  const toNumberOrUndefined = (value) => typeof value === 'number' ? value : undefined;
16
17
  const toStringOrUndefined = (value) => typeof value === 'string' && value.length > 0 ? value : undefined;
17
18
  const toBooleanOrUndefined = (value) => typeof value === 'number' ? value !== 0 : undefined;
@@ -787,5 +788,13 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
787
788
  return Promise.reject(new Error(`Failed to generate translated download: ${error instanceof Error ? error.message : 'Unknown error'}`));
788
789
  }
789
790
  }
791
+ /**
792
+ * Validate TouchChat file format
793
+ * @param filePath - Path to the file to validate
794
+ * @returns Promise with validation result
795
+ */
796
+ async validate(filePath) {
797
+ return touchChatValidator_1.TouchChatValidator.validateFile(filePath);
798
+ }
790
799
  }
791
800
  exports.TouchChatProcessor = TouchChatProcessor;
@@ -0,0 +1,69 @@
1
+ import { AACPage, AACTree } from '../core/treeStructure';
2
+ export interface ScreenshotCell {
3
+ text: string;
4
+ row: number;
5
+ col: number;
6
+ isCategory?: boolean;
7
+ isNavigation?: boolean;
8
+ isEmpty?: boolean;
9
+ imageUrl?: string;
10
+ }
11
+ export interface ScreenshotGrid {
12
+ rows: number;
13
+ cols: number;
14
+ cells: ScreenshotCell[];
15
+ categories: string[];
16
+ metadata?: {
17
+ timestamp?: string;
18
+ battery?: string;
19
+ date?: string;
20
+ };
21
+ }
22
+ export interface ScreenshotPage {
23
+ filename: string;
24
+ grid: ScreenshotGrid;
25
+ extractedAt: Date;
26
+ pageName?: string;
27
+ parentPath?: string;
28
+ pageTitle?: string;
29
+ }
30
+ export interface PageHierarchy {
31
+ [pageId: string]: {
32
+ page: ScreenshotPage;
33
+ children: string[];
34
+ parent?: string;
35
+ };
36
+ }
37
+ export interface ScreenshotConversionOptions {
38
+ includeEmptyCells: boolean;
39
+ generateIds: boolean;
40
+ targetPlatform?: 'grid3' | 'asterics' | 'snap' | 'touchchat';
41
+ language: string;
42
+ fallbackCategory: string;
43
+ filenameDelimiter?: string;
44
+ }
45
+ export declare class ScreenshotConverter {
46
+ private static defaultOptions;
47
+ /**
48
+ * Parse filename to extract page hierarchy and names
49
+ * Examples:
50
+ * - "Home.png" → pageName: "Home", parentPath: ""
51
+ * - "Home->Fragen.png" → pageName: "Fragen", parentPath: "Home"
52
+ * - "Home->Settings->Profile.jpg" → pageName: "Profile", parentPath: "Home->Settings"
53
+ */
54
+ static parseFilename(filename: string, delimiter?: string): {
55
+ pageName: string;
56
+ parentPath: string;
57
+ };
58
+ /**
59
+ * Build page hierarchy from an array of screenshots
60
+ */
61
+ static buildPageHierarchy(screenshots: ScreenshotPage[]): PageHierarchy;
62
+ static parseOCRText(ocrResult: string): ScreenshotGrid;
63
+ private static isCategoryToken;
64
+ private static isNavigationToken;
65
+ static convertToAACPage(screenshotPage: ScreenshotPage, pageHierarchy?: PageHierarchy, options?: Partial<ScreenshotConversionOptions>): AACPage;
66
+ private static createSemanticAction;
67
+ static convertToAACTree(screenshotPages: ScreenshotPage[], options?: Partial<ScreenshotConversionOptions>): AACTree;
68
+ private static sanitizePageId;
69
+ }