@willwade/aac-processors 0.1.21 → 0.2.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 (87) hide show
  1. package/README.md +3 -2
  2. package/dist/browser/processors/applePanelsProcessor.js +24 -24
  3. package/dist/browser/processors/astericsGridProcessor.js +22 -24
  4. package/dist/browser/processors/dotProcessor.js +6 -10
  5. package/dist/browser/processors/gridset/helpers.js +33 -30
  6. package/dist/browser/processors/gridset/symbolExtractor.js +2 -2
  7. package/dist/browser/processors/gridset/symbolSearch.js +22 -22
  8. package/dist/browser/processors/gridset/symbols.js +14 -14
  9. package/dist/browser/processors/gridsetProcessor.js +7 -7
  10. package/dist/browser/processors/obfProcessor.js +54 -47
  11. package/dist/browser/processors/opmlProcessor.js +6 -10
  12. package/dist/browser/processors/snap/helpers.js +34 -30
  13. package/dist/browser/processors/snapProcessor.js +28 -28
  14. package/dist/browser/processors/touchchatProcessor.js +24 -25
  15. package/dist/browser/utilities/analytics/history.js +24 -18
  16. package/dist/browser/utilities/analytics/metrics/comparison.js +16 -16
  17. package/dist/browser/utilities/analytics/metrics/vocabulary.js +2 -2
  18. package/dist/browser/utilities/analytics/reference/browser.js +16 -16
  19. package/dist/browser/utilities/analytics/reference/index.js +25 -24
  20. package/dist/browser/utils/io.js +29 -25
  21. package/dist/browser/utils/sqlite.js +5 -5
  22. package/dist/browser/utils/zip.js +2 -4
  23. package/dist/browser/validation/gridsetValidator.js +2 -2
  24. package/dist/browser/validation/obfValidator.js +2 -2
  25. package/dist/browser/validation/snapValidator.js +3 -3
  26. package/dist/browser/validation/touchChatValidator.js +3 -3
  27. package/dist/cli/index.js +19 -16
  28. package/dist/core/baseProcessor.d.ts +1 -1
  29. package/dist/processors/applePanelsProcessor.js +24 -24
  30. package/dist/processors/astericsGridProcessor.d.ts +4 -4
  31. package/dist/processors/astericsGridProcessor.js +22 -24
  32. package/dist/processors/dotProcessor.js +6 -10
  33. package/dist/processors/excelProcessor.d.ts +3 -3
  34. package/dist/processors/excelProcessor.js +10 -13
  35. package/dist/processors/gridset/helpers.d.ts +9 -9
  36. package/dist/processors/gridset/helpers.js +33 -30
  37. package/dist/processors/gridset/symbolExtractor.d.ts +1 -1
  38. package/dist/processors/gridset/symbolExtractor.js +2 -2
  39. package/dist/processors/gridset/symbolSearch.d.ts +10 -10
  40. package/dist/processors/gridset/symbolSearch.js +22 -22
  41. package/dist/processors/gridset/symbols.d.ts +3 -3
  42. package/dist/processors/gridset/symbols.js +14 -14
  43. package/dist/processors/gridsetProcessor.d.ts +2 -2
  44. package/dist/processors/gridsetProcessor.js +7 -7
  45. package/dist/processors/obfProcessor.d.ts +2 -2
  46. package/dist/processors/obfProcessor.js +54 -47
  47. package/dist/processors/obfsetProcessor.js +1 -2
  48. package/dist/processors/opmlProcessor.js +6 -10
  49. package/dist/processors/snap/helpers.d.ts +8 -8
  50. package/dist/processors/snap/helpers.js +34 -30
  51. package/dist/processors/snapProcessor.d.ts +2 -2
  52. package/dist/processors/snapProcessor.js +28 -28
  53. package/dist/processors/touchchatProcessor.d.ts +2 -2
  54. package/dist/processors/touchchatProcessor.js +24 -25
  55. package/dist/types/aac.d.ts +2 -2
  56. package/dist/utilities/analytics/history.d.ts +8 -8
  57. package/dist/utilities/analytics/history.js +24 -18
  58. package/dist/utilities/analytics/index.d.ts +1 -1
  59. package/dist/utilities/analytics/index.js +3 -2
  60. package/dist/utilities/analytics/metrics/comparison.d.ts +1 -1
  61. package/dist/utilities/analytics/metrics/comparison.js +16 -16
  62. package/dist/utilities/analytics/metrics/vocabulary.d.ts +1 -1
  63. package/dist/utilities/analytics/metrics/vocabulary.js +2 -2
  64. package/dist/utilities/analytics/reference/browser.d.ts +9 -9
  65. package/dist/utilities/analytics/reference/browser.js +16 -16
  66. package/dist/utilities/analytics/reference/index.d.ts +21 -21
  67. package/dist/utilities/analytics/reference/index.js +25 -24
  68. package/dist/utilities/symbolTools.d.ts +5 -5
  69. package/dist/utilities/symbolTools.js +10 -8
  70. package/dist/utils/io.d.ts +11 -11
  71. package/dist/utils/io.js +29 -25
  72. package/dist/utils/sqlite.d.ts +1 -1
  73. package/dist/utils/sqlite.js +5 -5
  74. package/dist/utils/zip.js +2 -4
  75. package/dist/validation/applePanelsValidator.js +7 -6
  76. package/dist/validation/astericsValidator.js +2 -2
  77. package/dist/validation/dotValidator.js +2 -2
  78. package/dist/validation/excelValidator.js +2 -2
  79. package/dist/validation/gridsetValidator.js +2 -2
  80. package/dist/validation/index.js +2 -2
  81. package/dist/validation/obfValidator.js +2 -2
  82. package/dist/validation/obfsetValidator.js +2 -2
  83. package/dist/validation/opmlValidator.js +2 -2
  84. package/dist/validation/snapValidator.js +3 -3
  85. package/dist/validation/touchChatValidator.js +3 -3
  86. package/docs/BROWSER_USAGE.md +0 -40
  87. package/package.json +1 -1
