@willwade/aac-processors 0.1.20 → 0.1.21

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 (94) hide show
  1. package/dist/browser/core/baseProcessor.js +4 -0
  2. package/dist/browser/processors/applePanelsProcessor.js +24 -31
  3. package/dist/browser/processors/astericsGridProcessor.js +10 -3
  4. package/dist/browser/processors/dotProcessor.js +5 -2
  5. package/dist/browser/processors/gridset/colorUtils.js +354 -0
  6. package/dist/browser/processors/gridset/helpers.js +49 -45
  7. package/dist/browser/processors/gridset/index.js +61 -0
  8. package/dist/browser/processors/gridset/styleHelpers.js +205 -0
  9. package/dist/browser/processors/gridset/symbolExtractor.js +331 -0
  10. package/dist/browser/processors/gridset/symbolSearch.js +248 -0
  11. package/dist/browser/processors/gridset/symbols.js +35 -68
  12. package/dist/browser/processors/gridsetProcessor.js +32 -41
  13. package/dist/browser/processors/obfProcessor.js +20 -33
  14. package/dist/browser/processors/opmlProcessor.js +5 -2
  15. package/dist/browser/processors/snap/helpers.js +49 -45
  16. package/dist/browser/processors/snapProcessor.js +39 -42
  17. package/dist/browser/processors/touchchatProcessor.js +54 -45
  18. package/dist/browser/utilities/analytics/reference/index.js +27 -19
  19. package/dist/browser/utils/io.js +67 -14
  20. package/dist/browser/utils/sqlite.js +6 -8
  21. package/dist/browser/utils/zip.js +45 -43
  22. package/dist/browser/validation/baseValidator.js +5 -0
  23. package/dist/browser/validation/gridsetValidator.js +12 -20
  24. package/dist/browser/validation/obfValidator.js +5 -4
  25. package/dist/browser/validation/snapValidator.js +9 -5
  26. package/dist/browser/validation/touchChatValidator.js +21 -11
  27. package/dist/cli/index.js +10 -15
  28. package/dist/core/baseProcessor.d.ts +7 -7
  29. package/dist/core/baseProcessor.js +4 -0
  30. package/dist/processors/applePanelsProcessor.js +29 -36
  31. package/dist/processors/astericsGridProcessor.js +20 -13
  32. package/dist/processors/dotProcessor.js +10 -7
  33. package/dist/processors/excelProcessor.js +9 -12
  34. package/dist/processors/gridset/helpers.d.ts +9 -11
  35. package/dist/processors/gridset/helpers.js +49 -71
  36. package/dist/processors/gridset/imageDebug.d.ts +3 -5
  37. package/dist/processors/gridset/imageDebug.js +4 -4
  38. package/dist/processors/gridset/password.d.ts +1 -1
  39. package/dist/processors/gridset/symbolExtractor.d.ts +5 -3
  40. package/dist/processors/gridset/symbolExtractor.js +15 -38
  41. package/dist/processors/gridset/symbolSearch.d.ts +3 -2
  42. package/dist/processors/gridset/symbolSearch.js +12 -34
  43. package/dist/processors/gridset/symbols.d.ts +8 -6
  44. package/dist/processors/gridset/symbols.js +34 -67
  45. package/dist/processors/gridset/wordlistHelpers.d.ts +4 -6
  46. package/dist/processors/gridset/wordlistHelpers.js +15 -74
  47. package/dist/processors/gridsetProcessor.js +36 -68
  48. package/dist/processors/obfProcessor.js +26 -62
  49. package/dist/processors/obfsetProcessor.js +2 -2
  50. package/dist/processors/opmlProcessor.js +10 -7
  51. package/dist/processors/snap/helpers.d.ts +8 -8
  52. package/dist/processors/snap/helpers.js +50 -72
  53. package/dist/processors/snapProcessor.js +38 -41
  54. package/dist/processors/touchchatProcessor.js +54 -45
  55. package/dist/utilities/analytics/index.d.ts +3 -2
  56. package/dist/utilities/analytics/index.js +8 -10
  57. package/dist/utilities/analytics/reference/index.d.ts +5 -3
  58. package/dist/utilities/analytics/reference/index.js +26 -18
  59. package/dist/utilities/symbolTools.d.ts +4 -2
  60. package/dist/utilities/symbolTools.js +16 -15
  61. package/dist/utils/io.d.ts +24 -6
  62. package/dist/utils/io.js +64 -14
  63. package/dist/utils/sqlite.d.ts +2 -0
  64. package/dist/utils/sqlite.js +6 -8
  65. package/dist/utils/zip.d.ts +7 -3
  66. package/dist/utils/zip.js +45 -43
  67. package/dist/validation/applePanelsValidator.d.ts +2 -1
  68. package/dist/validation/applePanelsValidator.js +9 -11
  69. package/dist/validation/astericsValidator.d.ts +2 -1
  70. package/dist/validation/astericsValidator.js +5 -4
  71. package/dist/validation/baseValidator.d.ts +2 -2
  72. package/dist/validation/baseValidator.js +5 -0
  73. package/dist/validation/dotValidator.d.ts +2 -1
  74. package/dist/validation/dotValidator.js +5 -4
  75. package/dist/validation/excelValidator.d.ts +2 -1
  76. package/dist/validation/excelValidator.js +5 -4
  77. package/dist/validation/gridsetValidator.d.ts +2 -1
  78. package/dist/validation/gridsetValidator.js +11 -22
  79. package/dist/validation/index.d.ts +2 -2
  80. package/dist/validation/index.js +5 -4
  81. package/dist/validation/obfValidator.d.ts +2 -1
  82. package/dist/validation/obfValidator.js +5 -4
  83. package/dist/validation/obfsetValidator.d.ts +2 -1
  84. package/dist/validation/obfsetValidator.js +5 -4
  85. package/dist/validation/opmlValidator.d.ts +2 -1
  86. package/dist/validation/opmlValidator.js +5 -4
  87. package/dist/validation/snapValidator.d.ts +2 -1
  88. package/dist/validation/snapValidator.js +9 -5
  89. package/dist/validation/touchChatValidator.d.ts +4 -6
  90. package/dist/validation/touchChatValidator.js +21 -11
  91. package/dist/validation/validationTypes.d.ts +8 -1
  92. package/package.json +1 -1
  93. package/dist/core/fileProcessor.d.ts +0 -7
  94. package/dist/core/fileProcessor.js +0 -57
