@willwade/aac-processors 0.1.20 → 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/core/baseProcessor.js +4 -0
- package/dist/browser/processors/applePanelsProcessor.js +33 -40
- package/dist/browser/processors/astericsGridProcessor.js +31 -26
- package/dist/browser/processors/dotProcessor.js +11 -12
- package/dist/browser/processors/gridset/colorUtils.js +354 -0
- package/dist/browser/processors/gridset/helpers.js +60 -53
- package/dist/browser/processors/gridset/index.js +61 -0
- package/dist/browser/processors/gridset/styleHelpers.js +205 -0
- package/dist/browser/processors/gridset/symbolExtractor.js +331 -0
- package/dist/browser/processors/gridset/symbolSearch.js +248 -0
- package/dist/browser/processors/gridset/symbols.js +39 -72
- package/dist/browser/processors/gridsetProcessor.js +39 -48
- package/dist/browser/processors/obfProcessor.js +39 -53
- package/dist/browser/processors/opmlProcessor.js +11 -12
- package/dist/browser/processors/snap/helpers.js +57 -49
- package/dist/browser/processors/snapProcessor.js +48 -51
- package/dist/browser/processors/touchchatProcessor.js +60 -52
- 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 +44 -35
- package/dist/browser/utils/io.js +78 -21
- package/dist/browser/utils/sqlite.js +8 -10
- package/dist/browser/utils/zip.js +43 -43
- package/dist/browser/validation/baseValidator.js +5 -0
- package/dist/browser/validation/gridsetValidator.js +12 -20
- package/dist/browser/validation/obfValidator.js +6 -5
- package/dist/browser/validation/snapValidator.js +11 -7
- package/dist/browser/validation/touchChatValidator.js +23 -13
- package/dist/cli/index.js +22 -24
- package/dist/core/baseProcessor.d.ts +7 -7
- package/dist/core/baseProcessor.js +4 -0
- package/dist/processors/applePanelsProcessor.js +32 -39
- package/dist/processors/astericsGridProcessor.d.ts +4 -4
- package/dist/processors/astericsGridProcessor.js +30 -25
- package/dist/processors/dotProcessor.js +10 -11
- package/dist/processors/excelProcessor.d.ts +3 -3
- package/dist/processors/excelProcessor.js +14 -20
- package/dist/processors/gridset/helpers.d.ts +12 -14
- package/dist/processors/gridset/helpers.js +60 -79
- package/dist/processors/gridset/imageDebug.d.ts +3 -5
- package/dist/processors/gridset/imageDebug.js +4 -4
- package/dist/processors/gridset/password.d.ts +1 -1
- package/dist/processors/gridset/symbolExtractor.d.ts +5 -3
- package/dist/processors/gridset/symbolExtractor.js +15 -38
- package/dist/processors/gridset/symbolSearch.d.ts +11 -10
- package/dist/processors/gridset/symbolSearch.js +29 -51
- package/dist/processors/gridset/symbols.d.ts +8 -6
- package/dist/processors/gridset/symbols.js +38 -71
- package/dist/processors/gridset/wordlistHelpers.d.ts +4 -6
- package/dist/processors/gridset/wordlistHelpers.js +15 -74
- package/dist/processors/gridsetProcessor.d.ts +2 -2
- package/dist/processors/gridsetProcessor.js +38 -70
- package/dist/processors/obfProcessor.d.ts +2 -2
- package/dist/processors/obfProcessor.js +38 -75
- package/dist/processors/obfsetProcessor.js +2 -3
- package/dist/processors/opmlProcessor.js +10 -11
- package/dist/processors/snap/helpers.d.ts +9 -9
- package/dist/processors/snap/helpers.js +58 -76
- package/dist/processors/snapProcessor.d.ts +2 -2
- package/dist/processors/snapProcessor.js +47 -50
- package/dist/processors/touchchatProcessor.d.ts +2 -2
- package/dist/processors/touchchatProcessor.js +59 -51
- 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 +3 -2
- package/dist/utilities/analytics/index.js +9 -10
- 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 +25 -23
- package/dist/utilities/analytics/reference/index.js +43 -34
- package/dist/utilities/symbolTools.d.ts +8 -6
- package/dist/utilities/symbolTools.js +21 -18
- package/dist/utils/io.d.ts +24 -6
- package/dist/utils/io.js +79 -25
- package/dist/utils/sqlite.d.ts +3 -1
- package/dist/utils/sqlite.js +7 -9
- package/dist/utils/zip.d.ts +7 -3
- package/dist/utils/zip.js +43 -43
- package/dist/validation/applePanelsValidator.d.ts +2 -1
- package/dist/validation/applePanelsValidator.js +10 -11
- package/dist/validation/astericsValidator.d.ts +2 -1
- package/dist/validation/astericsValidator.js +5 -4
- package/dist/validation/baseValidator.d.ts +2 -2
- package/dist/validation/baseValidator.js +5 -0
- package/dist/validation/dotValidator.d.ts +2 -1
- package/dist/validation/dotValidator.js +5 -4
- package/dist/validation/excelValidator.d.ts +2 -1
- package/dist/validation/excelValidator.js +5 -4
- package/dist/validation/gridsetValidator.d.ts +2 -1
- package/dist/validation/gridsetValidator.js +11 -22
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +5 -4
- package/dist/validation/obfValidator.d.ts +2 -1
- package/dist/validation/obfValidator.js +5 -4
- package/dist/validation/obfsetValidator.d.ts +2 -1
- package/dist/validation/obfsetValidator.js +5 -4
- package/dist/validation/opmlValidator.d.ts +2 -1
- package/dist/validation/opmlValidator.js +5 -4
- package/dist/validation/snapValidator.d.ts +2 -1
- package/dist/validation/snapValidator.js +10 -6
- package/dist/validation/touchChatValidator.d.ts +4 -6
- package/dist/validation/touchChatValidator.js +22 -12
- package/dist/validation/validationTypes.d.ts +8 -1
- package/package.json +1 -1
- package/dist/core/fileProcessor.d.ts +0 -7
- package/dist/core/fileProcessor.js +0 -57
|
@@ -9,7 +9,7 @@ const touchChatValidator_1 = require("../validation/touchChatValidator");
|
|
|
9
9
|
const io_1 = require("../utils/io");
|
|
10
10
|
const translationProcessor_1 = require("../utilities/translation/translationProcessor");
|
|
11
11
|
const sqlite_1 = require("../utils/sqlite");
|
|
12
|
-
const
|
|
12
|
+
const gridset_1 = require("./gridset");
|
|
13
13
|
const toNumberOrUndefined = (value) => typeof value === 'number' ? value : undefined;
|
|
14
14
|
const toStringOrUndefined = (value) => typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
15
15
|
const toBooleanOrUndefined = (value) => typeof value === 'number' ? value !== 0 : undefined;
|
|
@@ -58,7 +58,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
58
58
|
return texts;
|
|
59
59
|
}
|
|
60
60
|
async loadIntoTree(filePathOrBuffer) {
|
|
61
|
-
|
|
61
|
+
const { readBinaryFromInput } = this.options.fileAdapter;
|
|
62
62
|
// Unzip .ce file, extract the .c4v SQLite DB, and parse pages/buttons
|
|
63
63
|
let db = null;
|
|
64
64
|
let cleanup;
|
|
@@ -66,16 +66,17 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
66
66
|
// Store source file path or buffer
|
|
67
67
|
this.sourceFile = filePathOrBuffer;
|
|
68
68
|
// Step 1: Unzip
|
|
69
|
-
const zipInput =
|
|
70
|
-
const
|
|
71
|
-
? await this.options.zipAdapter(zipInput)
|
|
72
|
-
: await (0, zip_1.openZipFromInput)(zipInput);
|
|
69
|
+
const zipInput = await readBinaryFromInput(filePathOrBuffer);
|
|
70
|
+
const zip = await this.options.zipAdapter(zipInput);
|
|
73
71
|
const vocabEntry = zip.listFiles().find((name) => name.endsWith('.c4v'));
|
|
74
72
|
if (!vocabEntry) {
|
|
75
73
|
throw new Error('No .c4v vocab DB found in TouchChat export');
|
|
76
74
|
}
|
|
77
75
|
const dbBuffer = await zip.readFile(vocabEntry);
|
|
78
|
-
const dbResult = await (0, sqlite_1.openSqliteDatabase)(dbBuffer, {
|
|
76
|
+
const dbResult = await (0, sqlite_1.openSqliteDatabase)(dbBuffer, {
|
|
77
|
+
readonly: true,
|
|
78
|
+
fileAdapter: this.options.fileAdapter,
|
|
79
|
+
});
|
|
79
80
|
db = dbResult.db;
|
|
80
81
|
cleanup = dbResult.cleanup;
|
|
81
82
|
// Step 3: Create tree and load pages
|
|
@@ -470,7 +471,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
470
471
|
finally {
|
|
471
472
|
// Clean up
|
|
472
473
|
if (cleanup) {
|
|
473
|
-
cleanup();
|
|
474
|
+
await cleanup();
|
|
474
475
|
}
|
|
475
476
|
else if (db) {
|
|
476
477
|
db.close();
|
|
@@ -478,6 +479,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
478
479
|
}
|
|
479
480
|
}
|
|
480
481
|
async processTexts(filePathOrBuffer, translations, outputPath) {
|
|
482
|
+
const { pathExists, mkDir, removePath, mkTempDir, writeBinaryToPath, readBinaryFromInput, dirname, join, } = this.options.fileAdapter;
|
|
481
483
|
if (!(0, io_1.isNodeRuntime)()) {
|
|
482
484
|
throw new Error('processTexts is only supported in Node.js environments for TouchChat files.');
|
|
483
485
|
}
|
|
@@ -490,28 +492,25 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
490
492
|
* within the embedded SQLite database, ensuring assets and metadata remain intact.
|
|
491
493
|
*/
|
|
492
494
|
if (typeof filePathOrBuffer === 'string') {
|
|
493
|
-
const fs = (0, io_1.getFs)();
|
|
494
|
-
const path = (0, io_1.getPath)();
|
|
495
|
-
const os = (0, io_1.getOs)();
|
|
496
|
-
const AdmZip = (0, io_1.getNodeRequire)()('adm-zip');
|
|
497
495
|
const inputPath = filePathOrBuffer;
|
|
498
|
-
const outputDir =
|
|
499
|
-
|
|
500
|
-
|
|
496
|
+
const outputDir = dirname(outputPath);
|
|
497
|
+
const dirExists = await pathExists(outputDir);
|
|
498
|
+
if (!dirExists) {
|
|
499
|
+
await mkDir(outputDir, { recursive: true });
|
|
501
500
|
}
|
|
502
|
-
if (
|
|
503
|
-
|
|
501
|
+
if (await pathExists(outputPath)) {
|
|
502
|
+
await removePath(outputPath);
|
|
504
503
|
}
|
|
505
|
-
const zip =
|
|
506
|
-
const entries =
|
|
504
|
+
const zip = await this.options.zipAdapter(inputPath);
|
|
505
|
+
const entries = (0, gridset_1.getZipEntriesFromAdapter)(zip);
|
|
507
506
|
const vocabEntry = entries.find((entry) => entry.entryName.endsWith('.c4v'));
|
|
508
507
|
if (!vocabEntry) {
|
|
509
508
|
throw new Error('No .c4v vocab DB found in TouchChat export');
|
|
510
509
|
}
|
|
511
|
-
const tempDir =
|
|
512
|
-
const dbPath =
|
|
510
|
+
const tempDir = await mkTempDir('touchchat-translate-');
|
|
511
|
+
const dbPath = join(tempDir, 'vocab.c4v');
|
|
513
512
|
try {
|
|
514
|
-
|
|
513
|
+
await writeBinaryToPath(dbPath, await vocabEntry.getData());
|
|
515
514
|
const Database = (0, sqlite_1.requireBetterSqlite3)();
|
|
516
515
|
const db = new Database(dbPath, { readonly: false });
|
|
517
516
|
try {
|
|
@@ -564,26 +563,34 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
564
563
|
finally {
|
|
565
564
|
db.close();
|
|
566
565
|
}
|
|
567
|
-
const outputZip =
|
|
568
|
-
|
|
566
|
+
const outputZip = await this.options.zipAdapter();
|
|
567
|
+
const files = [];
|
|
568
|
+
for (const entry of entries) {
|
|
569
569
|
if (entry.entryName === vocabEntry.entryName) {
|
|
570
|
-
|
|
570
|
+
continue;
|
|
571
571
|
}
|
|
572
|
-
const data =
|
|
573
|
-
|
|
572
|
+
const data = await entry.getData();
|
|
573
|
+
files.push({
|
|
574
|
+
name: entry.entryName,
|
|
575
|
+
data,
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
files.push({
|
|
579
|
+
name: vocabEntry.entryName,
|
|
580
|
+
data: await readBinaryFromInput(dbPath),
|
|
574
581
|
});
|
|
575
|
-
outputZip.
|
|
576
|
-
|
|
582
|
+
const zipData = await outputZip.writeFiles(files);
|
|
583
|
+
await writeBinaryToPath(outputPath, zipData);
|
|
577
584
|
}
|
|
578
585
|
finally {
|
|
579
586
|
try {
|
|
580
|
-
|
|
587
|
+
await removePath(tempDir, { recursive: true, force: true });
|
|
581
588
|
}
|
|
582
589
|
catch {
|
|
583
590
|
// Best-effort cleanup
|
|
584
591
|
}
|
|
585
592
|
}
|
|
586
|
-
return
|
|
593
|
+
return await readBinaryFromInput(outputPath);
|
|
587
594
|
}
|
|
588
595
|
// Fallback for buffer inputs: rebuild from tree (may drop TouchChat metadata)
|
|
589
596
|
const tree = await this.loadIntoTree(filePathOrBuffer);
|
|
@@ -610,20 +617,16 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
610
617
|
});
|
|
611
618
|
});
|
|
612
619
|
await this.saveFromTree(tree, outputPath);
|
|
613
|
-
|
|
614
|
-
return fs.readFileSync(outputPath);
|
|
620
|
+
return await readBinaryFromInput(outputPath);
|
|
615
621
|
}
|
|
616
622
|
async saveFromTree(tree, outputPath) {
|
|
617
|
-
|
|
623
|
+
const { writeBinaryToPath, mkTempDir, readBinaryFromInput, pathExists, removePath, join } = this.options.fileAdapter;
|
|
618
624
|
if (!(0, io_1.isNodeRuntime)()) {
|
|
619
625
|
throw new Error('saveFromTree is only supported in Node.js environments for TouchChat files.');
|
|
620
626
|
}
|
|
621
|
-
const fs = (0, io_1.getFs)();
|
|
622
|
-
const path = (0, io_1.getPath)();
|
|
623
|
-
const os = (0, io_1.getOs)();
|
|
624
627
|
// Create a TouchChat database that matches the expected schema for loading
|
|
625
|
-
const tmpDir =
|
|
626
|
-
const dbPath =
|
|
628
|
+
const tmpDir = await mkTempDir('touchchat-export-');
|
|
629
|
+
const dbPath = join(tmpDir, 'vocab.c4v');
|
|
627
630
|
try {
|
|
628
631
|
const Database = (0, sqlite_1.requireBetterSqlite3)();
|
|
629
632
|
const db = new Database(dbPath);
|
|
@@ -916,15 +919,20 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
916
919
|
}
|
|
917
920
|
db.close();
|
|
918
921
|
// Create zip file with the database
|
|
919
|
-
const
|
|
920
|
-
const
|
|
921
|
-
zip.
|
|
922
|
-
|
|
922
|
+
const zip = await this.options.zipAdapter();
|
|
923
|
+
const data = await readBinaryFromInput(dbPath);
|
|
924
|
+
const zipData = await zip.writeFiles([
|
|
925
|
+
{
|
|
926
|
+
name: 'vocab.c4v',
|
|
927
|
+
data,
|
|
928
|
+
},
|
|
929
|
+
]);
|
|
930
|
+
await writeBinaryToPath(outputPath, zipData);
|
|
923
931
|
}
|
|
924
932
|
finally {
|
|
925
933
|
// Clean up
|
|
926
|
-
if (
|
|
927
|
-
|
|
934
|
+
if (await pathExists(tmpDir)) {
|
|
935
|
+
await removePath(tmpDir, { recursive: true, force: true });
|
|
928
936
|
}
|
|
929
937
|
}
|
|
930
938
|
}
|
|
@@ -1007,7 +1015,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
1007
1015
|
const outputPath = filePath.replace(/\.ce$/, '_translated.ce');
|
|
1008
1016
|
// Use existing processTexts method
|
|
1009
1017
|
await this.processTexts(filePath, translations, outputPath);
|
|
1010
|
-
return
|
|
1018
|
+
return outputPath;
|
|
1011
1019
|
}
|
|
1012
1020
|
catch (error) {
|
|
1013
1021
|
return Promise.reject(new Error(`Failed to generate translated download: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
@@ -1019,7 +1027,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
1019
1027
|
* @returns Promise with validation result
|
|
1020
1028
|
*/
|
|
1021
1029
|
async validate(filePath) {
|
|
1022
|
-
return touchChatValidator_1.TouchChatValidator.validateFile(filePath);
|
|
1030
|
+
return await touchChatValidator_1.TouchChatValidator.validateFile(filePath, this.options.fileAdapter);
|
|
1023
1031
|
}
|
|
1024
1032
|
/**
|
|
1025
1033
|
* Extract symbol information from a TouchChat file for LLM-based translation.
|
|
@@ -1028,7 +1036,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
1028
1036
|
* This method uses shared translation utilities that work across all AAC formats.
|
|
1029
1037
|
*
|
|
1030
1038
|
* @param filePathOrBuffer - Path to TouchChat .ce file or buffer
|
|
1031
|
-
* @returns
|
|
1039
|
+
* @returns Promise resolving to symbol information for LLM processing
|
|
1032
1040
|
*/
|
|
1033
1041
|
async extractSymbolsForLLM(filePathOrBuffer) {
|
|
1034
1042
|
const tree = await this.loadIntoTree(filePathOrBuffer);
|
|
@@ -1058,9 +1066,10 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
1058
1066
|
* @param llmTranslations - Array of LLM translations with symbol info
|
|
1059
1067
|
* @param outputPath - Where to save the translated TouchChat file
|
|
1060
1068
|
* @param options - Translation options (e.g., allowPartial for testing)
|
|
1061
|
-
* @returns
|
|
1069
|
+
* @returns Promise resolving to a buffer of the translated TouchChat file
|
|
1062
1070
|
*/
|
|
1063
1071
|
async processLLMTranslations(filePathOrBuffer, llmTranslations, outputPath, options) {
|
|
1072
|
+
const { readBinaryFromInput } = this.options.fileAdapter;
|
|
1064
1073
|
if (!(0, io_1.isNodeRuntime)()) {
|
|
1065
1074
|
throw new Error('processLLMTranslations is only supported in Node.js environments for TouchChat files.');
|
|
1066
1075
|
}
|
|
@@ -1102,8 +1111,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
1102
1111
|
});
|
|
1103
1112
|
// Save and return
|
|
1104
1113
|
await this.saveFromTree(tree, outputPath);
|
|
1105
|
-
|
|
1106
|
-
return fs.readFileSync(outputPath);
|
|
1114
|
+
return await readBinaryFromInput(outputPath);
|
|
1107
1115
|
}
|
|
1108
1116
|
}
|
|
1109
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[]>;
|
|
@@ -72,8 +72,9 @@ function exportHistoryToBaton(entries, options) {
|
|
|
72
72
|
/**
|
|
73
73
|
* Read Grid 3 phrase history from a history.sqlite database and tag entries with their source.
|
|
74
74
|
*/
|
|
75
|
-
function readGrid3History(historyDbPath) {
|
|
76
|
-
|
|
75
|
+
async function readGrid3History(historyDbPath) {
|
|
76
|
+
const history = await (0, helpers_1.readGrid3History)(historyDbPath);
|
|
77
|
+
return history.map((e) => ({
|
|
77
78
|
...e,
|
|
78
79
|
source: 'Grid',
|
|
79
80
|
}));
|
|
@@ -81,8 +82,9 @@ function readGrid3History(historyDbPath) {
|
|
|
81
82
|
/**
|
|
82
83
|
* Read Grid 3 history for a specific user/language combination.
|
|
83
84
|
*/
|
|
84
|
-
function readGrid3HistoryForUser(userName, langCode) {
|
|
85
|
-
|
|
85
|
+
async function readGrid3HistoryForUser(userName, langCode) {
|
|
86
|
+
const history = await (0, helpers_1.readGrid3HistoryForUser)(userName, langCode);
|
|
87
|
+
return history.map((e) => ({
|
|
86
88
|
...e,
|
|
87
89
|
source: 'Grid',
|
|
88
90
|
}));
|
|
@@ -90,39 +92,43 @@ function readGrid3HistoryForUser(userName, langCode) {
|
|
|
90
92
|
/**
|
|
91
93
|
* Read every available Grid 3 history database on the machine.
|
|
92
94
|
*/
|
|
93
|
-
function readAllGrid3History() {
|
|
94
|
-
|
|
95
|
+
async function readAllGrid3History() {
|
|
96
|
+
const history = await (0, helpers_1.readAllGrid3History)();
|
|
97
|
+
return history.map((e) => ({ ...e, source: 'Grid' }));
|
|
95
98
|
}
|
|
96
99
|
/**
|
|
97
100
|
* Read Snap button usage from a pageset database and tag entries with source.
|
|
98
101
|
*/
|
|
99
|
-
function readSnapUsage(pagesetPath) {
|
|
100
|
-
|
|
102
|
+
async function readSnapUsage(pagesetPath) {
|
|
103
|
+
const usage = await (0, helpers_2.readSnapUsage)(pagesetPath);
|
|
104
|
+
return usage.map((e) => ({ ...e, source: 'Snap' }));
|
|
101
105
|
}
|
|
102
106
|
/**
|
|
103
107
|
* Read Snap usage for a specific user across all discovered pagesets.
|
|
104
108
|
*/
|
|
105
|
-
function readSnapUsageForUser(userId, packageNamePattern = 'TobiiDynavox') {
|
|
106
|
-
|
|
109
|
+
async function readSnapUsageForUser(userId, packageNamePattern = 'TobiiDynavox') {
|
|
110
|
+
const usage = await (0, helpers_2.readSnapUsageForUser)(userId, packageNamePattern);
|
|
111
|
+
return usage.map((e) => ({
|
|
107
112
|
...e,
|
|
108
113
|
source: 'Snap',
|
|
109
114
|
}));
|
|
110
115
|
}
|
|
111
|
-
function listSnapUsers() {
|
|
112
|
-
return (0, helpers_2.findSnapUsers)();
|
|
116
|
+
async function listSnapUsers() {
|
|
117
|
+
return await (0, helpers_2.findSnapUsers)();
|
|
113
118
|
}
|
|
114
119
|
/**
|
|
115
120
|
* List Grid 3 users on the current machine.
|
|
116
121
|
*/
|
|
117
|
-
function listGrid3Users() {
|
|
118
|
-
return (0, helpers_1.findGrid3Users)();
|
|
122
|
+
async function listGrid3Users() {
|
|
123
|
+
return await (0, helpers_1.findGrid3Users)();
|
|
119
124
|
}
|
|
120
125
|
/**
|
|
121
126
|
* Convenience helper to gather all available history across Grid 3 and Snap.
|
|
122
127
|
* Returns an empty array if no history files are present.
|
|
123
128
|
*/
|
|
124
|
-
function collectUnifiedHistory() {
|
|
125
|
-
const gridHistory = readAllGrid3History();
|
|
126
|
-
const
|
|
127
|
-
|
|
129
|
+
async function collectUnifiedHistory() {
|
|
130
|
+
const gridHistory = await readAllGrid3History();
|
|
131
|
+
const users = await (0, helpers_2.findSnapUsers)();
|
|
132
|
+
const snapHistory = await Promise.all(users.map(async (u) => await readSnapUsageForUser(u.userId)));
|
|
133
|
+
return [...gridHistory, ...snapHistory.flat()];
|
|
128
134
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
|
+
import { FileAdapter } from '../../utils/io';
|
|
12
13
|
export * from './metrics/types';
|
|
13
14
|
export * from './metrics/effort';
|
|
14
15
|
export * from './utils/idGenerator';
|
|
@@ -23,8 +24,8 @@ export { ReferenceLoader } from './reference';
|
|
|
23
24
|
/**
|
|
24
25
|
* Get the default reference data path
|
|
25
26
|
*/
|
|
26
|
-
export declare function getReferenceDataPath(): string;
|
|
27
|
+
export declare function getReferenceDataPath(fileAdapter: FileAdapter): string;
|
|
27
28
|
/**
|
|
28
29
|
* Check if reference data files exist
|
|
29
30
|
*/
|
|
30
|
-
export declare function hasReferenceData(): boolean
|
|
31
|
+
export declare function hasReferenceData(fileAdapter?: FileAdapter): Promise<boolean>;
|
|
@@ -24,15 +24,11 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
24
24
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
25
25
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
26
26
|
};
|
|
27
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
28
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
29
|
-
};
|
|
30
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
28
|
exports.ReferenceLoader = exports.ComparisonAnalyzer = exports.SentenceAnalyzer = exports.VocabularyAnalyzer = exports.MetricsCalculator = exports.OblAnonymizer = exports.OblUtil = void 0;
|
|
32
29
|
exports.getReferenceDataPath = getReferenceDataPath;
|
|
33
30
|
exports.hasReferenceData = hasReferenceData;
|
|
34
|
-
const
|
|
35
|
-
const fs_1 = __importDefault(require("fs"));
|
|
31
|
+
const io_1 = require("../../utils/io");
|
|
36
32
|
// Always-available exports
|
|
37
33
|
__exportStar(require("./metrics/types"), exports);
|
|
38
34
|
__exportStar(require("./metrics/effort"), exports);
|
|
@@ -59,14 +55,16 @@ Object.defineProperty(exports, "ReferenceLoader", { enumerable: true, get: funct
|
|
|
59
55
|
/**
|
|
60
56
|
* Get the default reference data path
|
|
61
57
|
*/
|
|
62
|
-
function getReferenceDataPath() {
|
|
63
|
-
|
|
58
|
+
function getReferenceDataPath(fileAdapter) {
|
|
59
|
+
const { join } = fileAdapter;
|
|
60
|
+
return join(__dirname, 'reference', 'data');
|
|
64
61
|
}
|
|
65
62
|
/**
|
|
66
63
|
* Check if reference data files exist
|
|
67
64
|
*/
|
|
68
|
-
function hasReferenceData() {
|
|
69
|
-
const
|
|
65
|
+
async function hasReferenceData(fileAdapter = io_1.defaultFileAdapter) {
|
|
66
|
+
const { pathExists, join } = fileAdapter;
|
|
67
|
+
const dataPath = getReferenceDataPath(fileAdapter);
|
|
70
68
|
const requiredFiles = [
|
|
71
69
|
'core_lists.en.json',
|
|
72
70
|
'common_words.en.json',
|
|
@@ -74,5 +72,6 @@ function hasReferenceData() {
|
|
|
74
72
|
'synonyms.en.json',
|
|
75
73
|
'fringe.en.json',
|
|
76
74
|
];
|
|
77
|
-
|
|
75
|
+
const existingPaths = await Promise.all(requiredFiles.map(async (file) => await pathExists(join(dataPath, file))));
|
|
76
|
+
return existingPaths.every((exists) => exists);
|
|
78
77
|
}
|
|
@@ -19,7 +19,7 @@ export declare class ComparisonAnalyzer {
|
|
|
19
19
|
compare(targetResult: MetricsResult, compareResult: MetricsResult, options?: {
|
|
20
20
|
includeSentences?: boolean;
|
|
21
21
|
locale?: string;
|
|
22
|
-
} & Partial<MetricsOptions>): ComparisonResult
|
|
22
|
+
} & Partial<MetricsOptions>): Promise<ComparisonResult>;
|
|
23
23
|
/**
|
|
24
24
|
* Calculate CARE component scores
|
|
25
25
|
*/
|
|
@@ -26,7 +26,7 @@ class ComparisonAnalyzer {
|
|
|
26
26
|
/**
|
|
27
27
|
* Compare two board sets
|
|
28
28
|
*/
|
|
29
|
-
compare(targetResult, compareResult, options) {
|
|
29
|
+
async compare(targetResult, compareResult, options) {
|
|
30
30
|
// Create base result from target
|
|
31
31
|
const baseResult = { ...targetResult };
|
|
32
32
|
// Create word maps with normalized keys
|
|
@@ -80,7 +80,7 @@ class ComparisonAnalyzer {
|
|
|
80
80
|
};
|
|
81
81
|
});
|
|
82
82
|
// Calculate CARE components
|
|
83
|
-
const careComponents = this.calculateCareComponents(targetResult, compareResult, overlappingWords, options);
|
|
83
|
+
const careComponents = await this.calculateCareComponents(targetResult, compareResult, overlappingWords, options);
|
|
84
84
|
// Analyze high/low effort words
|
|
85
85
|
const highEffortWords = [];
|
|
86
86
|
const lowEffortWords = [];
|
|
@@ -113,7 +113,7 @@ class ComparisonAnalyzer {
|
|
|
113
113
|
// Sentence analysis
|
|
114
114
|
let sentences = [];
|
|
115
115
|
if (options?.includeSentences) {
|
|
116
|
-
const testSentences = this.referenceLoader.loadSentences();
|
|
116
|
+
const testSentences = await this.referenceLoader.loadSentences();
|
|
117
117
|
const targetSentences = this.sentenceAnalyzer.analyzeSentences(targetResult, testSentences);
|
|
118
118
|
const compareSentences = this.sentenceAnalyzer.analyzeSentences(compareResult, testSentences);
|
|
119
119
|
sentences = targetSentences.map((ts, idx) => ({
|
|
@@ -126,7 +126,7 @@ class ComparisonAnalyzer {
|
|
|
126
126
|
}));
|
|
127
127
|
}
|
|
128
128
|
// Core vocabulary analysis
|
|
129
|
-
const coreLists = this.referenceLoader.loadCoreLists();
|
|
129
|
+
const coreLists = await this.referenceLoader.loadCoreLists();
|
|
130
130
|
const cores = {};
|
|
131
131
|
coreLists.forEach((list) => {
|
|
132
132
|
let targetTotal = 0;
|
|
@@ -174,8 +174,8 @@ class ComparisonAnalyzer {
|
|
|
174
174
|
}
|
|
175
175
|
});
|
|
176
176
|
// Fringe vocabulary analysis
|
|
177
|
-
const fringeWords = this.analyzeFringe(targetWords, compareWords);
|
|
178
|
-
const commonFringeWords = this.analyzeCommonFringe(targetWords, compareWords);
|
|
177
|
+
const fringeWords = await this.analyzeFringe(targetWords, compareWords);
|
|
178
|
+
const commonFringeWords = await this.analyzeCommonFringe(targetWords, compareWords);
|
|
179
179
|
return {
|
|
180
180
|
...baseResult,
|
|
181
181
|
buttons: enrichedButtons,
|
|
@@ -217,9 +217,9 @@ class ComparisonAnalyzer {
|
|
|
217
217
|
/**
|
|
218
218
|
* Calculate CARE component scores
|
|
219
219
|
*/
|
|
220
|
-
calculateCareComponents(targetResult, compareResult, _overlappingWords, options) {
|
|
220
|
+
async calculateCareComponents(targetResult, compareResult, _overlappingWords, options) {
|
|
221
221
|
// Load common words with baseline efforts (matching Ruby line 527-534)
|
|
222
|
-
const commonWordsData = this.referenceLoader.loadCommonWords();
|
|
222
|
+
const commonWordsData = await this.referenceLoader.loadCommonWords();
|
|
223
223
|
const commonWords = new Map();
|
|
224
224
|
commonWordsData.words.forEach((word) => {
|
|
225
225
|
commonWords.set(word.toLowerCase(), commonWordsData.efforts[word] || 0);
|
|
@@ -271,10 +271,10 @@ class ComparisonAnalyzer {
|
|
|
271
271
|
}
|
|
272
272
|
});
|
|
273
273
|
// Load reference data
|
|
274
|
-
const coreLists = this.referenceLoader.loadCoreLists();
|
|
275
|
-
const fringe = this.referenceLoader.loadFringe();
|
|
276
|
-
const commonFringe = this.referenceLoader.loadCommonFringe();
|
|
277
|
-
const sentences = this.referenceLoader.loadSentences();
|
|
274
|
+
const coreLists = await this.referenceLoader.loadCoreLists();
|
|
275
|
+
const fringe = await this.referenceLoader.loadFringe();
|
|
276
|
+
const commonFringe = await this.referenceLoader.loadCommonFringe();
|
|
277
|
+
const sentences = await this.referenceLoader.loadSentences();
|
|
278
278
|
// Calculate core coverage and effort (matching Ruby lines 609-647)
|
|
279
279
|
let coreCount = 0;
|
|
280
280
|
let compCoreCount = 0;
|
|
@@ -426,8 +426,8 @@ class ComparisonAnalyzer {
|
|
|
426
426
|
/**
|
|
427
427
|
* Analyze fringe vocabulary
|
|
428
428
|
*/
|
|
429
|
-
analyzeFringe(targetWords, compareWords) {
|
|
430
|
-
const fringe = this.referenceLoader.loadFringe();
|
|
429
|
+
async analyzeFringe(targetWords, compareWords) {
|
|
430
|
+
const fringe = await this.referenceLoader.loadFringe();
|
|
431
431
|
const result = [];
|
|
432
432
|
fringe.forEach((word) => {
|
|
433
433
|
const key = this.normalize(word);
|
|
@@ -447,8 +447,8 @@ class ComparisonAnalyzer {
|
|
|
447
447
|
/**
|
|
448
448
|
* Analyze common fringe vocabulary
|
|
449
449
|
*/
|
|
450
|
-
analyzeCommonFringe(targetWords, compareWords) {
|
|
451
|
-
const fringe = this.referenceLoader.loadFringe();
|
|
450
|
+
async analyzeCommonFringe(targetWords, compareWords) {
|
|
451
|
+
const fringe = await this.referenceLoader.loadFringe();
|
|
452
452
|
const result = [];
|
|
453
453
|
fringe.forEach((word) => {
|
|
454
454
|
const key = this.normalize(word);
|
|
@@ -16,12 +16,12 @@ class VocabularyAnalyzer {
|
|
|
16
16
|
/**
|
|
17
17
|
* Analyze vocabulary coverage against core lists
|
|
18
18
|
*/
|
|
19
|
-
analyze(metrics, options) {
|
|
19
|
+
async analyze(metrics, options) {
|
|
20
20
|
// const locale = options?.locale || metrics.locale || 'en';
|
|
21
21
|
const highEffortThreshold = options?.highEffortThreshold || 5.0;
|
|
22
22
|
const lowEffortThreshold = options?.lowEffortThreshold || 2.0;
|
|
23
23
|
// Load reference data
|
|
24
|
-
const coreLists = this.referenceLoader.loadCoreLists();
|
|
24
|
+
const coreLists = await this.referenceLoader.loadCoreLists();
|
|
25
25
|
// Create word to effort map (using lowercase keys for matching)
|
|
26
26
|
const wordEffortMap = new Map();
|
|
27
27
|
metrics.buttons.forEach((btn) => {
|
|
@@ -16,16 +16,16 @@ export interface ReferenceData {
|
|
|
16
16
|
export declare class InMemoryReferenceLoader implements ReferenceDataProvider {
|
|
17
17
|
private data;
|
|
18
18
|
constructor(data: ReferenceData);
|
|
19
|
-
loadCoreLists(): CoreList[]
|
|
20
|
-
loadCommonWords(): CommonWordsData
|
|
21
|
-
loadSynonyms(): SynonymsData
|
|
22
|
-
loadSentences(): string[][]
|
|
23
|
-
loadFringe(): string[]
|
|
24
|
-
loadBaseWords(): {
|
|
19
|
+
loadCoreLists(): Promise<CoreList[]>;
|
|
20
|
+
loadCommonWords(): Promise<CommonWordsData>;
|
|
21
|
+
loadSynonyms(): Promise<SynonymsData>;
|
|
22
|
+
loadSentences(): Promise<string[][]>;
|
|
23
|
+
loadFringe(): Promise<string[]>;
|
|
24
|
+
loadBaseWords(): Promise<{
|
|
25
25
|
[word: string]: boolean;
|
|
26
|
-
}
|
|
27
|
-
loadCommonFringe(): string[]
|
|
28
|
-
loadAll(): ReferenceData
|
|
26
|
+
}>;
|
|
27
|
+
loadCommonFringe(): Promise<string[]>;
|
|
28
|
+
loadAll(): Promise<ReferenceData>;
|
|
29
29
|
}
|
|
30
30
|
export declare function loadReferenceDataFromUrl(baseUrl: string, locale?: string): Promise<ReferenceData>;
|
|
31
31
|
export declare function createBrowserReferenceLoader(baseUrl: string, locale?: string): Promise<InMemoryReferenceLoader>;
|
|
@@ -10,34 +10,34 @@ class InMemoryReferenceLoader {
|
|
|
10
10
|
constructor(data) {
|
|
11
11
|
this.data = data;
|
|
12
12
|
}
|
|
13
|
-
loadCoreLists() {
|
|
14
|
-
return this.data.coreLists;
|
|
13
|
+
async loadCoreLists() {
|
|
14
|
+
return Promise.resolve(this.data.coreLists);
|
|
15
15
|
}
|
|
16
|
-
loadCommonWords() {
|
|
17
|
-
return this.data.commonWords;
|
|
16
|
+
async loadCommonWords() {
|
|
17
|
+
return Promise.resolve(this.data.commonWords);
|
|
18
18
|
}
|
|
19
|
-
loadSynonyms() {
|
|
20
|
-
return this.data.synonyms;
|
|
19
|
+
async loadSynonyms() {
|
|
20
|
+
return Promise.resolve(this.data.synonyms);
|
|
21
21
|
}
|
|
22
|
-
loadSentences() {
|
|
23
|
-
return this.data.sentences;
|
|
22
|
+
async loadSentences() {
|
|
23
|
+
return Promise.resolve(this.data.sentences);
|
|
24
24
|
}
|
|
25
|
-
loadFringe() {
|
|
26
|
-
return this.data.fringe;
|
|
25
|
+
async loadFringe() {
|
|
26
|
+
return Promise.resolve(this.data.fringe);
|
|
27
27
|
}
|
|
28
|
-
loadBaseWords() {
|
|
29
|
-
return this.data.baseWords;
|
|
28
|
+
async loadBaseWords() {
|
|
29
|
+
return Promise.resolve(this.data.baseWords);
|
|
30
30
|
}
|
|
31
|
-
loadCommonFringe() {
|
|
31
|
+
async loadCommonFringe() {
|
|
32
32
|
const commonWords = new Set(this.data.commonWords.words.map((w) => w.toLowerCase()));
|
|
33
33
|
const coreWords = new Set();
|
|
34
34
|
this.data.coreLists.forEach((list) => {
|
|
35
35
|
list.words.forEach((word) => coreWords.add(word.toLowerCase()));
|
|
36
36
|
});
|
|
37
|
-
return Array.from(commonWords).filter((word) => !coreWords.has(word));
|
|
37
|
+
return Promise.resolve(Array.from(commonWords).filter((word) => !coreWords.has(word)));
|
|
38
38
|
}
|
|
39
|
-
loadAll() {
|
|
40
|
-
return this.data;
|
|
39
|
+
async loadAll() {
|
|
40
|
+
return Promise.resolve(this.data);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
exports.InMemoryReferenceLoader = InMemoryReferenceLoader;
|