@willwade/aac-processors 0.0.9 → 0.0.11

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 (75) hide show
  1. package/README.md +85 -11
  2. package/dist/cli/index.js +87 -0
  3. package/dist/core/analyze.js +1 -0
  4. package/dist/core/baseProcessor.d.ts +6 -0
  5. package/dist/core/fileProcessor.js +1 -0
  6. package/dist/core/treeStructure.d.ts +3 -1
  7. package/dist/core/treeStructure.js +3 -1
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +3 -0
  10. package/dist/optional/symbolTools.js +4 -2
  11. package/dist/processors/gridset/colorUtils.d.ts +18 -0
  12. package/dist/processors/gridset/colorUtils.js +36 -0
  13. package/dist/processors/gridset/commands.d.ts +103 -0
  14. package/dist/processors/gridset/commands.js +958 -0
  15. package/dist/processors/gridset/helpers.d.ts +1 -1
  16. package/dist/processors/gridset/helpers.js +5 -3
  17. package/dist/processors/gridset/index.d.ts +45 -0
  18. package/dist/processors/gridset/index.js +153 -0
  19. package/dist/processors/gridset/password.d.ts +11 -0
  20. package/dist/processors/gridset/password.js +37 -0
  21. package/dist/processors/gridset/pluginTypes.d.ts +109 -0
  22. package/dist/processors/gridset/pluginTypes.js +285 -0
  23. package/dist/processors/gridset/resolver.d.ts +14 -1
  24. package/dist/processors/gridset/resolver.js +47 -5
  25. package/dist/processors/gridset/styleHelpers.d.ts +22 -0
  26. package/dist/processors/gridset/styleHelpers.js +35 -1
  27. package/dist/processors/gridset/symbolExtractor.d.ts +121 -0
  28. package/dist/processors/gridset/symbolExtractor.js +362 -0
  29. package/dist/processors/gridset/symbolSearch.d.ts +117 -0
  30. package/dist/processors/gridset/symbolSearch.js +280 -0
  31. package/dist/processors/gridset/symbols.d.ts +199 -0
  32. package/dist/processors/gridset/symbols.js +468 -0
  33. package/dist/processors/gridset/wordlistHelpers.d.ts +2 -2
  34. package/dist/processors/gridset/wordlistHelpers.js +7 -4
  35. package/dist/processors/gridsetProcessor.d.ts +15 -1
  36. package/dist/processors/gridsetProcessor.js +98 -22
  37. package/dist/processors/index.d.ts +10 -1
  38. package/dist/processors/index.js +94 -2
  39. package/dist/processors/obfProcessor.d.ts +7 -0
  40. package/dist/processors/obfProcessor.js +9 -0
  41. package/dist/processors/snapProcessor.d.ts +7 -0
  42. package/dist/processors/snapProcessor.js +9 -0
  43. package/dist/processors/touchchatProcessor.d.ts +7 -0
  44. package/dist/processors/touchchatProcessor.js +9 -0
  45. package/dist/types/aac.d.ts +17 -0
  46. package/dist/utilities/screenshotConverter.d.ts +69 -0
  47. package/dist/utilities/screenshotConverter.js +453 -0
  48. package/dist/validation/baseValidator.d.ts +80 -0
  49. package/dist/validation/baseValidator.js +160 -0
  50. package/dist/validation/gridsetValidator.d.ts +36 -0
  51. package/dist/validation/gridsetValidator.js +288 -0
  52. package/dist/validation/index.d.ts +13 -0
  53. package/dist/validation/index.js +69 -0
  54. package/dist/validation/obfValidator.d.ts +44 -0
  55. package/dist/validation/obfValidator.js +530 -0
  56. package/dist/validation/snapValidator.d.ts +33 -0
  57. package/dist/validation/snapValidator.js +237 -0
  58. package/dist/validation/touchChatValidator.d.ts +33 -0
  59. package/dist/validation/touchChatValidator.js +229 -0
  60. package/dist/validation/validationTypes.d.ts +64 -0
  61. package/dist/validation/validationTypes.js +15 -0
  62. package/examples/README.md +7 -0
  63. package/examples/demo.js +143 -0
  64. package/examples/obf/aboutme.json +376 -0
  65. package/examples/obf/array.json +6 -0
  66. package/examples/obf/hash.json +4 -0
  67. package/examples/obf/links.obz +0 -0
  68. package/examples/obf/simple.obf +53 -0
  69. package/examples/package-lock.json +1326 -0
  70. package/examples/package.json +10 -0
  71. package/examples/styling-example.ts +316 -0
  72. package/examples/translate.js +39 -0
  73. package/examples/translate_demo.js +254 -0
  74. package/examples/typescript-demo.ts +251 -0
  75. package/package.json +3 -1