@@ -1,27 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  Object.defineProperty(exports, "__esModule", { value: true });
26
3
  exports.ObfProcessor = void 0;
27
4
  const baseProcessor_1 = require("../core/baseProcessor");
@@ -309,10 +286,11 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
309
286
  return texts;
310
287
  }
311
288
  async loadIntoTree(filePathOrBuffer) {
289
+ const { readBinaryFromInput, readTextFromInput } = this.options.fileAdapter;
312
290
  // Detailed logging for debugging input
313
291
  const bufferLength = typeof filePathOrBuffer === 'string'
314
292
  ? null
315
- : (0, io_1.readBinaryFromInput)(filePathOrBuffer).byteLength;
293
+ : readBinaryFromInput(filePathOrBuffer).byteLength;
316
294
  console.log('[OBF] loadIntoTree called with:', {
317
295
  type: typeof filePathOrBuffer,
318
296
  isBuffer: typeof Buffer !== 'undefined' && Buffer.isBuffer(filePathOrBuffer),
@@ -324,7 +302,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
324
302
  // Helper: try to parse JSON OBF
325
303
  function tryParseObfJson(data) {
326
304
  try {
327
- const str = typeof data === 'string' ? data : (0, io_1.readTextFromInput)(data);
305
+ const str = typeof data === 'string' ? data : readTextFromInput(data);
328
306
  // Check for empty or whitespace-only content
329
307
  if (!str.trim()) {
330
308
  return null;
@@ -346,7 +324,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
346
324
  // If input is a string path and ends with .obf, treat as JSON
347
325
  if (typeof filePathOrBuffer === 'string' && filePathOrBuffer.toLowerCase().endsWith('.obf')) {
348
326
  try {
349
- const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
327
+ const content = readTextFromInput(filePathOrBuffer);
350
328
  const boardData = tryParseObfJson(content);
351
329
  if (boardData) {
352
330
  console.log('[OBF] Detected .obf file, parsed as JSON');
@@ -380,7 +358,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
380
358
  const lowered = input.toLowerCase();
381
359
  return lowered.endsWith('.zip') || lowered.endsWith('.obz');
382
360
  }
383
- const bytes = (0, io_1.readBinaryFromInput)(input);
361
+ const bytes = readBinaryFromInput(input);
384
362
  return bytes.length >= 2 && bytes[0] === 0x50 && bytes[1] === 0x4b;
385
363
  }
386
364
  // Check if input is a buffer or string that parses as OBF JSON; throw if neither JSON nor ZIP
@@ -406,10 +384,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
406
384
  return tree;
407
385
  }
408
386
  try {
409
- const zipResult = this.options.zipAdapter
410
- ? await this.options.zipAdapter(filePathOrBuffer)
411
- : await (0, zip_1.openZipFromInput)(filePathOrBuffer);
412
- this.zipFile = zipResult.zip;
387
+ this.zipFile = await this.options.zipAdapter(filePathOrBuffer);
413
388
  }
414
389
  catch (err) {
415
390
  console.error('[OBF] Error loading ZIP:', err);
@@ -427,7 +402,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
427
402
  try {
428
403
  const content = await this.zipFile.readFile(manifestFile[0]);
429
404
  const data = (0, io_1.decodeText)(content);
430
- const str = typeof data === 'string' ? data : (0, io_1.readTextFromInput)(data);
405
+ const str = typeof data === 'string' ? data : readTextFromInput(data);
431
406
  if (!str.trim())
432
407
  throw new Error('Manifest object missing');
433
408
  const manifestObject = JSON.parse(str);
@@ -565,6 +540,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
565
540
  };
566
541
  }
567
542
  async processTexts(filePathOrBuffer, translations, outputPath) {
543
+ const { readBinaryFromInput } = this.options.fileAdapter;
568
544
  // Load the tree, apply translations, and save to new file
569
545
  const tree = await this.loadIntoTree(filePathOrBuffer);
570
546
  // Apply translations to all text content
@@ -594,9 +570,10 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
594
570
  });
595
571
  // Save the translated tree and return its content
596
572
  await this.saveFromTree(tree, outputPath);
597
- return (0, io_1.readBinaryFromInput)(outputPath);
573
+ return readBinaryFromInput(outputPath);
598
574
  }
599
575
  async saveFromTree(tree, outputPath) {
576
+ const { writeTextToPath, writeBinaryToPath } = this.options.fileAdapter;
600
577
  if (outputPath.endsWith('.obf')) {
601
578
  // Save as single OBF JSON file
602
579
  const rootPage = tree.rootId ? tree.getPage(tree.rootId) : Object.values(tree.pages)[0];
@@ -604,35 +581,21 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
604
581
  throw new Error('No pages to save');
605
582
  }
606
583
  const obfBoard = this.createObfBoardFromPage(rootPage, 'Exported Board', tree.metadata);
607
- (0, io_1.writeTextToPath)(outputPath, JSON.stringify(obfBoard, null, 2));
584
+ writeTextToPath(outputPath, JSON.stringify(obfBoard, null, 2));
608
585
  }
609
586
  else {
610
- // Save as OBZ (zip with multiple OBF files)
611
- if ((0, io_1.isNodeRuntime)()) {
612
- const AdmZip = (0, io_1.getNodeRequire)()('adm-zip');
613
- const zip = new AdmZip();
614
- Object.values(tree.pages).forEach((page) => {
615
- const obfBoard = this.createObfBoardFromPage(page, 'Board', tree.metadata);
616
- const obfContent = JSON.stringify(obfBoard, null, 2);
617
- zip.addFile(`${page.id}.obf`, Buffer.from(obfContent, 'utf8'));
618
- });
619
- const zipBuffer = zip.toBuffer();
620
- const { writeBinaryToPath } = await Promise.resolve().then(() => __importStar(require('../utils/io')));
621
- writeBinaryToPath(outputPath, zipBuffer);
622
- }
623
- else {
624
- const module = await Promise.resolve().then(() => __importStar(require('jszip')));
625
- const JSZip = module.default || module;
626
- const zip = new JSZip();
627
- Object.values(tree.pages).forEach((page) => {
628
- const obfBoard = this.createObfBoardFromPage(page, 'Board', tree.metadata);
629
- const obfContent = JSON.stringify(obfBoard, null, 2);
630
- zip.file(`${page.id}.obf`, obfContent);
631
- });
632
- const zipBuffer = await zip.generateAsync({ type: 'uint8array' });
633
- const { writeBinaryToPath } = await Promise.resolve().then(() => __importStar(require('../utils/io')));
634
- writeBinaryToPath(outputPath, zipBuffer);
635
- }
587
+ const files = Object.values(tree.pages).map((page) => {
588
+ const obfBoard = this.createObfBoardFromPage(page, 'Board', tree.metadata);
589
+ const obfContent = JSON.stringify(obfBoard, null, 2);
590
+ const name = page.id.endsWith('.obf') ? page.id : `${page.id}.obf`;
591
+ return {
592
+ name,
593
+ data: new TextEncoder().encode(obfContent),
594
+ };
595
+ });
596
+ const zip = await (0, zip_1.getZipAdapter)(undefined, this.options.fileAdapter);
597
+ const zipData = await zip.writeFiles(files);
598
+ writeBinaryToPath(outputPath, zipData);
636
599
  }
637
600
  }
638
601
  /**
@@ -656,7 +619,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
656
619
  */
657
620
  async validate(filePath) {
658
621
  const ObfValidator = this.getObfValidator();
659
- return ObfValidator.validateFile(filePath);
622
+ return ObfValidator.validateFile(filePath, this.options.fileAdapter);
660
623
  }
661
624
  /**
662
625
  * Extract symbol information from an OBF/OBZ file for LLM-based translation.
@@ -698,6 +661,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
698
661
  * @returns Buffer of the translated OBF/OBZ file
699
662
  */
700
663
  async processLLMTranslations(filePathOrBuffer, llmTranslations, outputPath, options) {
664
+ const { readBinaryFromInput } = this.options.fileAdapter;
701
665
  const tree = await this.loadIntoTree(filePathOrBuffer);
702
666
  // Validate translations using shared utility
703
667
  const buttonIds = Object.values(tree.pages).flatMap((page) => page.buttons.map((b) => b.id));
@@ -736,7 +700,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
736
700
  });
737
701
  // Save and return
738
702
  await this.saveFromTree(tree, outputPath);
739
- return (0, io_1.readBinaryFromInput)(outputPath);
703
+ return readBinaryFromInput(outputPath);
740
704
  }
741
705
  getObfValidator() {
742
706
  try {
@@ -8,7 +8,6 @@ exports.ObfsetProcessor = void 0;
8
8
  const treeStructure_1 = require("../core/treeStructure");
9
9
  const treeStructure_2 = require("../core/treeStructure");
10
10
  const baseProcessor_1 = require("../core/baseProcessor");
11
- const io_1 = require("../utils/io");
12
11
  class ObfsetProcessor extends baseProcessor_1.BaseProcessor {
13
12
  constructor(options = {}) {
14
13
  super(options);
@@ -33,10 +32,11 @@ class ObfsetProcessor extends baseProcessor_1.BaseProcessor {
33
32
  * Load an .obfset file (JSON array of boards)
34
33
  */
35
34
  async loadIntoTree(filePathOrBuffer) {
35
+ const { readTextFromInput } = this.options.fileAdapter;
36
36
  await Promise.resolve();
37
37
  const tree = new treeStructure_1.AACTree();
38
38
  tree.metadata.format = 'obfset';
39
- const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
39
+ const content = readTextFromInput(filePathOrBuffer);
40
40
  const boards = JSON.parse(content);
41
41
  // Track board ID mappings
42
42
  const boardMap = new Map();
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OpmlProcessor = void 0;
4
4
  const baseProcessor_1 = require("../core/baseProcessor");
5
5
  const treeStructure_1 = require("../core/treeStructure");
6
- // Removed unused import: FileProcessor
7
6
  const fast_xml_parser_1 = require("fast-xml-parser");
8
7
  const validationTypes_1 = require("../validation/validationTypes");
9
8
  const io_1 = require("../utils/io");
@@ -53,8 +52,9 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
53
52
  return { page, childPages };
54
53
  }
55
54
  async extractTexts(filePathOrBuffer) {
55
+ const { readTextFromInput } = this.options.fileAdapter;
56
56
  await Promise.resolve();
57
- const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
57
+ const content = readTextFromInput(filePathOrBuffer);
58
58
  const parser = new fast_xml_parser_1.XMLParser({ ignoreAttributes: false });
59
59
  const data = parser.parse(content);
60
60
  const texts = [];
@@ -85,10 +85,11 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
85
85
  return texts;
86
86
  }
87
87
  async loadIntoTree(filePathOrBuffer) {
88
+ const { readBinaryFromInput, readTextFromInput } = this.options.fileAdapter;
88
89
  await Promise.resolve();
89
90
  const filename = typeof filePathOrBuffer === 'string' ? (0, io_1.getBasename)(filePathOrBuffer) : 'upload.opml';
90
- const buffer = (0, io_1.readBinaryFromInput)(filePathOrBuffer);
91
- const content = (0, io_1.readTextFromInput)(buffer);
91
+ const buffer = readBinaryFromInput(filePathOrBuffer);
92
+ const content = readTextFromInput(buffer);
92
93
  try {
93
94
  if (!content || !content.trim()) {
94
95
  const validationResult = (0, validationTypes_1.buildValidationResultFromMessage)({
@@ -171,8 +172,9 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
171
172
  }
172
173
  }
173
174
  async processTexts(filePathOrBuffer, translations, outputPath) {
175
+ const { writeBinaryToPath, readTextFromInput } = this.options.fileAdapter;
174
176
  await Promise.resolve();
175
- const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
177
+ const content = readTextFromInput(filePathOrBuffer);
176
178
  let translatedContent = content;
177
179
  // Apply translations to text attributes in OPML outline elements
178
180
  translations.forEach((translation, originalText) => {
@@ -183,10 +185,11 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
183
185
  }
184
186
  });
185
187
  const resultBuffer = (0, io_1.encodeText)(translatedContent);
186
- (0, io_1.writeBinaryToPath)(outputPath, resultBuffer);
188
+ writeBinaryToPath(outputPath, resultBuffer);
187
189
  return resultBuffer;
188
190
  }
189
191
  async saveFromTree(tree, outputPath) {
192
+ const { writeTextToPath } = this.options.fileAdapter;
190
193
  await Promise.resolve();
191
194
  // Helper to recursively build outline nodes with cycle detection
192
195
  function buildOutline(page, visited = new Set()) {
@@ -257,7 +260,7 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
257
260
  attributeNamePrefix: '@_',
258
261
  });
259
262
  const xml = '<?xml version="1.0" encoding="UTF-8"?>\n' + builder.build(opmlObj);
260
- (0, io_1.writeTextToPath)(outputPath, xml);
263
+ writeTextToPath(outputPath, xml);
261
264
  }
262
265
  /**
263
266
  * Extract strings with metadata for aac-tools-platform compatibility
@@ -1,5 +1,5 @@
1
1
  import { AACTree, AACSemanticCategory, AACSemanticIntent } from '../../core/treeStructure';
2
- import { ProcessorInput } from '../../utils/io';
2
+ import { FileAdapter, ProcessorInput } from '../../utils/io';
3
3
  /**
4
4
  * Build a map of button IDs to resolved image entries for a specific page.
5
5
  * Mirrors the Grid helper for consumers that expect image reference data.
@@ -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): Buffer | null;
19
+ export declare function openImage(dbOrFile: ProcessorInput, entryPath: string, fileAdapter?: FileAdapter): 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): SnapPackagePath[];
56
+ export declare function findSnapPackages(packageNamePattern?: string, fileAdapter?: FileAdapter): 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): string | null;
63
+ export declare function findSnapPackagePath(packageNamePattern?: string, fileAdapter?: FileAdapter): 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): string
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): SnapUserInfo[];
71
+ export declare function findSnapUsers(packageNamePattern?: string, fileAdapter?: FileAdapter): 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): string[];
78
+ export declare function findSnapUserVocabularies(userId?: string, packageNamePattern?: string, fileAdapter?: FileAdapter): 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): string[];
86
+ export declare function findSnapUserHistory(userId: string, packageNamePattern?: string, fileAdapter?: FileAdapter): string[];
87
87
  /**
88
88
  * Check whether TD Snap appears to be installed (Windows only)
89
89
  */
@@ -91,7 +91,7 @@ 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): SnapUsageEntry[];
94
+ export declare function readSnapUsage(pagesetPath: string, fileAdapter?: FileAdapter): SnapUsageEntry[];
95
95
  /**
96
96
  * Read Snap usage history for a user (all pagesets)
97
97
  */
@@ -1,30 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
2
  Object.defineProperty(exports, "__esModule", { value: true });
29
3
  exports.getPageTokenImageMap = getPageTokenImageMap;
30
4
  exports.getAllowedImageEntries = getAllowedImageEntries;
@@ -38,10 +12,9 @@ exports.isSnapInstalled = isSnapInstalled;
38
12
  exports.readSnapUsage = readSnapUsage;
39
13
  exports.readSnapUsageForUser = readSnapUsageForUser;
40
14
  const treeStructure_1 = require("../../core/treeStructure");
41
- const fs = __importStar(require("fs"));
42
- const path = __importStar(require("path"));
43
- const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
44
15
  const dotnetTicks_1 = require("../../utils/dotnetTicks");
16
+ const io_1 = require("../../utils/io");
17
+ const sqlite_1 = require("../../utils/sqlite");
45
18
  // Minimal Snap helpers (stubs) to align with processors/<engine>/helpers pattern
46
19
  // NOTE: Snap files can store different types of image data in PageSetData:
47
20
  // - PNG/JPEG binaries: Actual images that can be displayed
@@ -50,7 +23,8 @@ const dotnetTicks_1 = require("../../utils/dotnetTicks");
50
23
  // We extract PNG/JPEG images but skip vector graphics (requires renderer).
51
24
  // NOTE: Snap buttons currently do not populate resolvedImageEntry; these helpers
52
25
  // therefore return empty collections until image resolution is implemented.
53
- function collectFiles(root, matcher, maxDepth = 3) {
26
+ function collectFiles(root, matcher, maxDepth = 3, fileAdapter = io_1.defaultFileAdapter) {
27
+ const { listDir, join, isDirectory } = fileAdapter;
54
28
  const results = new Set();
55
29
  const stack = [{ dir: root, depth: 0 }];
56
30
  while (stack.length > 0) {
@@ -61,14 +35,14 @@ function collectFiles(root, matcher, maxDepth = 3) {
61
35
  continue;
62
36
  let entries;
63
37
  try {
64
- entries = fs.readdirSync(current.dir, { withFileTypes: true });
38
+ entries = listDir(current.dir);
65
39
  }
66
40
  catch (error) {
67
41
  continue;
68
42
  }
69
43
  for (const entry of entries) {
70
- const fullPath = path.join(current.dir, entry.name);
71
- if (entry.isDirectory()) {
44
+ const fullPath = join(current.dir, entry);
45
+ if (isDirectory(entry)) {
72
46
  stack.push({ dir: fullPath, depth: current.depth + 1 });
73
47
  }
74
48
  else if (matcher(fullPath)) {
@@ -122,17 +96,15 @@ function getAllowedImageEntries(tree) {
122
96
  * @param entryPath Symbol identifier (e.g., "SYM:12345")
123
97
  * @returns Image data buffer or null if not found
124
98
  */
125
- function openImage(dbOrFile, entryPath) {
99
+ function openImage(dbOrFile, entryPath, fileAdapter = io_1.defaultFileAdapter) {
100
+ const { mkTempDir, join, writeBinaryToPath, removePath, dirname } = fileAdapter;
126
101
  let dbPath;
127
102
  let cleanupNeeded = false;
128
103
  // Handle Buffer input by writing to temp file
129
104
  if (Buffer.isBuffer(dbOrFile)) {
130
- if (typeof fs.mkdtempSync !== 'function') {
131
- return null; // Not in Node environment
132
- }
133
- const tempDir = fs.mkdtempSync(path.join(process.cwd(), 'snap-'));
134
- dbPath = path.join(tempDir, 'temp.sps');
135
- fs.writeFileSync(dbPath, dbOrFile);
105
+ const tempDir = mkTempDir(join(process.cwd(), 'snap-'));
106
+ dbPath = join(tempDir, 'temp.sps');
107
+ writeBinaryToPath(dbPath, dbOrFile);
136
108
  cleanupNeeded = true;
137
109
  }
138
110
  else if (typeof dbOrFile === 'string') {
@@ -141,9 +113,10 @@ function openImage(dbOrFile, entryPath) {
141
113
  else {
142
114
  return null;
143
115
  }
116
+ const better_sqlite3 = (0, io_1.getNodeRequire)()('better-sqlite3');
144
117
  let db = null;
145
118
  try {
146
- db = new better_sqlite3_1.default(dbPath, { readonly: true });
119
+ db = new better_sqlite3.Database(dbPath, { readonly: true });
147
120
  // Query PageSetData for the symbol
148
121
  const row = db
149
122
  .prepare('SELECT Id, Identifier, Data FROM PageSetData WHERE Identifier = ?')
@@ -166,9 +139,9 @@ function openImage(dbOrFile, entryPath) {
166
139
  }
167
140
  if (cleanupNeeded && dbPath) {
168
141
  try {
169
- fs.unlinkSync(dbPath);
170
- const dir = path.dirname(dbPath);
171
- fs.rmdirSync(dir);
142
+ removePath(dbPath);
143
+ const dir = dirname(dbPath);
144
+ removePath(dir);
172
145
  }
173
146
  catch (e) {
174
147
  // Ignore cleanup errors
@@ -182,7 +155,8 @@ function openImage(dbOrFile, entryPath) {
182
155
  * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
183
156
  * @returns Array of Snap package path information
184
157
  */
185
- function findSnapPackages(packageNamePattern = 'TobiiDynavox') {
158
+ function findSnapPackages(packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
159
+ const { join, listDir, isDirectory, pathExists } = fileAdapter;
186
160
  const results = [];
187
161
  // Only works on Windows
188
162
  if (process.platform !== 'win32') {
@@ -193,22 +167,22 @@ function findSnapPackages(packageNamePattern = 'TobiiDynavox') {
193
167
  if (!localAppData) {
194
168
  return results;
195
169
  }
196
- const packagesPath = path.join(localAppData, 'Packages');
170
+ const packagesPath = join(localAppData, 'Packages');
197
171
  // Check if Packages directory exists
198
- if (!fs.existsSync(packagesPath)) {
172
+ if (!pathExists(packagesPath)) {
199
173
  return results;
200
174
  }
201
175
  // Enumerate packages
202
- const packages = fs.readdirSync(packagesPath, { withFileTypes: true });
176
+ const packages = listDir(packagesPath);
203
177
  for (const packageDir of packages) {
204
- if (!packageDir.isDirectory())
178
+ if (!isDirectory(packageDir))
205
179
  continue;
206
- const packageName = packageDir.name;
180
+ const packageName = packageDir;
207
181
  // Filter by pattern
208
182
  if (packageName.includes(packageNamePattern)) {
209
183
  results.push({
210
184
  packageName,
211
- packagePath: path.join(packagesPath, packageName),
185
+ packagePath: join(packagesPath, packageName),
212
186
  });
213
187
  }
214
188
  }
@@ -224,8 +198,8 @@ function findSnapPackages(packageNamePattern = 'TobiiDynavox') {
224
198
  * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
225
199
  * @returns Path to the first matching Snap package, or null if not found
226
200
  */
227
- function findSnapPackagePath(packageNamePattern = 'TobiiDynavox') {
228
- const packages = findSnapPackages(packageNamePattern);
201
+ function findSnapPackagePath(packageNamePattern = 'TobiiDynavox', fileAdapter) {
202
+ const packages = findSnapPackages(packageNamePattern, fileAdapter);
229
203
  return packages.length > 0 ? packages[0].packagePath : null;
230
204
  }
231
205
  /**
@@ -235,32 +209,33 @@ function findSnapPackagePath(packageNamePattern = 'TobiiDynavox') {
235
209
  * @param packageNamePattern Optional package filter (default TobiiDynavox)
236
210
  * @returns Array of user info with vocab paths
237
211
  */
238
- function findSnapUsers(packageNamePattern = 'TobiiDynavox') {
212
+ function findSnapUsers(packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
213
+ const { join, listDir, isDirectory, pathExists } = fileAdapter;
239
214
  const results = [];
240
215
  if (process.platform !== 'win32') {
241
216
  return results;
242
217
  }
243
- const packagePath = findSnapPackagePath(packageNamePattern);
218
+ const packagePath = findSnapPackagePath(packageNamePattern, fileAdapter);
244
219
  if (!packagePath) {
245
220
  return results;
246
221
  }
247
- const usersRoot = path.join(packagePath, 'LocalState', 'Users');
248
- if (!fs.existsSync(usersRoot)) {
222
+ const usersRoot = join(packagePath, 'LocalState', 'Users');
223
+ if (!pathExists(usersRoot)) {
249
224
  return results;
250
225
  }
251
- const entries = fs.readdirSync(usersRoot, { withFileTypes: true });
226
+ const entries = listDir(usersRoot);
252
227
  for (const entry of entries) {
253
- if (!entry.isDirectory())
228
+ if (!isDirectory(entry))
254
229
  continue;
255
- if (entry.name.toLowerCase().startsWith('swiftkey'))
230
+ if (entry.toLowerCase().startsWith('swiftkey'))
256
231
  continue;
257
- const userPath = path.join(usersRoot, entry.name);
232
+ const userPath = join(usersRoot, entry);
258
233
  const vocabPaths = collectFiles(userPath, (full) => {
259
- const ext = path.extname(full).toLowerCase();
234
+ const ext = (0, io_1.extname)(full).toLowerCase();
260
235
  return ext === '.sps' || ext === '.spb';
261
- }, 2);
236
+ }, 2, fileAdapter);
262
237
  results.push({
263
- userId: entry.name,
238
+ userId: entry,
264
239
  userPath,
265
240
  vocabPaths,
266
241
  });
@@ -273,8 +248,8 @@ function findSnapUsers(packageNamePattern = 'TobiiDynavox') {
273
248
  * @param packageNamePattern Optional package filter
274
249
  * @returns Array of vocab file paths
275
250
  */
276
- function findSnapUserVocabularies(userId, packageNamePattern = 'TobiiDynavox') {
277
- const users = findSnapUsers(packageNamePattern).filter((u) => !userId || u.userId === userId);
251
+ function findSnapUserVocabularies(userId, packageNamePattern = 'TobiiDynavox', fileAdapter) {
252
+ const users = findSnapUsers(packageNamePattern, fileAdapter).filter((u) => !userId || u.userId === userId);
278
253
  return users.flatMap((u) => u.vocabPaths);
279
254
  }
280
255
  /**
@@ -284,11 +259,12 @@ function findSnapUserVocabularies(userId, packageNamePattern = 'TobiiDynavox') {
284
259
  * @param packageNamePattern Optional package filter
285
260
  * @returns Array of history file paths (may be empty if not found)
286
261
  */
287
- function findSnapUserHistory(userId, packageNamePattern = 'TobiiDynavox') {
288
- const user = findSnapUsers(packageNamePattern).find((u) => u.userId === userId);
262
+ function findSnapUserHistory(userId, packageNamePattern = 'TobiiDynavox', fileAdapter = io_1.defaultFileAdapter) {
263
+ const { basename } = fileAdapter;
264
+ const user = findSnapUsers(packageNamePattern, fileAdapter).find((u) => u.userId === userId);
289
265
  if (!user)
290
266
  return [];
291
- return collectFiles(user.userPath, (full) => path.basename(full).toLowerCase().includes('history'), 2);
267
+ return collectFiles(user.userPath, (full) => basename(full).toLowerCase().includes('history'), 2, fileAdapter);
292
268
  }
293
269
  /**
294
270
  * Check whether TD Snap appears to be installed (Windows only)
@@ -301,10 +277,12 @@ function isSnapInstalled(packageNamePattern = 'TobiiDynavox') {
301
277
  /**
302
278
  * Read Snap usage history from a pageset file (.sps/.spb)
303
279
  */
304
- function readSnapUsage(pagesetPath) {
305
- if (!fs.existsSync(pagesetPath))
280
+ function readSnapUsage(pagesetPath, fileAdapter = io_1.defaultFileAdapter) {
281
+ const { pathExists } = fileAdapter;
282
+ if (!pathExists(pagesetPath))
306
283
  return [];
307
- const db = new better_sqlite3_1.default(pagesetPath, { readonly: true });
284
+ const Database = (0, sqlite_1.requireBetterSqlite3)();
285
+ const db = new Database(pagesetPath, { readonly: true });
308
286
  const tableCheck = db
309
287
  .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name IN ('ButtonUsage','Button')")
310
288
  .all();