@@ -16,7 +16,7 @@ export declare function getAllowedImageEntries(tree: AACTree): Set<string>;
16
16
  * @param entryPath Symbol identifier (e.g., "SYM:12345")
17
17
  * @returns Image data buffer or null if not found
18
18
  */
19
- export declare function openImage(dbOrFile: ProcessorInput, entryPath: string, fileAdapter?: FileAdapter): Buffer | null;
19
+ export declare function openImage(dbOrFile: ProcessorInput, entryPath: string, fileAdapter?: FileAdapter): Promise<Buffer | null>;
20
20
  /**
21
21
  * Snap package path information
22
22
  */
@@ -53,14 +53,14 @@ export interface SnapUsageEntry {
53
53
  * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
54
54
  * @returns Array of Snap package path information
55
55
  */
56
- export declare function findSnapPackages(packageNamePattern?: string, fileAdapter?: FileAdapter): SnapPackagePath[];
56
+ export declare function findSnapPackages(packageNamePattern?: string, fileAdapter?: FileAdapter): Promise<SnapPackagePath[]>;
57
57
  /**
58
58
  * Find the first Snap package path matching the pattern
59
59
  * Convenience method for when you expect only one Snap installation
60
60
  * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
61
61
  * @returns Path to the first matching Snap package, or null if not found
62
62
  */
63
- export declare function findSnapPackagePath(packageNamePattern?: string, fileAdapter?: FileAdapter): string | null;
63
+ export declare function findSnapPackagePath(packageNamePattern?: string, fileAdapter?: FileAdapter): Promise<string | null>;
64
64
  /**
65
65
  * Find Snap user directories and their vocab files (.sps/.spb)
66
66
  * Typical path:
@@ -68,14 +68,14 @@ export declare function findSnapPackagePath(packageNamePattern?: string, fileAda
68
68
  * @param packageNamePattern Optional package filter (default TobiiDynavox)
69
69
  * @returns Array of user info with vocab paths
70
70
  */
71
- export declare function findSnapUsers(packageNamePattern?: string, fileAdapter?: FileAdapter): SnapUserInfo[];
71
+ export declare function findSnapUsers(packageNamePattern?: string, fileAdapter?: FileAdapter): Promise<SnapUserInfo[]>;
72
72
  /**
73
73
  * Find vocab files for a specific Snap user (or all users)
74
74
  * @param userId Optional user identifier filter (case-sensitive directory name)
75
75
  * @param packageNamePattern Optional package filter
76
76
  * @returns Array of vocab file paths
77
77
  */
78
- export declare function findSnapUserVocabularies(userId?: string, packageNamePattern?: string, fileAdapter?: FileAdapter): string[];
78
+ export declare function findSnapUserVocabularies(userId?: string, packageNamePattern?: string, fileAdapter?: FileAdapter): Promise<string[]>;
79
79
  /**
80
80
  * Attempt to find history/analytics files for a Snap user by name
81
81
  * Currently searches for files containing "history" under the user directory
@@ -83,7 +83,7 @@ export declare function findSnapUserVocabularies(userId?: string, packageNamePat
83
83
  * @param packageNamePattern Optional package filter
84
84
  * @returns Array of history file paths (may be empty if not found)
85
85
  */
86
- export declare function findSnapUserHistory(userId: string, packageNamePattern?: string, fileAdapter?: FileAdapter): string[];
86
+ export declare function findSnapUserHistory(userId: string, packageNamePattern?: string, fileAdapter?: FileAdapter): Promise<string[]>;
87
87
  /**
88
88
  * Check whether TD Snap appears to be installed (Windows only)
89
89
  */
@@ -91,8 +91,8 @@ export declare function isSnapInstalled(packageNamePattern?: string): boolean;
91
91
  /**
92
92
  * Read Snap usage history from a pageset file (.sps/.spb)
93
93
  */
94
- export declare function readSnapUsage(pagesetPath: string, fileAdapter?: FileAdapter): SnapUsageEntry[];
94
+ export declare function readSnapUsage(pagesetPath: string, fileAdapter?: FileAdapter): Promise<SnapUsageEntry[]>;
95
95
  /**
96
96
  * Read Snap usage history for a user (all pagesets)
97
97
  */
98
- export declare function readSnapUsageForUser(userId?: string, packageNamePattern?: string): SnapUsageEntry[];
98
+ export declare function readSnapUsageForUser(userId?: string, packageNamePattern?: string): Promise<SnapUsageEntry[]>;
@@ -23,7 +23,7 @@ const sqlite_1 = require("../../utils/sqlite");
23
23
  // We extract PNG/JPEG images but skip vector graphics (requires renderer).
24
24
  // NOTE: Snap buttons currently do not populate resolvedImageEntry; these helpers
25
25
  // therefore return empty collections until image resolution is implemented.
26
- function collectFiles(root, matcher, maxDepth = 3, fileAdapter = io_1.defaultFileAdapter) {
26
+ async function collectFiles(root, matcher, maxDepth = 3, fileAdapter = io_1.defaultFileAdapter) {
27
27
  const { listDir, join, isDirectory } = fileAdapter;
28
28
  const results = new Set();
29
29
  const stack = [{ dir: root, depth: 0 }];
@@ -35,14 +35,14 @@ function collectFiles(root, matcher, maxDepth = 3, fileAdapter = io_1.defaultFil
35
35
  continue;
36
36
  let entries;
37
37
  try {
38
- entries = listDir(current.dir);
38
+ entries = await listDir(current.dir);
39
39
  }
40
40
  catch (error) {
41
41
  continue;
42
42
  }
43
43
  for (const entry of entries) {
44
44
  const fullPath = join(current.dir, entry);
45
- if (isDirectory(entry)) {
45
+ if (await isDirectory(entry)) {
46
46
  stack.push({ dir: fullPath, depth: current.depth + 1 });
47
47
  }
48
48
  else if (matcher(fullPath)) {
@@ -96,15 +96,15 @@ function getAllowedImageEntries(tree) {
96
96
  * @param entryPath Symbol identifier (e.g., "SYM:12345")
97
97
  * @returns Image data buffer or null if not found
98
98
  */
99
- function openImage(dbOrFile, entryPath, fileAdapter = io_1.defaultFileAdapter) {
99
+ async function openImage(dbOrFile, entryPath, fileAdapter = io_1.defaultFileAdapter) {
100
100
  const { mkTempDir, join, writeBinaryToPath, removePath, dirname } = fileAdapter;
101
101
  let dbPath;
102
102
  let cleanupNeeded = false;
103
103
  // Handle Buffer input by writing to temp file
104
104
  if (Buffer.isBuffer(dbOrFile)) {
105
- const tempDir = mkTempDir(join(process.cwd(), 'snap-'));
105
+ const tempDir = await mkTempDir(join(process.cwd(), 'snap-'));
106
106
  dbPath = join(tempDir, 'temp.sps');
107
- writeBinaryToPath(dbPath, dbOrFile);
107
+ await writeBinaryToPath(dbPath, dbOrFile);
108
108
  cleanupNeeded = true;
109
109
  }
110
110
  else if (typeof dbOrFile === 'string') {
@@ -139,9 +139,9 @@ function openImage(dbOrFile, entryPath, fileAdapter = io_1.defaultFileAdapter) {
139
139
  }
140
140
  if (cleanupNeeded && dbPath) {
141
141
  try {
142
- removePath(dbPath);
142
+ await removePath(dbPath);
143
143
  const dir = dirname(dbPath);
144
- removePath(dir);
144
+ await removePath(dir);
145
145
  }
146
146
  catch (e) {
147
147
  // Ignore cleanup errors
@@ -155,7 +155,7 @@ function openImage(dbOrFile, entryPath, fileAdapter = io_1.defaultFileAdapter) {
155
155
  * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
156
156
  * @returns Array of Snap package path information
157
157
  */
158
- function findSnapPackages(packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
158
+ async function findSnapPackages(packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
159
159
  const { join, listDir, isDirectory, pathExists } = fileAdapter;
160
160
  const results = [];
161
161
  // Only works on Windows
@@ -169,13 +169,13 @@ function findSnapPackages(packageNamePattern = 'TobiiDynavox', fileAdapter = io_
169
169
  }
170
170
  const packagesPath = join(localAppData, 'Packages');
171
171
  // Check if Packages directory exists
172
- if (!pathExists(packagesPath)) {
172
+ if (!(await pathExists(packagesPath))) {
173
173
  return results;
174
174
  }
175
175
  // Enumerate packages
176
- const packages = listDir(packagesPath);
176
+ const packages = await listDir(packagesPath);
177
177
  for (const packageDir of packages) {
178
- if (!isDirectory(packageDir))
178
+ if (!(await isDirectory(packageDir)))
179
179
  continue;
180
180
  const packageName = packageDir;
181
181
  // Filter by pattern
@@ -198,8 +198,8 @@ function findSnapPackages(packageNamePattern = 'TobiiDynavox', fileAdapter = io_
198
198
  * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
199
199
  * @returns Path to the first matching Snap package, or null if not found
200
200
  */
201
- function findSnapPackagePath(packageNamePattern = 'TobiiDynavox', fileAdapter) {
202
- const packages = findSnapPackages(packageNamePattern, fileAdapter);
201
+ async function findSnapPackagePath(packageNamePattern = 'TobiiDynavox', fileAdapter) {
202
+ const packages = await findSnapPackages(packageNamePattern, fileAdapter);
203
203
  return packages.length > 0 ? packages[0].packagePath : null;
204
204
  }
205
205
  /**
@@ -209,28 +209,28 @@ function findSnapPackagePath(packageNamePattern = 'TobiiDynavox', fileAdapter) {
209
209
  * @param packageNamePattern Optional package filter (default TobiiDynavox)
210
210
  * @returns Array of user info with vocab paths
211
211
  */
212
- function findSnapUsers(packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
212
+ async function findSnapUsers(packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
213
213
  const { join, listDir, isDirectory, pathExists } = fileAdapter;
214
214
  const results = [];
215
215
  if (process.platform !== 'win32') {
216
216
  return results;
217
217
  }
218
- const packagePath = findSnapPackagePath(packageNamePattern, fileAdapter);
218
+ const packagePath = await findSnapPackagePath(packageNamePattern, fileAdapter);
219
219
  if (!packagePath) {
220
220
  return results;
221
221
  }
222
222
  const usersRoot = join(packagePath, 'LocalState', 'Users');
223
- if (!pathExists(usersRoot)) {
223
+ if (!(await pathExists(usersRoot))) {
224
224
  return results;
225
225
  }
226
- const entries = listDir(usersRoot);
226
+ const entries = await listDir(usersRoot);
227
227
  for (const entry of entries) {
228
- if (!isDirectory(entry))
228
+ if (!(await isDirectory(entry)))
229
229
  continue;
230
230
  if (entry.toLowerCase().startsWith('swiftkey'))
231
231
  continue;
232
232
  const userPath = join(usersRoot, entry);
233
- const vocabPaths = collectFiles(userPath, (full) => {
233
+ const vocabPaths = await collectFiles(userPath, (full) => {
234
234
  const ext = (0, io_1.extname)(full).toLowerCase();
235
235
  return ext === '.sps' || ext === '.spb';
236
236
  }, 2, fileAdapter);
@@ -248,8 +248,9 @@ function findSnapUsers(packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.d
248
248
  * @param packageNamePattern Optional package filter
249
249
  * @returns Array of vocab file paths
250
250
  */
251
- function findSnapUserVocabularies(userId, packageNamePattern = 'TobiiDynavox', fileAdapter) {
252
- const users = findSnapUsers(packageNamePattern, fileAdapter).filter((u) => !userId || u.userId === userId);
251
+ async function findSnapUserVocabularies(userId, packageNamePattern = 'TobiiDynavox', fileAdapter) {
252
+ const allUsers = await findSnapUsers(packageNamePattern, fileAdapter);
253
+ const users = allUsers.filter((u) => !userId || u.userId === userId);
253
254
  return users.flatMap((u) => u.vocabPaths);
254
255
  }
255
256
  /**
@@ -259,12 +260,13 @@ function findSnapUserVocabularies(userId, packageNamePattern = 'TobiiDynavox', f
259
260
  * @param packageNamePattern Optional package filter
260
261
  * @returns Array of history file paths (may be empty if not found)
261
262
  */
262
- function findSnapUserHistory(userId, packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
263
+ async function findSnapUserHistory(userId, packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
263
264
  const { basename } = fileAdapter;
264
- const user = findSnapUsers(packageNamePattern, fileAdapter).find((u) => u.userId === userId);
265
+ const allUsers = await findSnapUsers(packageNamePattern, fileAdapter);
266
+ const user = allUsers.find((u) => u.userId === userId);
265
267
  if (!user)
266
268
  return [];
267
- return collectFiles(user.userPath, (full) => basename(full).toLowerCase().includes('history'), 2, fileAdapter);
269
+ return await collectFiles(user.userPath, (full) => basename(full).toLowerCase().includes('history'), 2, fileAdapter);
268
270
  }
269
271
  /**
270
272
  * Check whether TD Snap appears to be installed (Windows only)
@@ -277,9 +279,9 @@ function isSnapInstalled(packageNamePattern = 'TobiiDynavox') {
277
279
  /**
278
280
  * Read Snap usage history from a pageset file (.sps/.spb)
279
281
  */
280
- function readSnapUsage(pagesetPath, fileAdapter = io_1.defaultFileAdapter) {
282
+ async function readSnapUsage(pagesetPath, fileAdapter = io_1.defaultFileAdapter) {
281
283
  const { pathExists } = fileAdapter;
282
- if (!pathExists(pagesetPath))
284
+ if (!(await pathExists(pagesetPath)))
283
285
  return [];
284
286
  const Database = (0, sqlite_1.requireBetterSqlite3)();
285
287
  const db = new Database(pagesetPath, { readonly: true });
@@ -336,8 +338,10 @@ function readSnapUsage(pagesetPath, fileAdapter = io_1.defaultFileAdapter) {
336
338
  /**
337
339
  * Read Snap usage history for a user (all pagesets)
338
340
  */
339
- function readSnapUsageForUser(userId, packageNamePattern = 'TobiiDynavox') {
340
- const users = findSnapUsers(packageNamePattern).filter((u) => !userId || u.userId === userId);
341
+ async function readSnapUsageForUser(userId, packageNamePattern = 'TobiiDynavox') {
342
+ const allUsers = await findSnapUsers(packageNamePattern);
343
+ const users = allUsers.filter((u) => !userId || u.userId === userId);
341
344
  const pagesets = users.flatMap((u) => u.vocabPaths);
342
- return pagesets.flatMap((p) => readSnapUsage(p));
345
+ const usage = await Promise.all(pagesets.map(async (p) => await readSnapUsage(p)));
346
+ return usage.flat();
343
347
  }
@@ -54,9 +54,9 @@ declare class SnapProcessor extends BaseProcessor {
54
54
  * Get available PageLayouts for a Snap file
55
55
  * Useful for UI components that want to let users select layout size
56
56
  * @param filePath - Path to the Snap file
57
- * @returns Array of available PageLayouts with their dimensions
57
+ * @returns Promise resolving to available PageLayouts with their dimensions
58
58
  */
59
- getAvailablePageLayouts(filePath: string): PageLayoutInfo[];
59
+ getAvailablePageLayouts(filePath: string): Promise<PageLayoutInfo[]>;
60
60
  }
61
61
  /**
62
62
  * Interface for PageLayout information returned by getAvailablePageLayouts
@@ -68,7 +68,6 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
68
68
  }
69
69
  async loadIntoTree(filePathOrBuffer) {
70
70
  const { writeBinaryToPath, removePath, mkTempDir, basename, join } = this.options.fileAdapter;
71
- await Promise.resolve();
72
71
  const tree = new treeStructure_1.AACTree();
73
72
  let dbResult = null;
74
73
  let cleanupTempZip = null;
@@ -79,22 +78,22 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
79
78
  const fileName = basename(filePathOrBuffer).toLowerCase();
80
79
  if (fileName.endsWith('.sub.zip') || filePathOrBuffer.endsWith('.sub')) {
81
80
  // Extract .sub.zip to find the embedded .sps file
82
- const tempDir = mkTempDir('snap-sub-');
81
+ const tempDir = await mkTempDir('snap-sub-');
83
82
  const zip = await this.options.zipAdapter(filePathOrBuffer);
84
83
  // Find the .sps file in the archive
85
84
  const files = zip.listFiles();
86
85
  const spsFile = files.find((f) => f.endsWith('.sps'));
87
86
  if (!spsFile) {
88
- removePath(tempDir, { recursive: true, force: true });
87
+ await removePath(tempDir, { recursive: true, force: true });
89
88
  throw new Error('No .sps file found in .sub.zip archive');
90
89
  }
91
90
  // Extract the .sps file
92
91
  const spsData = await zip.readFile(spsFile);
93
92
  const extractedSpsPath = join(tempDir, basename(spsFile));
94
- writeBinaryToPath(extractedSpsPath, Buffer.from(spsData));
93
+ await writeBinaryToPath(extractedSpsPath, Buffer.from(spsData));
95
94
  inputFile = extractedSpsPath;
96
- cleanupTempZip = () => {
97
- removePath(tempDir, { recursive: true, force: true });
95
+ cleanupTempZip = async () => {
96
+ await removePath(tempDir, { recursive: true, force: true });
98
97
  };
99
98
  }
100
99
  }
@@ -686,7 +685,7 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
686
685
  }
687
686
  finally {
688
687
  if (dbResult?.cleanup) {
689
- dbResult.cleanup();
688
+ await dbResult.cleanup();
690
689
  }
691
690
  else if (dbResult?.db) {
692
691
  dbResult.db.close();
@@ -694,7 +693,7 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
694
693
  // Clean up temporary extracted .sps file from .sub.zip
695
694
  if (cleanupTempZip) {
696
695
  try {
697
- cleanupTempZip();
696
+ await cleanupTempZip();
698
697
  }
699
698
  catch (e) {
700
699
  console.warn('[SnapProcessor] Failed to clean up temporary .sps file:', e);
@@ -710,13 +709,14 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
710
709
  if (typeof filePathOrBuffer === 'string') {
711
710
  const inputPath = filePathOrBuffer;
712
711
  const outputDir = dirname(outputPath);
713
- if (!pathExists(outputDir)) {
714
- mkDir(outputDir, { recursive: true });
712
+ const dirExists = await pathExists(outputDir);
713
+ if (!dirExists) {
714
+ await mkDir(outputDir, { recursive: true });
715
715
  }
716
- if (pathExists(outputPath)) {
717
- removePath(outputPath);
716
+ if (await pathExists(outputPath)) {
717
+ await removePath(outputPath);
718
718
  }
719
- writeBinaryToPath(outputPath, readBinaryFromInput(inputPath));
719
+ await writeBinaryToPath(outputPath, await readBinaryFromInput(inputPath));
720
720
  const Database = (0, sqlite_1.requireBetterSqlite3)();
721
721
  const db = new Database(outputPath, { readonly: false });
722
722
  try {
@@ -778,7 +778,7 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
778
778
  finally {
779
779
  db.close();
780
780
  }
781
- return readBinaryFromInput(outputPath);
781
+ return await readBinaryFromInput(outputPath);
782
782
  }
783
783
  // Fallback for buffer inputs: rebuild from tree (may drop Snap assets)
784
784
  const tree = await this.loadIntoTree(filePathOrBuffer);
@@ -805,20 +805,20 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
805
805
  });
806
806
  });
807
807
  await this.saveFromTree(tree, outputPath);
808
- return readBinaryFromInput(outputPath);
808
+ return await readBinaryFromInput(outputPath);
809
809
  }
810
810
  async saveFromTree(tree, outputPath) {
811
811
  const { pathExists, mkDir, removePath, dirname } = this.options.fileAdapter;
812
812
  if (!(0, io_1.isNodeRuntime)()) {
813
813
  throw new Error('saveFromTree is only supported in Node.js environments for Snap files.');
814
814
  }
815
- await Promise.resolve();
816
815
  const outputDir = dirname(outputPath);
817
- if (!pathExists(outputDir)) {
818
- mkDir(outputDir, { recursive: true });
816
+ const dirExists = await pathExists(outputDir);
817
+ if (!dirExists) {
818
+ await mkDir(outputDir, { recursive: true });
819
819
  }
820
- if (pathExists(outputPath)) {
821
- removePath(outputPath);
820
+ if (await pathExists(outputPath)) {
821
+ await removePath(outputPath);
822
822
  }
823
823
  // Create a new SQLite database for Snap format
824
824
  const Database = (0, sqlite_1.requireBetterSqlite3)();
@@ -1053,7 +1053,6 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
1053
1053
  * Add audio recording to a button in the database
1054
1054
  */
1055
1055
  async addAudioToButton(dbPath, buttonId, audioData, metadata) {
1056
- await Promise.resolve();
1057
1056
  if (!(0, io_1.isNodeRuntime)()) {
1058
1057
  throw new Error('addAudioToButton is only supported in Node.js environments.');
1059
1058
  }
@@ -1091,7 +1090,7 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
1091
1090
  const updateButton = db.prepare('UPDATE Button SET MessageRecordingId = ?, UseMessageRecording = 1, SerializedMessageSoundMetadata = ? WHERE Id = ?');
1092
1091
  const metadataJson = metadata ? JSON.stringify({ FileName: metadata }) : null;
1093
1092
  updateButton.run(audioId, metadataJson, buttonId);
1094
- return audioId;
1093
+ return Promise.resolve(audioId);
1095
1094
  }
1096
1095
  finally {
1097
1096
  db.close();
@@ -1106,7 +1105,7 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
1106
1105
  throw new Error('createAudioEnhancedPageset is only supported in Node.js environments.');
1107
1106
  }
1108
1107
  // Copy the source database to target
1109
- writeBinaryToPath(targetDbPath, readBinaryFromInput(sourceDbPath));
1108
+ await writeBinaryToPath(targetDbPath, await readBinaryFromInput(sourceDbPath));
1110
1109
  // Add audio recordings to the copy
1111
1110
  for (const [buttonId, audioInfo] of audioMappings.entries()) {
1112
1111
  await this.addAudioToButton(targetDbPath, buttonId, audioInfo.audioData, audioInfo.metadata);
@@ -1174,16 +1173,16 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
1174
1173
  * Get available PageLayouts for a Snap file
1175
1174
  * Useful for UI components that want to let users select layout size
1176
1175
  * @param filePath - Path to the Snap file
1177
- * @returns Array of available PageLayouts with their dimensions
1176
+ * @returns Promise resolving to available PageLayouts with their dimensions
1178
1177
  */
1179
- getAvailablePageLayouts(filePath) {
1178
+ async getAvailablePageLayouts(filePath) {
1180
1179
  const { writeBinaryToPath, removePath, pathExists, join } = this.options.fileAdapter;
1181
1180
  if (!(0, io_1.isNodeRuntime)()) {
1182
1181
  throw new Error('getAvailablePageLayouts is only supported in Node.js environments.');
1183
1182
  }
1184
1183
  const dbPath = typeof filePath === 'string' ? filePath : join(process.cwd(), 'temp.spb');
1185
1184
  if (Buffer.isBuffer(filePath)) {
1186
- writeBinaryToPath(dbPath, filePath);
1185
+ await writeBinaryToPath(dbPath, filePath);
1187
1186
  }
1188
1187
  let db = null;
1189
1188
  try {
@@ -1234,9 +1233,10 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
1234
1233
  db.close();
1235
1234
  }
1236
1235
  // Clean up temporary file if created from buffer
1237
- if (Buffer.isBuffer(filePath) && pathExists(dbPath)) {
1236
+ const exists = await pathExists(dbPath);
1237
+ if (Buffer.isBuffer(filePath) && exists) {
1238
1238
  try {
1239
- removePath(dbPath);
1239
+ await removePath(dbPath);
1240
1240
  }
1241
1241
  catch (e) {
1242
1242
  console.warn('Failed to clean up temporary file:', e);
@@ -39,7 +39,7 @@ declare class TouchChatProcessor extends BaseProcessor {
39
39
  * This method uses shared translation utilities that work across all AAC formats.
40
40
  *
41
41
  * @param filePathOrBuffer - Path to TouchChat .ce file or buffer
42
- * @returns Array of symbol information for LLM processing
42
+ * @returns Promise resolving to symbol information for LLM processing
43
43
  */
44
44
  extractSymbolsForLLM(filePathOrBuffer: string | Buffer): Promise<ButtonForTranslation[]>;
45
45
  /**
@@ -52,7 +52,7 @@ declare class TouchChatProcessor extends BaseProcessor {
52
52
  * @param llmTranslations - Array of LLM translations with symbol info
53
53
  * @param outputPath - Where to save the translated TouchChat file
54
54
  * @param options - Translation options (e.g., allowPartial for testing)
55
- * @returns Buffer of the translated TouchChat file
55
+ * @returns Promise resolving to a buffer of the translated TouchChat file
56
56
  */
57
57
  processLLMTranslations(filePathOrBuffer: string | Uint8Array, llmTranslations: LLMLTranslationResult[], outputPath: string, options?: {
58
58
  allowPartial?: boolean;
@@ -59,7 +59,6 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
59
59
  }
60
60
  async loadIntoTree(filePathOrBuffer) {
61
61
  const { readBinaryFromInput } = this.options.fileAdapter;
62
- await Promise.resolve();
63
62
  // Unzip .ce file, extract the .c4v SQLite DB, and parse pages/buttons
64
63
  let db = null;
65
64
  let cleanup;
@@ -67,7 +66,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
67
66
  // Store source file path or buffer
68
67
  this.sourceFile = filePathOrBuffer;
69
68
  // Step 1: Unzip
70
- const zipInput = readBinaryFromInput(filePathOrBuffer);
69
+ const zipInput = await readBinaryFromInput(filePathOrBuffer);
71
70
  const zip = await this.options.zipAdapter(zipInput);
72
71
  const vocabEntry = zip.listFiles().find((name) => name.endsWith('.c4v'));
73
72
  if (!vocabEntry) {
@@ -472,7 +471,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
472
471
  finally {
473
472
  // Clean up
474
473
  if (cleanup) {
475
- cleanup();
474
+ await cleanup();
476
475
  }
477
476
  else if (db) {
478
477
  db.close();
@@ -495,11 +494,12 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
495
494
  if (typeof filePathOrBuffer === 'string') {
496
495
  const inputPath = filePathOrBuffer;
497
496
  const outputDir = dirname(outputPath);
498
- if (!pathExists(outputDir)) {
499
- mkDir(outputDir, { recursive: true });
497
+ const dirExists = await pathExists(outputDir);
498
+ if (!dirExists) {
499
+ await mkDir(outputDir, { recursive: true });
500
500
  }
501
- if (pathExists(outputPath)) {
502
- removePath(outputPath);
501
+ if (await pathExists(outputPath)) {
502
+ await removePath(outputPath);
503
503
  }
504
504
  const zip = await this.options.zipAdapter(inputPath);
505
505
  const entries = (0, gridset_1.getZipEntriesFromAdapter)(zip);
@@ -507,10 +507,10 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
507
507
  if (!vocabEntry) {
508
508
  throw new Error('No .c4v vocab DB found in TouchChat export');
509
509
  }
510
- const tempDir = mkTempDir('touchchat-translate-');
510
+ const tempDir = await mkTempDir('touchchat-translate-');
511
511
  const dbPath = join(tempDir, 'vocab.c4v');
512
512
  try {
513
- writeBinaryToPath(dbPath, await vocabEntry.getData());
513
+ await writeBinaryToPath(dbPath, await vocabEntry.getData());
514
514
  const Database = (0, sqlite_1.requireBetterSqlite3)();
515
515
  const db = new Database(dbPath, { readonly: false });
516
516
  try {
@@ -577,20 +577,20 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
577
577
  }
578
578
  files.push({
579
579
  name: vocabEntry.entryName,
580
- data: readBinaryFromInput(dbPath),
580
+ data: await readBinaryFromInput(dbPath),
581
581
  });
582
582
  const zipData = await outputZip.writeFiles(files);
583
- writeBinaryToPath(outputPath, zipData);
583
+ await writeBinaryToPath(outputPath, zipData);
584
584
  }
585
585
  finally {
586
586
  try {
587
- removePath(tempDir, { recursive: true, force: true });
587
+ await removePath(tempDir, { recursive: true, force: true });
588
588
  }
589
589
  catch {
590
590
  // Best-effort cleanup
591
591
  }
592
592
  }
593
- return readBinaryFromInput(outputPath);
593
+ return await readBinaryFromInput(outputPath);
594
594
  }
595
595
  // Fallback for buffer inputs: rebuild from tree (may drop TouchChat metadata)
596
596
  const tree = await this.loadIntoTree(filePathOrBuffer);
@@ -617,16 +617,15 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
617
617
  });
618
618
  });
619
619
  await this.saveFromTree(tree, outputPath);
620
- return readBinaryFromInput(outputPath);
620
+ return await readBinaryFromInput(outputPath);
621
621
  }
622
622
  async saveFromTree(tree, outputPath) {
623
623
  const { writeBinaryToPath, mkTempDir, readBinaryFromInput, pathExists, removePath, join } = this.options.fileAdapter;
624
- await Promise.resolve();
625
624
  if (!(0, io_1.isNodeRuntime)()) {
626
625
  throw new Error('saveFromTree is only supported in Node.js environments for TouchChat files.');
627
626
  }
628
627
  // Create a TouchChat database that matches the expected schema for loading
629
- const tmpDir = mkTempDir('touchchat-export-');
628
+ const tmpDir = await mkTempDir('touchchat-export-');
630
629
  const dbPath = join(tmpDir, 'vocab.c4v');
631
630
  try {
632
631
  const Database = (0, sqlite_1.requireBetterSqlite3)();
@@ -921,19 +920,19 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
921
920
  db.close();
922
921
  // Create zip file with the database
923
922
  const zip = await this.options.zipAdapter();
924
- const data = readBinaryFromInput(dbPath);
923
+ const data = await readBinaryFromInput(dbPath);
925
924
  const zipData = await zip.writeFiles([
926
925
  {
927
926
  name: 'vocab.c4v',
928
927
  data,
929
928
  },
930
929
  ]);
931
- writeBinaryToPath(outputPath, zipData);
930
+ await writeBinaryToPath(outputPath, zipData);
932
931
  }
933
932
  finally {
934
933
  // Clean up
935
- if (pathExists(tmpDir)) {
936
- removePath(tmpDir, { recursive: true, force: true });
934
+ if (await pathExists(tmpDir)) {
935
+ await removePath(tmpDir, { recursive: true, force: true });
937
936
  }
938
937
  }
939
938
  }
@@ -1016,7 +1015,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
1016
1015
  const outputPath = filePath.replace(/\.ce$/, '_translated.ce');
1017
1016
  // Use existing processTexts method
1018
1017
  await this.processTexts(filePath, translations, outputPath);
1019
- return Promise.resolve(outputPath);
1018
+ return outputPath;
1020
1019
  }
1021
1020
  catch (error) {
1022
1021
  return Promise.reject(new Error(`Failed to generate translated download: ${error instanceof Error ? error.message : 'Unknown error'}`));
@@ -1028,7 +1027,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
1028
1027
  * @returns Promise with validation result
1029
1028
  */
1030
1029
  async validate(filePath) {
1031
- return touchChatValidator_1.TouchChatValidator.validateFile(filePath, this.options.fileAdapter);
1030
+ return await touchChatValidator_1.TouchChatValidator.validateFile(filePath, this.options.fileAdapter);
1032
1031
  }
1033
1032
  /**
1034
1033
  * Extract symbol information from a TouchChat file for LLM-based translation.
@@ -1037,7 +1036,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
1037
1036
  * This method uses shared translation utilities that work across all AAC formats.
1038
1037
  *
1039
1038
  * @param filePathOrBuffer - Path to TouchChat .ce file or buffer
1040
- * @returns Array of symbol information for LLM processing
1039
+ * @returns Promise resolving to symbol information for LLM processing
1041
1040
  */
1042
1041
  async extractSymbolsForLLM(filePathOrBuffer) {
1043
1042
  const tree = await this.loadIntoTree(filePathOrBuffer);
@@ -1067,7 +1066,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
1067
1066
  * @param llmTranslations - Array of LLM translations with symbol info
1068
1067
  * @param outputPath - Where to save the translated TouchChat file
1069
1068
  * @param options - Translation options (e.g., allowPartial for testing)
1070
- * @returns Buffer of the translated TouchChat file
1069
+ * @returns Promise resolving to a buffer of the translated TouchChat file
1071
1070
  */
1072
1071
  async processLLMTranslations(filePathOrBuffer, llmTranslations, outputPath, options) {
1073
1072
  const { readBinaryFromInput } = this.options.fileAdapter;
@@ -1112,7 +1111,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
1112
1111
  });
1113
1112
  // Save and return
1114
1113
  await this.saveFromTree(tree, outputPath);
1115
- return readBinaryFromInput(outputPath);
1114
+ return await readBinaryFromInput(outputPath);
1116
1115
  }
1117
1116
  }
1118
1117
  exports.TouchChatProcessor = TouchChatProcessor;
@@ -203,6 +203,6 @@ export interface AACTree {
203
203
  getPage(id: string): AACPage | undefined;
204
204
  }
205
205
  export interface AACProcessor {
206
- extractTexts(filePath: string | Buffer): string[];
207
- loadIntoTree(filePath: string | Buffer): AACTree;
206
+ extractTexts(filePath: string | Buffer): Promise<string[]>;
207
+ loadIntoTree(filePath: string | Buffer): Promise<AACTree>;
208
208
  }