@@ -0,0 +1,362 @@
1
+ "use strict";
2
+ /**
3
+ * Grid 3 Symbol Extraction Strategy
4
+ *
5
+ * For converting Grid 3 gridsets to other formats (like Asterics),
6
+ * we need to handle symbol library references properly.
7
+ *
8
+ * Strategy:
9
+ * 1. Check if image is embedded in gridset (extract directly)
10
+ * 2. If symbol library reference:
11
+ * a. Check if we can extract from .pix file (limited support)
12
+ * b. Provide reference/URL for manual resolution
13
+ * c. For Tawasol: provide alternative sources
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.extractButtonImage = extractButtonImage;
43
+ exports.extractSymbolLibraryImage = extractSymbolLibraryImage;
44
+ exports.convertToAstericsImage = convertToAstericsImage;
45
+ exports.analyzeSymbolExtraction = analyzeSymbolExtraction;
46
+ exports.suggestExtractionStrategy = suggestExtractionStrategy;
47
+ exports.exportSymbolReferencesToCsv = exportSymbolReferencesToCsv;
48
+ exports.createSymbolManifest = createSymbolManifest;
49
+ const fs = __importStar(require("fs"));
50
+ const adm_zip_1 = __importDefault(require("adm-zip"));
51
+ const symbols_1 = require("./symbols");
52
+ /**
53
+ * Known open-license symbol sources
54
+ */
55
+ const OPEN_LICENSE_SYMBOLS = {
56
+ tawasl: {
57
+ name: 'Tawasol',
58
+ attribution: 'Tawasol symbols by Mada (Qatar Assistive Technology Center)',
59
+ license: 'CC BY-SA 4.0',
60
+ url: 'https://mada.org.qa/en/resources/tawasol-symbols',
61
+ alternativeSources: ['https://github.com/mada-qatar/Tawasol'],
62
+ },
63
+ blissx: {
64
+ name: 'Blissymbols',
65
+ attribution: 'Blissymbolics Communication International',
66
+ license: 'CC BY-ND 3.0',
67
+ url: 'https://blissymbolics.org',
68
+ },
69
+ symoji: {
70
+ name: 'Symoji',
71
+ attribution: 'Smartbox Assistive Technology',
72
+ license: 'Proprietary - Free use in Grid 3',
73
+ },
74
+ };
75
+ /**
76
+ * Extract image data for a button
77
+ * @param gridsetBuffer - Gridset ZIP buffer
78
+ * @param resolvedImageEntry - Path to embedded image in gridset
79
+ * @param symbolReference - Symbol library reference
80
+ * @param options - Extraction options
81
+ * @returns Extracted image data
82
+ */
83
+ function extractButtonImage(gridsetBuffer, resolvedImageEntry, symbolReference, options = {}) {
84
+ // Priority 1: Use embedded image if available
85
+ if (resolvedImageEntry && options.preferEmbedded !== false) {
86
+ try {
87
+ const zip = new adm_zip_1.default(gridsetBuffer);
88
+ const entries = zip.getEntries();
89
+ const entry = entries.find((e) => e.entryName === resolvedImageEntry);
90
+ if (entry) {
91
+ const data = entry.getData();
92
+ const format = detectImageFormat(data);
93
+ return {
94
+ found: true,
95
+ data,
96
+ format,
97
+ source: 'embedded',
98
+ reference: resolvedImageEntry,
99
+ };
100
+ }
101
+ }
102
+ catch (error) {
103
+ console.warn(`Failed to extract embedded image: ${String(error)}`);
104
+ }
105
+ }
106
+ // Priority 2: Check symbol library reference
107
+ if (symbolReference) {
108
+ return extractSymbolLibraryImage(symbolReference, options);
109
+ }
110
+ // Not found
111
+ return {
112
+ found: false,
113
+ source: 'not-found',
114
+ };
115
+ }
116
+ /**
117
+ * Extract image from symbol library
118
+ * @param reference - Symbol reference like "[tawasl]/food/apple.png"
119
+ * @param options - Extraction options
120
+ * @returns Extracted image or reference info
121
+ */
122
+ function extractSymbolLibraryImage(reference, options = {}) {
123
+ const ref = parseSymbolReferenceSafe(reference);
124
+ if (!ref || !ref.isValid) {
125
+ return {
126
+ found: false,
127
+ source: 'not-found',
128
+ reference,
129
+ };
130
+ }
131
+ // Get library metadata
132
+ const libInfo = OPEN_LICENSE_SYMBOLS[ref.library];
133
+ // Resolve symbol reference and extract from .symbols file
134
+ const resolved = (0, symbols_1.resolveSymbolReference)(reference, {
135
+ grid3Path: options.grid3Path,
136
+ });
137
+ const metadata = {
138
+ library: ref.library,
139
+ symbolPath: ref.path,
140
+ attribution: libInfo?.attribution,
141
+ license: libInfo?.license,
142
+ };
143
+ if (!resolved.found) {
144
+ // Symbol not found in library
145
+ if (options.onMissingSymbol) {
146
+ options.onMissingSymbol(ref);
147
+ }
148
+ return {
149
+ found: false,
150
+ source: 'symbol-library',
151
+ reference: reference,
152
+ metadata,
153
+ error: resolved.error,
154
+ };
155
+ }
156
+ // Successfully extracted!
157
+ const format = detectImageFormat(resolved.data);
158
+ return {
159
+ found: true,
160
+ data: resolved.data,
161
+ format,
162
+ source: 'symbol-library',
163
+ reference: reference,
164
+ metadata,
165
+ };
166
+ }
167
+ /**
168
+ * Convert extracted image to Asterics Grid format
169
+ * @param extracted - Extracted image
170
+ * @returns GridImage object for Asterics
171
+ */
172
+ function convertToAstericsImage(extracted) {
173
+ const image = {};
174
+ if (extracted.found && extracted.data) {
175
+ // Embed as base64
176
+ image.data = Buffer.from(extracted.data).toString('base64');
177
+ }
178
+ // Even if embedded, add attribution for symbol libraries
179
+ if (extracted.source === 'symbol-library') {
180
+ if (extracted.metadata?.attribution) {
181
+ image.author = extracted.metadata.attribution;
182
+ }
183
+ if (extracted.metadata?.license) {
184
+ image.searchProviderName = extracted.metadata.license;
185
+ }
186
+ }
187
+ // If not found but we have a reference, keep it for manual handling
188
+ if (!extracted.found && extracted.reference) {
189
+ image.url = `symbol:${extracted.reference}`;
190
+ if (extracted.metadata?.attribution) {
191
+ image.author = extracted.metadata.attribution;
192
+ }
193
+ }
194
+ return image;
195
+ }
196
+ /**
197
+ * Analyze symbol usage for a gridset
198
+ * @param tree - AAC tree
199
+ * @returns Symbol usage report
200
+ */
201
+ function analyzeSymbolExtraction(tree) {
202
+ const report = {
203
+ total: 0,
204
+ embedded: 0,
205
+ symbolLibraries: 0,
206
+ notFound: 0,
207
+ byLibrary: {},
208
+ missingSymbols: [],
209
+ };
210
+ for (const pageId in tree.pages) {
211
+ const page = tree.pages[pageId];
212
+ if (page.buttons) {
213
+ for (const button of page.buttons) {
214
+ report.total++;
215
+ // Embedded image
216
+ if (button.resolvedImageEntry && !button.symbolLibrary) {
217
+ report.embedded++;
218
+ continue;
219
+ }
220
+ // Symbol library reference
221
+ if (button.symbolLibrary) {
222
+ report.symbolLibraries++;
223
+ report.byLibrary[button.symbolLibrary] =
224
+ (report.byLibrary[button.symbolLibrary] || 0) + 1;
225
+ const ref = `[${button.symbolLibrary}]${button.symbolPath || ''}`;
226
+ const libInfo = OPEN_LICENSE_SYMBOLS[button.symbolLibrary];
227
+ report.missingSymbols.push({
228
+ reference: ref,
229
+ library: button.symbolLibrary,
230
+ path: button.symbolPath || '',
231
+ attribution: libInfo?.attribution,
232
+ license: libInfo?.license,
233
+ });
234
+ continue;
235
+ }
236
+ // Not found
237
+ if (!button.resolvedImageEntry && !button.symbolLibrary) {
238
+ report.notFound++;
239
+ }
240
+ }
241
+ }
242
+ }
243
+ return report;
244
+ }
245
+ /**
246
+ * Suggest extraction strategy based on report
247
+ */
248
+ function suggestExtractionStrategy(report) {
249
+ const suggestions = [];
250
+ if (report.embedded > 0) {
251
+ suggestions.push(`✓ Can extract ${report.embedded} embedded images directly`);
252
+ }
253
+ if (report.symbolLibraries > 0) {
254
+ suggestions.push(`⚠ ${report.symbolLibraries} symbol library references found:`);
255
+ Object.entries(report.byLibrary).forEach(([lib, count]) => {
256
+ const libInfo = OPEN_LICENSE_SYMBOLS[lib];
257
+ if (libInfo) {
258
+ suggestions.push(` - ${lib}: ${count} symbols (${libInfo.license})`);
259
+ if (libInfo.alternativeSources) {
260
+ suggestions.push(` Alternative: ${libInfo.alternativeSources.join(', ')}`);
261
+ }
262
+ }
263
+ else {
264
+ suggestions.push(` - ${lib}: ${count} symbols (Proprietary - requires Grid 3)`);
265
+ }
266
+ });
267
+ }
268
+ if (report.notFound > 0) {
269
+ suggestions.push(`✗ ${report.notFound} images not found`);
270
+ }
271
+ return suggestions.join('\n');
272
+ }
273
+ /**
274
+ * Detect image format from buffer
275
+ */
276
+ function detectImageFormat(buffer) {
277
+ if (buffer.length < 4)
278
+ return 'unknown';
279
+ // PNG: 89 50 4E 47
280
+ if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) {
281
+ return 'png';
282
+ }
283
+ // JPEG: FF D8 FF
284
+ if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
285
+ return 'jpg';
286
+ }
287
+ // GIF: 47 49 46 38
288
+ if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x38) {
289
+ return 'gif';
290
+ }
291
+ // SVG (check for <svg text)
292
+ const header = buffer.slice(0, Math.min(100, buffer.length)).toString('ascii').toLowerCase();
293
+ if (header.includes('<svg')) {
294
+ return 'svg';
295
+ }
296
+ return 'unknown';
297
+ }
298
+ /**
299
+ * Safe parse of symbol reference
300
+ */
301
+ function parseSymbolReferenceSafe(reference) {
302
+ try {
303
+ return (0, symbols_1.parseSymbolReference)(reference);
304
+ }
305
+ catch {
306
+ return null;
307
+ }
308
+ }
309
+ /**
310
+ * Export symbol references to CSV for manual extraction
311
+ */
312
+ function exportSymbolReferencesToCsv(report, outputPath) {
313
+ const lines = ['Reference,Library,Path,Attribution,License'];
314
+ for (const symbol of report.missingSymbols) {
315
+ lines.push(`"${symbol.reference}","${symbol.library}","${symbol.path}","${symbol.attribution || ''}","${symbol.license || ''}"`);
316
+ }
317
+ fs.writeFileSync(outputPath, lines.join('\n'));
318
+ }
319
+ function createSymbolManifest(tree, gridsetName) {
320
+ const manifest = {
321
+ generatedAt: new Date().toISOString(),
322
+ gridset: gridsetName,
323
+ totalSymbols: 0,
324
+ embedded: 0,
325
+ fromLibraries: 0,
326
+ libraries: {},
327
+ symbols: [],
328
+ };
329
+ for (const pageId in tree.pages) {
330
+ const page = tree.pages[pageId];
331
+ if (page.buttons) {
332
+ for (const button of page.buttons) {
333
+ manifest.totalSymbols++;
334
+ if (button.resolvedImageEntry && !button.symbolLibrary) {
335
+ manifest.embedded++;
336
+ continue;
337
+ }
338
+ if (button.symbolLibrary) {
339
+ manifest.fromLibraries++;
340
+ if (!manifest.libraries[button.symbolLibrary]) {
341
+ const libInfo = OPEN_LICENSE_SYMBOLS[button.symbolLibrary];
342
+ manifest.libraries[button.symbolLibrary] = {
343
+ count: 0,
344
+ attribution: libInfo?.attribution,
345
+ license: libInfo?.license,
346
+ url: libInfo?.url,
347
+ };
348
+ }
349
+ manifest.libraries[button.symbolLibrary].count++;
350
+ const ref = `[${button.symbolLibrary}]${button.symbolPath || ''}`;
351
+ manifest.symbols.push({
352
+ pageId,
353
+ buttonId: button.id,
354
+ reference: ref,
355
+ label: button.label,
356
+ });
357
+ }
358
+ }
359
+ }
360
+ }
361
+ return manifest;
362
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Grid 3 Symbol Search Implementation
3
+ *
4
+ * The .pix files are simple text mappings:
5
+ * searchTerm=symbolFilename=searchTerm
6
+ *
7
+ * Example:
8
+ * above bw=above bw.png=above bw
9
+ * active family=active family.png=active family
10
+ */
11
+ /**
12
+ * Symbol search result
13
+ */
14
+ export interface SymbolSearchResult {
15
+ searchTerm: string;
16
+ symbolFilename: string;
17
+ displayName: string;
18
+ library: string;
19
+ exactMatch: boolean;
20
+ }
21
+ /**
22
+ * Symbol search options
23
+ */
24
+ export interface SymbolSearchOptions {
25
+ grid3Path?: string;
26
+ locale?: string;
27
+ libraries?: string[];
28
+ limit?: number;
29
+ fuzzyMatch?: boolean;
30
+ }
31
+ /**
32
+ * Search index for a single library
33
+ */
34
+ export interface LibrarySearchIndex {
35
+ library: string;
36
+ searchTerms: Map<string, string>;
37
+ filenames: Map<string, string>;
38
+ }
39
+ /**
40
+ * Parse a .pix file into search index
41
+ * @param pixFilePath - Path to .pix file
42
+ * @returns Search index
43
+ */
44
+ export declare function parsePixFile(pixFilePath: string): LibrarySearchIndex;
45
+ /**
46
+ * Load search indexes for all available libraries
47
+ * @param options - Search options
48
+ * @returns Map of library name to search index
49
+ */
50
+ export declare function loadSearchIndexes(options?: SymbolSearchOptions): Map<string, LibrarySearchIndex>;
51
+ /**
52
+ * Search for symbols by term
53
+ * @param searchTerm - Term to search for
54
+ * @param options - Search options
55
+ * @returns Array of search results
56
+ */
57
+ export declare function searchSymbols(searchTerm: string, options?: SymbolSearchOptions): SymbolSearchResult[];
58
+ /**
59
+ * Get symbol filename for a specific search term
60
+ * @param searchTerm - Search term to look up
61
+ * @param library - Library name
62
+ * @param options - Search options
63
+ * @returns Symbol filename or undefined
64
+ */
65
+ export declare function getSymbolFilename(searchTerm: string, library: string, options?: SymbolSearchOptions): string | undefined;
66
+ /**
67
+ * Get display name for a symbol filename
68
+ * @param symbolFilename - Symbol filename (e.g., "above bw.png")
69
+ * @param library - Library name
70
+ * @param options - Search options
71
+ * @returns Display name or undefined
72
+ */
73
+ export declare function getSymbolDisplayName(symbolFilename: string, library: string, options?: SymbolSearchOptions): string | undefined;
74
+ /**
75
+ * Get all search terms for a library
76
+ * @param library - Library name
77
+ * @param options - Search options
78
+ * @returns Array of search terms
79
+ */
80
+ export declare function getAllSearchTerms(library: string, options?: SymbolSearchOptions): string[];
81
+ /**
82
+ * Search suggestions (autocomplete)
83
+ * @param partialTerm - Partial search term
84
+ * @param options - Search options
85
+ * @returns Array of suggested terms
86
+ */
87
+ export declare function getSearchSuggestions(partialTerm: string, options?: SymbolSearchOptions): string[];
88
+ /**
89
+ * Search for symbols and return results with library references
90
+ * @param searchTerm - Term to search for
91
+ * @param options - Search options
92
+ * @returns Array of full symbol references
93
+ */
94
+ export declare function searchSymbolsWithReferences(searchTerm: string, options?: SymbolSearchOptions): string[];
95
+ /**
96
+ * Count symbols in each library
97
+ * @param options - Search options
98
+ * @returns Map of library name to symbol count
99
+ */
100
+ export declare function countLibrarySymbols(options?: SymbolSearchOptions): Map<string, number>;
101
+ /**
102
+ * Get statistics about symbol libraries
103
+ */
104
+ export interface SymbolSearchStats {
105
+ totalLibraries: number;
106
+ totalSymbols: number;
107
+ libraries: Record<string, {
108
+ symbolCount: number;
109
+ exampleTerms: string[];
110
+ }>;
111
+ }
112
+ /**
113
+ * Get symbol search statistics
114
+ * @param options - Search options
115
+ * @returns Statistics about available symbols
116
+ */
117
+ export declare function getSymbolSearchStats(options?: SymbolSearchOptions): SymbolSearchStats;