@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
package/README.md CHANGED
@@ -27,6 +27,7 @@ A comprehensive **TypeScript library** for processing AAC (Augmentative and Alte
27
27
  - ๐ŸŒ **Translation workflows** - Built-in i18n support with `processTexts()`
28
28
  - ๐ŸŽจ **Comprehensive styling support** - Preserve visual appearance across formats
29
29
  - ๐Ÿงช **Property-based testing** - Robust validation with 140+ tests
30
+ - โœ… **Format validation** - Spec-based validation for all supported formats
30
31
  - โšก **Performance optimized** - Memory-efficient processing of large files
31
32
  - ๐Ÿ›ก๏ธ **Error recovery** - Graceful handling of corrupted data
32
33
  - ๐Ÿ”’ **Thread-safe** - Concurrent processing support
@@ -191,6 +192,78 @@ const translatedBuffer = processor.processTexts(
191
192
  console.log("Translation complete!");
192
193
  ```
193
194
 
195
+ ### Format Validation
196
+
197
+ Validate AAC files against format specifications to ensure data integrity:
198
+
199
+ ```typescript
200
+ import { ObfProcessor, GridsetProcessor } from "aac-processors";
201
+
202
+ // Validate OBF/OBZ files
203
+ const obfProcessor = new ObfProcessor();
204
+ const result = await obfProcessor.validate("board.obf");
205
+
206
+ console.log(`Valid: ${result.valid}`);
207
+ console.log(`Errors: ${result.errors}`);
208
+ console.log(`Warnings: ${result.warnings}`);
209
+
210
+ // Detailed validation results
211
+ if (!result.valid) {
212
+ result.results
213
+ .filter((check) => !check.valid)
214
+ .forEach((check) => {
215
+ console.log(`โœ— ${check.description}: ${check.error}`);
216
+ });
217
+ }
218
+
219
+ // Validate Gridset files (with optional password for encrypted files)
220
+ const gridsetProcessor = new GridsetProcessor({
221
+ gridsetPassword: "optional-password",
222
+ });
223
+ const gridsetResult = await gridsetProcessor.validate("vocab.gridsetx");
224
+ ```
225
+
226
+ #### Using the CLI
227
+
228
+ ```bash
229
+ # Validate a file
230
+ aacprocessors validate board.obf
231
+
232
+ # JSON output
233
+ aacprocessors validate board.obf --json
234
+
235
+ # Quiet mode (just valid/invalid)
236
+ aacprocessors validate board.gridset --quiet
237
+
238
+ # Validate encrypted Gridset file
239
+ aacprocessors validate board.gridsetx --gridset-password <password>
240
+ ```
241
+
242
+ #### What Gets Validated?
243
+
244
+ - **OBF/OBZ**: Spec compliance (Open Board Format)
245
+ - Required fields (format, id, locale, buttons, grid, images, sounds)
246
+ - Grid structure (rows, columns, order)
247
+ - Button references (image_id, sound_id, load_board paths)
248
+ - Color formats (RGB/RGBA)
249
+ - Cross-reference validation
250
+
251
+ - **Gridset**: XML structure
252
+ - Required elements (gridset, pages, cells)
253
+ - FixedCellSize configuration
254
+ - Page and cell attributes
255
+ - Image references
256
+
257
+ - **Snap**: Package structure
258
+ - ZIP package validity
259
+ - Settings file format
260
+ - Page/button configurations
261
+
262
+ - **TouchChat**: XML structure
263
+ - PageSet hierarchy
264
+ - Button definitions
265
+ - Navigation links
266
+
194
267
  ### Cross-Format Conversion
195
268
 
196
269
  Convert between any supported AAC formats:
@@ -506,6 +579,7 @@ npx aac-processors analyze examples/example.gridset --pretty
506
579
  - `--pretty` - Human-readable output (analyze command)
507
580
  - `--verbose` - Detailed output (extract command)
508
581
  - `--quiet` - Minimal output (extract command)
582
+ - `--gridset-password <password>` - Password for encrypted Grid 3 archives (`.gridsetx`)
509
583
 
510
584
  **Button Filtering Options:**
511
585
 
@@ -594,17 +668,17 @@ interface AACButton {
594
668
 
595
669
  ### Supported Processors
596
670
 
597
- | Processor | File Extensions | Description |
598
- | ----------------------- | --------------- | ----------------------------- |
599
- | `DotProcessor` | `.dot` | Graphviz DOT format |
600
- | `OpmlProcessor` | `.opml` | OPML hierarchical format |
601
- | `ObfProcessor` | `.obf`, `.obz` | Open Board Format (JSON/ZIP) |
602
- | `SnapProcessor` | `.sps`, `.spb` | Tobii Dynavox Snap format |
603
- | `GridsetProcessor` | `.gridset` | Smartbox Grid 3 format |
604
- | `TouchChatProcessor` | `.ce` | PRC-Saltillo TouchChat format |
605
- | `ApplePanelsProcessor` | `.plist` | iOS Apple Panels format |
606
- | `AstericsGridProcessor` | `.grd` | Asterics Grid native format |
607
- | `ExcelProcessor` | `.xlsx` | Microsoft Excel format |
671
+ | Processor | File Extensions | Description |
672
+ | ----------------------- | ----------------------- | ----------------------------- |
673
+ | `DotProcessor` | `.dot` | Graphviz DOT format |
674
+ | `OpmlProcessor` | `.opml` | OPML hierarchical format |
675
+ | `ObfProcessor` | `.obf`, `.obz` | Open Board Format (JSON/ZIP) |
676
+ | `SnapProcessor` | `.sps`, `.spb` | Tobii Dynavox Snap format |
677
+ | `GridsetProcessor` | `.gridset`, `.gridsetx` | Smartbox Grid 3 format |
678
+ | `TouchChatProcessor` | `.ce` | PRC-Saltillo TouchChat format |
679
+ | `ApplePanelsProcessor` | `.plist` | iOS Apple Panels format |
680
+ | `AstericsGridProcessor` | `.grd` | Asterics Grid native format |
681
+ | `ExcelProcessor` | `.xlsx` | Microsoft Excel format |
608
682
 
609
683
  ---
610
684
 
package/dist/cli/index.js CHANGED
@@ -23,6 +23,9 @@ function detectFormat(filePath) {
23
23
  // Helper function to parse filtering options from CLI arguments
24
24
  function parseFilteringOptions(options) {
25
25
  const processorOptions = {};
26
+ if (options.gridsetPassword) {
27
+ processorOptions.gridsetPassword = options.gridsetPassword;
28
+ }
26
29
  // Handle preserve all buttons flag
27
30
  if (options.preserveAllButtons) {
28
31
  processorOptions.preserveAllButtons = true;
@@ -63,6 +66,7 @@ commander_1.program
63
66
  .option('--no-exclude-navigation', "Don't exclude navigation buttons (Home, Back)")
64
67
  .option('--no-exclude-system', "Don't exclude system buttons (Delete, Clear, etc.)")
65
68
  .option('--exclude-buttons <list>', 'Comma-separated list of button labels/terms to exclude')
69
+ .option('--gridset-password <password>', 'Password for encrypted Grid3 archives (.gridsetx)')
66
70
  .action((file, options) => {
67
71
  try {
68
72
  // Parse filtering options
@@ -97,6 +101,7 @@ commander_1.program
97
101
  .option('--no-exclude-navigation', "Don't exclude navigation buttons (Home, Back)")
98
102
  .option('--no-exclude-system', "Don't exclude system buttons (Delete, Clear, etc.)")
99
103
  .option('--exclude-buttons <list>', 'Comma-separated list of button labels/terms to exclude')
104
+ .option('--gridset-password <password>', 'Password for encrypted Grid3 archives (.gridsetx)')
100
105
  .action((file, options) => {
101
106
  try {
102
107
  // Parse filtering options
@@ -142,6 +147,7 @@ commander_1.program
142
147
  .option('--no-exclude-navigation', "Don't exclude navigation buttons (Home, Back)")
143
148
  .option('--no-exclude-system', "Don't exclude system buttons (Delete, Clear, etc.)")
144
149
  .option('--exclude-buttons <list>', 'Comma-separated list of button labels/terms to exclude')
150
+ .option('--gridset-password <password>', 'Password for encrypted Grid3 archives (.gridsetx)')
145
151
  .action(async (input, output, options) => {
146
152
  try {
147
153
  if (!options.format) {
@@ -182,6 +188,87 @@ commander_1.program
182
188
  process.exit(1);
183
189
  }
184
190
  });
191
+ commander_1.program
192
+ .command('validate <file>')
193
+ .description('Validate an AAC file format')
194
+ .option('--format <format>', 'Format type (auto-detected if not specified)')
195
+ .option('--json', 'Output results as JSON')
196
+ .option('--quiet', 'Only output validation result (valid/invalid)')
197
+ .option('--gridset-password <password>', 'Password for encrypted Grid3 archives (.gridsetx)')
198
+ .action(async (file, options) => {
199
+ try {
200
+ // Auto-detect format if not specified
201
+ const format = options.format || detectFormat(file);
202
+ // Get processor with gridset password if provided
203
+ const processorOptions = {};
204
+ if (options.gridsetPassword) {
205
+ processorOptions.gridsetPassword = options.gridsetPassword;
206
+ }
207
+ const processor = (0, analyze_1.getProcessor)(format, processorOptions);
208
+ // Check if processor supports validation
209
+ if (!processor.validate) {
210
+ console.error(`Error: Validation not supported for format '${format}'`);
211
+ process.exit(1);
212
+ }
213
+ // Run validation
214
+ const result = await processor.validate(file);
215
+ // Output results
216
+ if (options.quiet) {
217
+ console.log(result.valid ? 'valid' : 'invalid');
218
+ }
219
+ else if (options.json) {
220
+ console.log(JSON.stringify(result, null, 2));
221
+ }
222
+ else {
223
+ // Pretty print validation results
224
+ console.log(`\nValidation Results for: ${result.filename}`);
225
+ console.log(`Format: ${result.format}`);
226
+ console.log(`File size: ${result.filesize} bytes`);
227
+ console.log(`Status: ${result.valid ? 'โœ“ VALID' : 'โœ— INVALID'}`);
228
+ console.log(`Errors: ${result.errors}`);
229
+ console.log(`Warnings: ${result.warnings}\n`);
230
+ if (result.errors > 0 || result.warnings > 0) {
231
+ if (result.errors > 0) {
232
+ console.log('Errors:');
233
+ result.results
234
+ .filter((r) => !r.valid)
235
+ .forEach((check) => {
236
+ console.log(` โœ— ${check.description}`);
237
+ if (check.error) {
238
+ console.log(` ${check.error}`);
239
+ }
240
+ });
241
+ }
242
+ if (result.warnings > 0) {
243
+ console.log('\nWarnings:');
244
+ result.results.forEach((check) => {
245
+ if (check.warnings && check.warnings.length > 0) {
246
+ console.log(` โš  ${check.description}`);
247
+ check.warnings.forEach((warning) => {
248
+ console.log(` ${warning}`);
249
+ });
250
+ }
251
+ });
252
+ }
253
+ }
254
+ // Show sub-results if available
255
+ if (result.sub_results && result.sub_results.length > 0) {
256
+ console.log('\nSub-results:');
257
+ result.sub_results.forEach((sub, idx) => {
258
+ console.log(` [${idx + 1}] ${sub.filename}`);
259
+ console.log(` Status: ${sub.valid ? 'โœ“' : 'โœ—'} (${sub.errors} errors, ${sub.warnings} warnings)`);
260
+ });
261
+ }
262
+ console.log('');
263
+ }
264
+ // Exit with appropriate code
265
+ process.exit(result.valid ? 0 : 1);
266
+ }
267
+ catch (error) {
268
+ console.error('Error validating file:', error instanceof Error ? error.message : String(error));
269
+ process.exit(1);
270
+ }
271
+ });
185
272
  // Show help if no command provided
186
273
  if (process.argv.length <= 2) {
187
274
  commander_1.program.help();
@@ -27,6 +27,7 @@ function getProcessor(format, options) {
27
27
  case 'ce': // TouchChat file extension
28
28
  return new touchchatProcessor_1.TouchChatProcessor(options);
29
29
  case 'gridset':
30
+ case 'gridsetx':
30
31
  return new gridsetProcessor_1.GridsetProcessor(options); // Grid3 format
31
32
  case 'grd': // Asterics Grid file extension
32
33
  return new astericsGridProcessor_1.AstericsGridProcessor(options);
@@ -1,10 +1,15 @@
1
1
  import { AACTree, AACButton } from './treeStructure';
2
2
  import { StringCasing } from './stringCasing';
3
+ import { ValidationResult } from '../validation/validationTypes';
3
4
  export interface ProcessorOptions {
4
5
  excludeNavigationButtons?: boolean;
5
6
  excludeSystemButtons?: boolean;
7
+ gridsetPassword?: string;
6
8
  customButtonFilter?: (button: AACButton) => boolean;
7
9
  preserveAllButtons?: boolean;
10
+ grid3SymbolDir?: string;
11
+ grid3Path?: string;
12
+ grid3Locale?: string;
8
13
  }
9
14
  export interface ExtractedString {
10
15
  string: string;
@@ -44,6 +49,7 @@ declare abstract class BaseProcessor {
44
49
  abstract loadIntoTree(filePathOrBuffer: string | Buffer): AACTree;
45
50
  abstract processTexts(filePathOrBuffer: string | Buffer, translations: Map<string, string>, outputPath: string): Buffer;
46
51
  abstract saveFromTree(tree: AACTree, outputPath: string): void | Promise<void>;
52
+ validate?(filePath: string): Promise<ValidationResult>;
47
53
  /**
48
54
  * Extract strings with metadata for external platform integration
49
55
  * @param filePath - Path to the AAC file
@@ -20,6 +20,7 @@ class FileProcessor {
20
20
  const ext = path_1.default.extname(filePathOrBuffer).toLowerCase();
21
21
  switch (ext) {
22
22
  case '.gridset':
23
+ case '.gridsetx':
23
24
  return 'gridset';
24
25
  case '.obf':
25
26
  case '.obz':
@@ -115,7 +115,7 @@ export declare class AACButton implements IAACButton {
115
115
  parameters?: {
116
116
  [key: string]: any;
117
117
  };
118
- constructor({ id, label, message, targetPageId, semanticAction, audioRecording, style, contentType, contentSubType, image, resolvedImageEntry, x, y, columnSpan, rowSpan, scanBlocks, visibility, directActivate, parameters, type, action, }: {
118
+ constructor({ id, label, message, targetPageId, semanticAction, audioRecording, style, contentType, contentSubType, image, resolvedImageEntry, symbolLibrary, symbolPath, x, y, columnSpan, rowSpan, scanBlocks, visibility, directActivate, parameters, type, action, }: {
119
119
  id: string;
120
120
  label?: string;
121
121
  message?: string;
@@ -132,6 +132,8 @@ export declare class AACButton implements IAACButton {
132
132
  contentSubType?: string;
133
133
  image?: string;
134
134
  resolvedImageEntry?: string;
135
+ symbolLibrary?: string;
136
+ symbolPath?: string;
135
137
  x?: number;
136
138
  y?: number;
137
139
  columnSpan?: number;
@@ -43,7 +43,7 @@ var AACSemanticIntent;
43
43
  AACSemanticIntent["PLATFORM_SPECIFIC"] = "PLATFORM_SPECIFIC";
44
44
  })(AACSemanticIntent || (exports.AACSemanticIntent = AACSemanticIntent = {}));
45
45
  class AACButton {
46
- constructor({ id, label = '', message = '', targetPageId, semanticAction, audioRecording, style, contentType, contentSubType, image, resolvedImageEntry, x, y, columnSpan, rowSpan, scanBlocks, visibility, directActivate, parameters,
46
+ constructor({ id, label = '', message = '', targetPageId, semanticAction, audioRecording, style, contentType, contentSubType, image, resolvedImageEntry, symbolLibrary, symbolPath, x, y, columnSpan, rowSpan, scanBlocks, visibility, directActivate, parameters,
47
47
  // Legacy input support
48
48
  type, action, }) {
49
49
  this.id = id;
@@ -57,6 +57,8 @@ class AACButton {
57
57
  this.contentSubType = contentSubType;
58
58
  this.image = image;
59
59
  this.resolvedImageEntry = resolvedImageEntry;
60
+ this.symbolLibrary = symbolLibrary;
61
+ this.symbolPath = symbolPath;
60
62
  this.x = x;
61
63
  this.y = y;
62
64
  this.columnSpan = columnSpan;
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from './core/baseProcessor';
3
3
  export * from './core/stringCasing';
4
4
  export * from './processors';
5
5
  export { collectUnifiedHistory, listGrid3Users as listHistoryGrid3Users, listSnapUsers as listHistorySnapUsers, } from './analytics/history';
6
+ export * from './validation';
6
7
  import { BaseProcessor } from './core/baseProcessor';
7
8
  /**
8
9
  * Factory function to get the appropriate processor for a file extension
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ var history_1 = require("./analytics/history");
27
27
  Object.defineProperty(exports, "collectUnifiedHistory", { enumerable: true, get: function () { return history_1.collectUnifiedHistory; } });
28
28
  Object.defineProperty(exports, "listHistoryGrid3Users", { enumerable: true, get: function () { return history_1.listGrid3Users; } });
29
29
  Object.defineProperty(exports, "listHistorySnapUsers", { enumerable: true, get: function () { return history_1.listSnapUsers; } });
30
+ __exportStar(require("./validation"), exports);
30
31
  const dotProcessor_1 = require("./processors/dotProcessor");
31
32
  const excelProcessor_1 = require("./processors/excelProcessor");
32
33
  const opmlProcessor_1 = require("./processors/opmlProcessor");
@@ -58,6 +59,7 @@ function getProcessor(filePathOrExtension) {
58
59
  case '.obz':
59
60
  return new obfProcessor_1.ObfProcessor();
60
61
  case '.gridset':
62
+ case '.gridsetx':
61
63
  return new gridsetProcessor_1.GridsetProcessor();
62
64
  case '.spb':
63
65
  case '.sps':
@@ -84,6 +86,7 @@ function getSupportedExtensions() {
84
86
  '.obf',
85
87
  '.obz',
86
88
  '.gridset',
89
+ '.gridsetx',
87
90
  '.spb',
88
91
  '.sps',
89
92
  '.ce',
@@ -7,6 +7,7 @@ exports.TouchChatSymbolResolver = exports.TouchChatSymbolExtractor = exports.Gri
7
7
  exports.resolveSymbol = resolveSymbol;
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const fs_1 = __importDefault(require("fs"));
10
+ const password_1 = require("../processors/gridset/password");
10
11
  // --- Base Classes ---
11
12
  class SymbolExtractor {
12
13
  }
@@ -76,8 +77,9 @@ class Grid3SymbolExtractor extends SymbolExtractor {
76
77
  const zip = new AdmZip(filePath);
77
78
  const parser = new XMLParser();
78
79
  const refs = new Set();
79
- zip.getEntries().forEach((entry) => {
80
- if (entry.entryName.endsWith('.gridset')) {
80
+ const entries = (0, password_1.getZipEntriesWithPassword)(zip, (0, password_1.resolveGridsetPasswordFromEnv)());
81
+ entries.forEach((entry) => {
82
+ if (entry.entryName.endsWith('.gridset') || entry.entryName.endsWith('.gridsetx')) {
81
83
  const xmlBuffer = entry.getData();
82
84
  // Parse to validate XML structure (future: extract refs)
83
85
  parser.parse(xmlBuffer.toString('utf8'));
@@ -54,6 +54,24 @@ export declare function toHexColor(value: string): string | undefined;
54
54
  * @returns Darkened hex color
55
55
  */
56
56
  export declare function darkenColor(hex: string, amount: number): string;
57
+ /**
58
+ * Lighten a hex color by a specified amount
59
+ * @param hex - Hex color string
60
+ * @param amount - Amount to lighten (0-255)
61
+ * @returns Lightened hex color
62
+ */
63
+ export declare function lightenColor(hex: string, amount: number): string;
64
+ /**
65
+ * Convert hex color to RGBA object
66
+ * @param hex - Hex color string (#RRGGBB or #RRGGBBAA)
67
+ * @returns RGBA object with r, g, b, a properties (0-1 for alpha)
68
+ */
69
+ export declare function hexToRgba(hex: string): {
70
+ r: number;
71
+ g: number;
72
+ b: number;
73
+ a: number;
74
+ };
57
75
  /**
58
76
  * Normalize any color format to Grid3's 8-digit hex format
59
77
  * @param input - Color string in any supported format
@@ -16,6 +16,8 @@ exports.clampColorChannel = clampColorChannel;
16
16
  exports.clampAlpha = clampAlpha;
17
17
  exports.toHexColor = toHexColor;
18
18
  exports.darkenColor = darkenColor;
19
+ exports.lightenColor = lightenColor;
20
+ exports.hexToRgba = hexToRgba;
19
21
  exports.normalizeColor = normalizeColor;
20
22
  exports.ensureAlphaChannel = ensureAlphaChannel;
21
23
  /**
@@ -288,6 +290,40 @@ function darkenColor(hex, amount) {
288
290
  const newB = clamp(b - amount);
289
291
  return `#${channelToHex(newR)}${channelToHex(newG)}${channelToHex(newB)}${alpha.toUpperCase()}`;
290
292
  }
293
+ /**
294
+ * Lighten a hex color by a specified amount
295
+ * @param hex - Hex color string
296
+ * @param amount - Amount to lighten (0-255)
297
+ * @returns Lightened hex color
298
+ */
299
+ function lightenColor(hex, amount) {
300
+ const normalized = ensureAlphaChannel(hex).substring(1); // strip #
301
+ const rgb = normalized.substring(0, 6);
302
+ const alpha = normalized.substring(6) || 'FF';
303
+ const r = parseInt(rgb.substring(0, 2), 16);
304
+ const g = parseInt(rgb.substring(2, 4), 16);
305
+ const b = parseInt(rgb.substring(4, 6), 16);
306
+ const clamp = (val) => Math.max(0, Math.min(255, val));
307
+ const newR = clamp(r + amount);
308
+ const newG = clamp(g + amount);
309
+ const newB = clamp(b + amount);
310
+ return `#${channelToHex(newR)}${channelToHex(newG)}${channelToHex(newB)}${alpha.toUpperCase()}`;
311
+ }
312
+ /**
313
+ * Convert hex color to RGBA object
314
+ * @param hex - Hex color string (#RRGGBB or #RRGGBBAA)
315
+ * @returns RGBA object with r, g, b, a properties (0-1 for alpha)
316
+ */
317
+ function hexToRgba(hex) {
318
+ const normalized = ensureAlphaChannel(hex).substring(1); // strip #
319
+ const rgb = normalized.substring(0, 6);
320
+ const alphaHex = normalized.substring(6) || 'FF';
321
+ const r = parseInt(rgb.substring(0, 2), 16);
322
+ const g = parseInt(rgb.substring(2, 4), 16);
323
+ const b = parseInt(rgb.substring(4, 6), 16);
324
+ const a = parseInt(alphaHex, 16) / 255;
325
+ return { r, g, b, a };
326
+ }
291
327
  /**
292
328
  * Normalize any color format to Grid3's 8-digit hex format
293
329
  * @param input - Color string in any supported format
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Grid 3 Command Definitions and Detection System
3
+ *
4
+ * This module provides comprehensive metadata for all Grid 3 commands,
5
+ * organized by plugin/category. It enables:
6
+ * - Command detection and classification
7
+ * - Parameter extraction
8
+ * - Future extensibility for command execution
9
+ * - Semantic action mapping
10
+ *
11
+ * Grid 3 has 33+ plugins with 200+ commands. This catalog captures
12
+ * the most commonly used and important commands.
13
+ */
14
+ /**
15
+ * Command categories in Grid 3
16
+ */
17
+ export declare enum Grid3CommandCategory {
18
+ NAVIGATION = "navigation",
19
+ COMMUNICATION = "communication",
20
+ TEXT_EDITING = "text_editing",
21
+ COMPUTER_CONTROL = "computer_control",
22
+ WEB_BROWSER = "web_browser",
23
+ EMAIL = "email",
24
+ PHONE = "phone",
25
+ SMS = "sms",
26
+ SYSTEM = "system",
27
+ SETTINGS = "settings",
28
+ SPEECH = "speech",
29
+ AUTO_CONTENT = "auto_content",
30
+ ENVIRONMENT_CONTROL = "environment_control",
31
+ MOUSE = "mouse",
32
+ WINDOW = "window",
33
+ MEDIA = "media",
34
+ CUSTOM = "custom"
35
+ }
36
+ /**
37
+ * Parameter definition for commands
38
+ */
39
+ export interface CommandParameter {
40
+ key: string;
41
+ type: 'string' | 'number' | 'boolean' | 'grid' | 'color' | 'font';
42
+ required: boolean;
43
+ description?: string;
44
+ }
45
+ /**
46
+ * Command metadata definition
47
+ */
48
+ export interface Grid3CommandDefinition {
49
+ id: string;
50
+ category: Grid3CommandCategory;
51
+ pluginId: string;
52
+ displayName: string;
53
+ description: string;
54
+ parameters?: CommandParameter[];
55
+ platforms?: ('desktop' | 'ios' | 'medicare' | 'medicareBionics')[];
56
+ deprecated?: boolean;
57
+ }
58
+ /**
59
+ * Registry of all Grid 3 commands
60
+ * Key is command ID (e.g., 'Jump.To', 'Action.InsertText')
61
+ */
62
+ export declare const GRID3_COMMANDS: Record<string, Grid3CommandDefinition>;
63
+ /**
64
+ * Get command definition by ID
65
+ */
66
+ export declare function getCommandDefinition(commandId: string): Grid3CommandDefinition | undefined;
67
+ /**
68
+ * Check if a command ID is known
69
+ */
70
+ export declare function isKnownCommand(commandId: string): boolean;
71
+ /**
72
+ * Get all commands for a specific plugin
73
+ */
74
+ export declare function getCommandsByPlugin(pluginId: string): Grid3CommandDefinition[];
75
+ /**
76
+ * Get all commands in a category
77
+ */
78
+ export declare function getCommandsByCategory(category: Grid3CommandCategory): Grid3CommandDefinition[];
79
+ /**
80
+ * Get all command IDs
81
+ */
82
+ export declare function getAllCommandIds(): string[];
83
+ /**
84
+ * Get all plugin IDs that have commands
85
+ */
86
+ export declare function getAllPluginIds(): string[];
87
+ /**
88
+ * Extract parameters from a Grid 3 command object
89
+ */
90
+ export interface ExtractedParameters {
91
+ [key: string]: string | number | boolean;
92
+ }
93
+ export declare function extractCommandParameters(command: any): ExtractedParameters;
94
+ /**
95
+ * Detect and categorize a command from Grid 3
96
+ */
97
+ export declare function detectCommand(commandObj: any): {
98
+ id: string;
99
+ definition?: Grid3CommandDefinition;
100
+ parameters: ExtractedParameters;
101
+ category: Grid3CommandCategory | 'unknown';
102
+ pluginId: string | 'unknown';
103
+ };