@willwade/aac-processors 0.1.21 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/processors/applePanelsProcessor.js +24 -24
- package/dist/browser/processors/astericsGridProcessor.js +22 -24
- package/dist/browser/processors/dotProcessor.js +6 -10
- package/dist/browser/processors/gridset/helpers.js +33 -30
- package/dist/browser/processors/gridset/symbolExtractor.js +2 -2
- package/dist/browser/processors/gridset/symbolSearch.js +22 -22
- package/dist/browser/processors/gridset/symbols.js +14 -14
- package/dist/browser/processors/gridsetProcessor.js +7 -7
- package/dist/browser/processors/obfProcessor.js +24 -25
- package/dist/browser/processors/opmlProcessor.js +6 -10
- package/dist/browser/processors/snap/helpers.js +34 -30
- package/dist/browser/processors/snapProcessor.js +28 -28
- package/dist/browser/processors/touchchatProcessor.js +24 -25
- package/dist/browser/utilities/analytics/history.js +24 -18
- package/dist/browser/utilities/analytics/metrics/comparison.js +16 -16
- package/dist/browser/utilities/analytics/metrics/vocabulary.js +2 -2
- package/dist/browser/utilities/analytics/reference/browser.js +16 -16
- package/dist/browser/utilities/analytics/reference/index.js +25 -24
- package/dist/browser/utils/io.js +29 -25
- package/dist/browser/utils/sqlite.js +5 -5
- package/dist/browser/utils/zip.js +2 -4
- package/dist/browser/validation/gridsetValidator.js +2 -2
- package/dist/browser/validation/obfValidator.js +2 -2
- package/dist/browser/validation/snapValidator.js +3 -3
- package/dist/browser/validation/touchChatValidator.js +3 -3
- package/dist/cli/index.js +19 -16
- package/dist/core/baseProcessor.d.ts +1 -1
- package/dist/processors/applePanelsProcessor.js +24 -24
- package/dist/processors/astericsGridProcessor.d.ts +4 -4
- package/dist/processors/astericsGridProcessor.js +22 -24
- package/dist/processors/dotProcessor.js +6 -10
- package/dist/processors/excelProcessor.d.ts +3 -3
- package/dist/processors/excelProcessor.js +10 -13
- package/dist/processors/gridset/helpers.d.ts +9 -9
- package/dist/processors/gridset/helpers.js +33 -30
- package/dist/processors/gridset/symbolExtractor.d.ts +1 -1
- package/dist/processors/gridset/symbolExtractor.js +2 -2
- package/dist/processors/gridset/symbolSearch.d.ts +10 -10
- package/dist/processors/gridset/symbolSearch.js +22 -22
- package/dist/processors/gridset/symbols.d.ts +3 -3
- package/dist/processors/gridset/symbols.js +14 -14
- package/dist/processors/gridsetProcessor.d.ts +2 -2
- package/dist/processors/gridsetProcessor.js +7 -7
- package/dist/processors/obfProcessor.d.ts +2 -2
- package/dist/processors/obfProcessor.js +24 -25
- package/dist/processors/obfsetProcessor.js +1 -2
- package/dist/processors/opmlProcessor.js +6 -10
- package/dist/processors/snap/helpers.d.ts +8 -8
- package/dist/processors/snap/helpers.js +34 -30
- package/dist/processors/snapProcessor.d.ts +2 -2
- package/dist/processors/snapProcessor.js +28 -28
- package/dist/processors/touchchatProcessor.d.ts +2 -2
- package/dist/processors/touchchatProcessor.js +24 -25
- package/dist/types/aac.d.ts +2 -2
- package/dist/utilities/analytics/history.d.ts +8 -8
- package/dist/utilities/analytics/history.js +24 -18
- package/dist/utilities/analytics/index.d.ts +1 -1
- package/dist/utilities/analytics/index.js +3 -2
- package/dist/utilities/analytics/metrics/comparison.d.ts +1 -1
- package/dist/utilities/analytics/metrics/comparison.js +16 -16
- package/dist/utilities/analytics/metrics/vocabulary.d.ts +1 -1
- package/dist/utilities/analytics/metrics/vocabulary.js +2 -2
- package/dist/utilities/analytics/reference/browser.d.ts +9 -9
- package/dist/utilities/analytics/reference/browser.js +16 -16
- package/dist/utilities/analytics/reference/index.d.ts +21 -21
- package/dist/utilities/analytics/reference/index.js +25 -24
- package/dist/utilities/symbolTools.d.ts +5 -5
- package/dist/utilities/symbolTools.js +10 -8
- package/dist/utils/io.d.ts +11 -11
- package/dist/utils/io.js +29 -25
- package/dist/utils/sqlite.d.ts +1 -1
- package/dist/utils/sqlite.js +5 -5
- package/dist/utils/zip.js +2 -4
- package/dist/validation/applePanelsValidator.js +7 -6
- package/dist/validation/astericsValidator.js +2 -2
- package/dist/validation/dotValidator.js +2 -2
- package/dist/validation/excelValidator.js +2 -2
- package/dist/validation/gridsetValidator.js +2 -2
- package/dist/validation/index.js +2 -2
- package/dist/validation/obfValidator.js +2 -2
- package/dist/validation/obfsetValidator.js +2 -2
- package/dist/validation/opmlValidator.js +2 -2
- package/dist/validation/snapValidator.js +3 -3
- package/dist/validation/touchChatValidator.js +3 -3
- package/package.json +1 -1
|
@@ -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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
714
|
-
|
|
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
|
-
|
|
818
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
499
|
-
|
|
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
|
|
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
|
|
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
|
|
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;
|
package/dist/types/aac.d.ts
CHANGED
|
@@ -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
|
}
|
|
@@ -64,30 +64,30 @@ export declare function exportHistoryToBaton(entries: HistoryEntry[], options?:
|
|
|
64
64
|
/**
|
|
65
65
|
* Read Grid 3 phrase history from a history.sqlite database and tag entries with their source.
|
|
66
66
|
*/
|
|
67
|
-
export declare function readGrid3History(historyDbPath: string): HistoryEntry[]
|
|
67
|
+
export declare function readGrid3History(historyDbPath: string): Promise<HistoryEntry[]>;
|
|
68
68
|
/**
|
|
69
69
|
* Read Grid 3 history for a specific user/language combination.
|
|
70
70
|
*/
|
|
71
|
-
export declare function readGrid3HistoryForUser(userName: string, langCode?: string): HistoryEntry[]
|
|
71
|
+
export declare function readGrid3HistoryForUser(userName: string, langCode?: string): Promise<HistoryEntry[]>;
|
|
72
72
|
/**
|
|
73
73
|
* Read every available Grid 3 history database on the machine.
|
|
74
74
|
*/
|
|
75
|
-
export declare function readAllGrid3History(): HistoryEntry[]
|
|
75
|
+
export declare function readAllGrid3History(): Promise<HistoryEntry[]>;
|
|
76
76
|
/**
|
|
77
77
|
* Read Snap button usage from a pageset database and tag entries with source.
|
|
78
78
|
*/
|
|
79
|
-
export declare function readSnapUsage(pagesetPath: string): HistoryEntry[]
|
|
79
|
+
export declare function readSnapUsage(pagesetPath: string): Promise<HistoryEntry[]>;
|
|
80
80
|
/**
|
|
81
81
|
* Read Snap usage for a specific user across all discovered pagesets.
|
|
82
82
|
*/
|
|
83
|
-
export declare function readSnapUsageForUser(userId?: string, packageNamePattern?: string): HistoryEntry[]
|
|
84
|
-
export declare function listSnapUsers(): SnapUserInfo[]
|
|
83
|
+
export declare function readSnapUsageForUser(userId?: string, packageNamePattern?: string): Promise<HistoryEntry[]>;
|
|
84
|
+
export declare function listSnapUsers(): Promise<SnapUserInfo[]>;
|
|
85
85
|
/**
|
|
86
86
|
* List Grid 3 users on the current machine.
|
|
87
87
|
*/
|
|
88
|
-
export declare function listGrid3Users(): Grid3UserPath[]
|
|
88
|
+
export declare function listGrid3Users(): Promise<Grid3UserPath[]>;
|
|
89
89
|
/**
|
|
90
90
|
* Convenience helper to gather all available history across Grid 3 and Snap.
|
|
91
91
|
* Returns an empty array if no history files are present.
|
|
92
92
|
*/
|
|
93
|
-
export declare function collectUnifiedHistory(): HistoryEntry[]
|
|
93
|
+
export declare function collectUnifiedHistory(): Promise<HistoryEntry[]>;
|