@willwade/aac-processors 0.0.6 → 0.0.7
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/README.md +0 -37
- package/dist/processors/dotProcessor.js +31 -12
- package/dist/processors/gridset/colorUtils.d.ts +69 -0
- package/dist/processors/gridset/colorUtils.js +331 -0
- package/dist/processors/gridset/helpers.d.ts +30 -0
- package/dist/processors/gridset/helpers.js +69 -0
- package/dist/processors/gridset/styleHelpers.d.ts +3 -4
- package/dist/processors/gridset/styleHelpers.js +10 -44
- package/dist/processors/index.d.ts +5 -3
- package/dist/processors/index.js +21 -2
- package/dist/processors/obfProcessor.js +4 -1
- package/dist/processors/snapProcessor.js +27 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -658,13 +658,8 @@ npm test
|
|
|
658
658
|
|
|
659
659
|
- The repository keeps `package.json` at `0.0.0-development`; release tags control the published version.
|
|
660
660
|
- Create a GitHub release with a semantic tag (e.g. `v2.1.0`). Publishing only runs for non-prerelease tags.
|
|
661
|
-
- Add an `NPM_TOKEN` repository secret with publish rights. The release workflow uses it to authenticate and calls `npm publish`.
|
|
662
661
|
- The workflow (`.github/workflows/publish.yml`) automatically installs dependencies, rewrites the package version from the tag, and runs the standard publish pipeline.
|
|
663
662
|
|
|
664
|
-
**Private distribution options**
|
|
665
|
-
- Unscoped packages on npm must be public. To keep this package private, re-scope it (e.g. `@your-org/aac-processors`) and configure `publishConfig.access: "restricted"`—this requires an npm org with paid seats.
|
|
666
|
-
- Alternatively, publish to GitHub Packages by adjusting the workflow’s registry URL and using a `GITHUB_TOKEN` with the `packages: write` permission.
|
|
667
|
-
|
|
668
663
|
---
|
|
669
664
|
|
|
670
665
|
## 📄 License
|
|
@@ -715,15 +710,6 @@ Inspired by the Python AACProcessors project
|
|
|
715
710
|
- [ ] **Add Symbol Tools coverage** (currently 0%) - Implement tests for PCS and ARASAAC symbol lookups to reach >70% coverage
|
|
716
711
|
- [ ] **Fix property-based test failures** - Resolve TypeScript interface compatibility issues in edge case generators
|
|
717
712
|
|
|
718
|
-
### Recently Completed ✅
|
|
719
|
-
|
|
720
|
-
- [x] **Core utilities test coverage** - Complete implementation for analyze.ts and fileProcessor.ts (0% → 100% coverage, 45 comprehensive tests, src/core/ directory 30% → 83% coverage)
|
|
721
|
-
- [x] **CLI test infrastructure** - Fixed DotProcessor parsing and test expectations (0 → 25 passing tests, 100% CLI functionality)
|
|
722
|
-
- [x] **Critical linting fixes** - Resolved unsafe argument types and CLI type safety issues (177 → 123 errors, 32% improvement)
|
|
723
|
-
- [x] **Audio test syntax fixes** - Fixed non-null assertion errors in audio tests (21 → 5 failing tests, 76% improvement)
|
|
724
|
-
- [x] **Comprehensive styling support** - Complete implementation across all AAC formats with cross-format preservation (Added: AACStyle interface, enhanced all processors, 7 new test cases, complete documentation)
|
|
725
|
-
- [x] **TouchChatProcessor save/load functionality** - Fixed button persistence and ID mapping (coverage improved from 57.62% to 86.44%)
|
|
726
|
-
- [x] **Build integration** - Ensure `npm run build` is executed before CLI tests (Fixed: All test scripts now automatically build before running)
|
|
727
713
|
|
|
728
714
|
### Medium Priority
|
|
729
715
|
|
|
@@ -749,29 +735,6 @@ Inspired by the Python AACProcessors project
|
|
|
749
735
|
- [ ] **CI/CD improvements** - Add automated releases and npm publishing
|
|
750
736
|
- [ ] **Documentation improvements** - Add more real-world examples and tutorials
|
|
751
737
|
|
|
752
|
-
### Known Issues
|
|
753
|
-
|
|
754
|
-
- ⚠️ **Audio Persistence**: 5 functional tests failing due to audio recording not persisting through SnapProcessor save/load cycle
|
|
755
|
-
- ⚠️ **Grid3 Layout**: Grid sizes not reliable and X,Y positions incorrect, particularly affecting Grid3 processor functionality
|
|
756
|
-
- ⚠️ **Database Constraints**: UNIQUE constraint violations with real-world data files (Page.Id and buttons.id conflicts)
|
|
757
|
-
- ⚠️ **Linting**: 123 ESLint issues remaining (mostly in test files, reduced from 177)
|
|
758
|
-
- ⚠️ **SnapProcessor**: Lowest coverage at 48.32%, missing comprehensive audio handling tests
|
|
759
|
-
- ⚠️ **Memory usage**: Large files (>50MB) may cause memory pressure
|
|
760
|
-
- ⚠️ **Concurrent access**: Some processors not fully thread-safe for simultaneous writes
|
|
761
|
-
|
|
762
|
-
### 🧪 Current Test Status & Immediate Follow-Up
|
|
763
|
-
|
|
764
|
-
As of the latest run (`npm test`), **47 suites pass / 6 fail (10 individual tests)**. Remaining blockers are:
|
|
765
|
-
|
|
766
|
-
1. **Edge-case loaders** – corrupted JSON/XML fixtures still expect explicit exceptions. Decide whether to restore the old throwing behaviour (Asterics/OPML/DOT) or update the tests to accept the softer error reporting.
|
|
767
|
-
2. **Gridset exports & styling** – round-trip continues to lose a button and the styling suite cannot find `style.xml`. GridsetProcessor needs to preserve button arrays and emit the styling assets Grid 3 expects.
|
|
768
|
-
3. **DOT navigation semantics** – the deterministic DOT test still falls back to `SPEAK`. Improve semantic reconstruction when loading navigation edges so navigation buttons survive round-trips.
|
|
769
|
-
4. **Advanced workflow scenario** – the multi-format pipeline still loses Spanish translations (likely during the Gridset ⇄ Snap steps); trace text propagation and patch the conversion chain.
|
|
770
|
-
5. **Styling suite** – Grid 3 export still lacks `style.xml`; ensure the styling assets are generated alongside the gridset payload.
|
|
771
|
-
6. **Memory comparison suite** – memory delta expectations are still unmet (TouchChat GC + DOT vs others). Either recalibrate the harness or tune the processors before re-enabling the assertions.
|
|
772
|
-
|
|
773
|
-
Clearing these items will put the test matrix back in the green and unblock the release.
|
|
774
|
-
|
|
775
738
|
## More enhancements
|
|
776
739
|
|
|
777
740
|
- Much more effort put into fixing the layout issues. Grid sizes are not reliably and X, Y positions too. Particularly in the Grid3
|
|
@@ -17,17 +17,14 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
17
17
|
const edges = [];
|
|
18
18
|
// Extract all edge statements using regex to handle single-line DOT files
|
|
19
19
|
const edgeRegex = /"?([^"\s]+)"?\s*->\s*"?([^"\s]+)"?(?:\s*\[label="([^"]+)"\])?/g;
|
|
20
|
-
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const [, id, label] = nodeMatch;
|
|
25
|
-
nodes.set(id, { id, label });
|
|
26
|
-
}
|
|
27
|
-
// Find all edge definitions
|
|
20
|
+
// We need to find nodes, but avoid matching the target of an edge which might look like a node definition
|
|
21
|
+
// e.g. A -> B [label="L"] -- "B [label="L"]" looks like a node def
|
|
22
|
+
// Strategy: Find all edges, record them, and then "mask" them in the content to avoid false positives for nodes
|
|
23
|
+
let maskedContent = content;
|
|
28
24
|
let edgeMatch;
|
|
25
|
+
// Find all edge definitions
|
|
29
26
|
while ((edgeMatch = edgeRegex.exec(content)) !== null) {
|
|
30
|
-
const [, from, to, label] = edgeMatch;
|
|
27
|
+
const [fullMatch, from, to, label] = edgeMatch;
|
|
31
28
|
edges.push({ from, to, label });
|
|
32
29
|
// Add nodes if they don't exist (implicit definition)
|
|
33
30
|
if (!nodes.has(from)) {
|
|
@@ -36,6 +33,23 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
36
33
|
if (!nodes.has(to)) {
|
|
37
34
|
nodes.set(to, { id: to, label: to });
|
|
38
35
|
}
|
|
36
|
+
// Mask this edge in the content so we don't match it as a node
|
|
37
|
+
// We replace it with spaces to preserve indices if needed, but simple replacement is enough here
|
|
38
|
+
maskedContent = maskedContent.replace(fullMatch, ' '.repeat(fullMatch.length));
|
|
39
|
+
}
|
|
40
|
+
// Now find explicit node definitions in the masked content
|
|
41
|
+
// This regex matches: ID [label="LABEL"]
|
|
42
|
+
// We use a non-greedy match for the label content to handle escaped quotes if possible,
|
|
43
|
+
// but the previous regex `[^"]+` was too simple.
|
|
44
|
+
// Better regex for quoted string content: (?:[^"\\]|\\.)*
|
|
45
|
+
const nodeRegex = /"?([^"\s]+)"?\s*\[label="((?:[^"\\]|\\.)*)"\]/g;
|
|
46
|
+
let nodeMatch;
|
|
47
|
+
while ((nodeMatch = nodeRegex.exec(maskedContent)) !== null) {
|
|
48
|
+
const [, id, rawLabel] = nodeMatch;
|
|
49
|
+
// Unescape the label: replace \" with " and \\ with \
|
|
50
|
+
const label = rawLabel.replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
|
51
|
+
// Only update if not already defined or if we want to override the implicit label
|
|
52
|
+
nodes.set(id, { id, label });
|
|
39
53
|
}
|
|
40
54
|
return { nodes: Array.from(nodes.values()), edges };
|
|
41
55
|
}
|
|
@@ -82,7 +96,8 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
82
96
|
let hasControl = false;
|
|
83
97
|
for (let i = 0; i < head.length; i++) {
|
|
84
98
|
const code = head.charCodeAt(i);
|
|
85
|
-
|
|
99
|
+
// Allow UTF-8 characters (code >= 127)
|
|
100
|
+
if (code === 0 || (code >= 0 && code <= 8) || (code >= 14 && code <= 31)) {
|
|
86
101
|
hasControl = true;
|
|
87
102
|
break;
|
|
88
103
|
}
|
|
@@ -150,10 +165,14 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
150
165
|
}
|
|
151
166
|
saveFromTree(tree, _outputPath) {
|
|
152
167
|
let dotContent = 'digraph AACBoard {\n';
|
|
168
|
+
// Helper to escape DOT string
|
|
169
|
+
const escapeDotString = (str) => {
|
|
170
|
+
return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
171
|
+
};
|
|
153
172
|
// Add nodes
|
|
154
173
|
for (const pageId in tree.pages) {
|
|
155
174
|
const page = tree.pages[pageId];
|
|
156
|
-
dotContent += ` "${page.id}" [label="${page.name}"]\n`;
|
|
175
|
+
dotContent += ` "${page.id}" [label="${escapeDotString(page.name)}"]\n`;
|
|
157
176
|
}
|
|
158
177
|
// Add edges from navigation buttons (semantic intent or legacy targetPageId)
|
|
159
178
|
for (const pageId in tree.pages) {
|
|
@@ -166,7 +185,7 @@ class DotProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
166
185
|
.forEach((btn) => {
|
|
167
186
|
const target = btn.semanticAction?.targetId || btn.targetPageId;
|
|
168
187
|
if (target) {
|
|
169
|
-
dotContent += ` "${page.id}" -> "${target}" [label="${btn.label}"]\n`;
|
|
188
|
+
dotContent += ` "${page.id}" -> "${target}" [label="${escapeDotString(btn.label)}"]\n`;
|
|
170
189
|
}
|
|
171
190
|
});
|
|
172
191
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grid3 Color Utilities
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive color handling for Grid3 format, including:
|
|
5
|
+
* - CSS color name lookup (147 named colors)
|
|
6
|
+
* - Color format conversion (hex, RGB, RGBA, named colors)
|
|
7
|
+
* - Color manipulation (darkening, normalization)
|
|
8
|
+
* - Grid3-specific color formatting (8-digit ARGB hex)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Get RGB values for a CSS color name
|
|
12
|
+
* @param name - CSS color name (case-insensitive)
|
|
13
|
+
* @returns RGB tuple [r, g, b] or undefined if not found
|
|
14
|
+
*/
|
|
15
|
+
export declare function getNamedColor(name: string): [number, number, number] | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Convert RGBA values to hex format
|
|
18
|
+
* @param r - Red channel (0-255)
|
|
19
|
+
* @param g - Green channel (0-255)
|
|
20
|
+
* @param b - Blue channel (0-255)
|
|
21
|
+
* @param a - Alpha channel (0-1)
|
|
22
|
+
* @returns Hex color string in format #RRGGBBAA
|
|
23
|
+
*/
|
|
24
|
+
export declare function rgbaToHex(r: number, g: number, b: number, a: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* Convert a single color channel value to hex
|
|
27
|
+
* @param value - Channel value (0-255)
|
|
28
|
+
* @returns Two-digit hex string
|
|
29
|
+
*/
|
|
30
|
+
export declare function channelToHex(value: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* Clamp RGB channel value to valid range
|
|
33
|
+
* @param value - Channel value
|
|
34
|
+
* @returns Clamped value (0-255)
|
|
35
|
+
*/
|
|
36
|
+
export declare function clampColorChannel(value: number): number;
|
|
37
|
+
/**
|
|
38
|
+
* Clamp alpha value to valid range
|
|
39
|
+
* @param value - Alpha value
|
|
40
|
+
* @returns Clamped value (0-1)
|
|
41
|
+
*/
|
|
42
|
+
export declare function clampAlpha(value: number): number;
|
|
43
|
+
/**
|
|
44
|
+
* Convert any color format to hex
|
|
45
|
+
* Supports: hex (#RGB, #RRGGBB, #RRGGBBAA), RGB/RGBA, and CSS color names
|
|
46
|
+
* @param value - Color string in any supported format
|
|
47
|
+
* @returns Hex color string (#RRGGBBAA) or undefined if invalid
|
|
48
|
+
*/
|
|
49
|
+
export declare function toHexColor(value: string): string | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Darken a hex color by a specified amount
|
|
52
|
+
* @param hex - Hex color string
|
|
53
|
+
* @param amount - Amount to darken (0-255)
|
|
54
|
+
* @returns Darkened hex color
|
|
55
|
+
*/
|
|
56
|
+
export declare function darkenColor(hex: string, amount: number): string;
|
|
57
|
+
/**
|
|
58
|
+
* Normalize any color format to Grid3's 8-digit hex format
|
|
59
|
+
* @param input - Color string in any supported format
|
|
60
|
+
* @param fallback - Fallback color if input is invalid (default: white)
|
|
61
|
+
* @returns Normalized color in format #AARRGGBBFF
|
|
62
|
+
*/
|
|
63
|
+
export declare function normalizeColor(input: string, fallback?: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Ensure a color has an alpha channel (Grid3 format requires 8-digit ARGB)
|
|
66
|
+
* @param color - Color string (hex format)
|
|
67
|
+
* @returns Color with alpha channel in format #AARRGGBBFF
|
|
68
|
+
*/
|
|
69
|
+
export declare function ensureAlphaChannel(color: string | undefined): string;
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Grid3 Color Utilities
|
|
4
|
+
*
|
|
5
|
+
* Comprehensive color handling for Grid3 format, including:
|
|
6
|
+
* - CSS color name lookup (147 named colors)
|
|
7
|
+
* - Color format conversion (hex, RGB, RGBA, named colors)
|
|
8
|
+
* - Color manipulation (darkening, normalization)
|
|
9
|
+
* - Grid3-specific color formatting (8-digit ARGB hex)
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getNamedColor = getNamedColor;
|
|
13
|
+
exports.rgbaToHex = rgbaToHex;
|
|
14
|
+
exports.channelToHex = channelToHex;
|
|
15
|
+
exports.clampColorChannel = clampColorChannel;
|
|
16
|
+
exports.clampAlpha = clampAlpha;
|
|
17
|
+
exports.toHexColor = toHexColor;
|
|
18
|
+
exports.darkenColor = darkenColor;
|
|
19
|
+
exports.normalizeColor = normalizeColor;
|
|
20
|
+
exports.ensureAlphaChannel = ensureAlphaChannel;
|
|
21
|
+
/**
|
|
22
|
+
* CSS color names to RGB values
|
|
23
|
+
* Supports 147 standard CSS color names
|
|
24
|
+
*/
|
|
25
|
+
const CSS_COLORS = {
|
|
26
|
+
aliceblue: [240, 248, 255],
|
|
27
|
+
antiquewhite: [250, 235, 215],
|
|
28
|
+
aqua: [0, 255, 255],
|
|
29
|
+
aquamarine: [127, 255, 212],
|
|
30
|
+
azure: [240, 255, 255],
|
|
31
|
+
beige: [245, 245, 220],
|
|
32
|
+
bisque: [255, 228, 196],
|
|
33
|
+
black: [0, 0, 0],
|
|
34
|
+
blanchedalmond: [255, 235, 205],
|
|
35
|
+
blue: [0, 0, 255],
|
|
36
|
+
blueviolet: [138, 43, 226],
|
|
37
|
+
brown: [165, 42, 42],
|
|
38
|
+
burlywood: [222, 184, 135],
|
|
39
|
+
cadetblue: [95, 158, 160],
|
|
40
|
+
chartreuse: [127, 255, 0],
|
|
41
|
+
chocolate: [210, 105, 30],
|
|
42
|
+
coral: [255, 127, 80],
|
|
43
|
+
cornflowerblue: [100, 149, 237],
|
|
44
|
+
cornsilk: [255, 248, 220],
|
|
45
|
+
crimson: [220, 20, 60],
|
|
46
|
+
cyan: [0, 255, 255],
|
|
47
|
+
darkblue: [0, 0, 139],
|
|
48
|
+
darkcyan: [0, 139, 139],
|
|
49
|
+
darkgoldenrod: [184, 134, 11],
|
|
50
|
+
darkgray: [169, 169, 169],
|
|
51
|
+
darkgreen: [0, 100, 0],
|
|
52
|
+
darkgrey: [169, 169, 169],
|
|
53
|
+
darkkhaki: [189, 183, 107],
|
|
54
|
+
darkmagenta: [139, 0, 139],
|
|
55
|
+
darkolivegreen: [85, 107, 47],
|
|
56
|
+
darkorange: [255, 140, 0],
|
|
57
|
+
darkorchid: [153, 50, 204],
|
|
58
|
+
darkred: [139, 0, 0],
|
|
59
|
+
darksalmon: [233, 150, 122],
|
|
60
|
+
darkseagreen: [143, 188, 143],
|
|
61
|
+
darkslateblue: [72, 61, 139],
|
|
62
|
+
darkslategray: [47, 79, 79],
|
|
63
|
+
darkslategrey: [47, 79, 79],
|
|
64
|
+
darkturquoise: [0, 206, 209],
|
|
65
|
+
darkviolet: [148, 0, 211],
|
|
66
|
+
deeppink: [255, 20, 147],
|
|
67
|
+
deepskyblue: [0, 191, 255],
|
|
68
|
+
dimgray: [105, 105, 105],
|
|
69
|
+
dimgrey: [105, 105, 105],
|
|
70
|
+
dodgerblue: [30, 144, 255],
|
|
71
|
+
firebrick: [178, 34, 34],
|
|
72
|
+
floralwhite: [255, 250, 240],
|
|
73
|
+
forestgreen: [34, 139, 34],
|
|
74
|
+
fuchsia: [255, 0, 255],
|
|
75
|
+
gainsboro: [220, 220, 220],
|
|
76
|
+
ghostwhite: [248, 248, 255],
|
|
77
|
+
gold: [255, 215, 0],
|
|
78
|
+
goldenrod: [218, 165, 32],
|
|
79
|
+
gray: [128, 128, 128],
|
|
80
|
+
grey: [128, 128, 128],
|
|
81
|
+
green: [0, 128, 0],
|
|
82
|
+
greenyellow: [173, 255, 47],
|
|
83
|
+
honeydew: [240, 255, 240],
|
|
84
|
+
hotpink: [255, 105, 180],
|
|
85
|
+
indianred: [205, 92, 92],
|
|
86
|
+
indigo: [75, 0, 130],
|
|
87
|
+
ivory: [255, 255, 240],
|
|
88
|
+
khaki: [240, 230, 140],
|
|
89
|
+
lavender: [230, 230, 250],
|
|
90
|
+
lavenderblush: [255, 240, 245],
|
|
91
|
+
lawngreen: [124, 252, 0],
|
|
92
|
+
lemonchiffon: [255, 250, 205],
|
|
93
|
+
lightblue: [173, 216, 230],
|
|
94
|
+
lightcoral: [240, 128, 128],
|
|
95
|
+
lightcyan: [224, 255, 255],
|
|
96
|
+
lightgoldenrodyellow: [250, 250, 210],
|
|
97
|
+
lightgray: [211, 211, 211],
|
|
98
|
+
lightgreen: [144, 238, 144],
|
|
99
|
+
lightgrey: [211, 211, 211],
|
|
100
|
+
lightpink: [255, 182, 193],
|
|
101
|
+
lightsalmon: [255, 160, 122],
|
|
102
|
+
lightseagreen: [32, 178, 170],
|
|
103
|
+
lightskyblue: [135, 206, 250],
|
|
104
|
+
lightslategray: [119, 136, 153],
|
|
105
|
+
lightslategrey: [119, 136, 153],
|
|
106
|
+
lightsteelblue: [176, 196, 222],
|
|
107
|
+
lightyellow: [255, 255, 224],
|
|
108
|
+
lime: [0, 255, 0],
|
|
109
|
+
limegreen: [50, 205, 50],
|
|
110
|
+
linen: [250, 240, 230],
|
|
111
|
+
magenta: [255, 0, 255],
|
|
112
|
+
maroon: [128, 0, 0],
|
|
113
|
+
mediumaquamarine: [102, 205, 170],
|
|
114
|
+
mediumblue: [0, 0, 205],
|
|
115
|
+
mediumorchid: [186, 85, 211],
|
|
116
|
+
mediumpurple: [147, 112, 219],
|
|
117
|
+
mediumseagreen: [60, 179, 113],
|
|
118
|
+
mediumslateblue: [123, 104, 238],
|
|
119
|
+
mediumspringgreen: [0, 250, 154],
|
|
120
|
+
mediumturquoise: [72, 209, 204],
|
|
121
|
+
mediumvioletred: [199, 21, 133],
|
|
122
|
+
midnightblue: [25, 25, 112],
|
|
123
|
+
mintcream: [245, 255, 250],
|
|
124
|
+
mistyrose: [255, 228, 225],
|
|
125
|
+
moccasin: [255, 228, 181],
|
|
126
|
+
navajowhite: [255, 222, 173],
|
|
127
|
+
navy: [0, 0, 128],
|
|
128
|
+
oldlace: [253, 245, 230],
|
|
129
|
+
olive: [128, 128, 0],
|
|
130
|
+
olivedrab: [107, 142, 35],
|
|
131
|
+
orange: [255, 165, 0],
|
|
132
|
+
orangered: [255, 69, 0],
|
|
133
|
+
orchid: [218, 112, 214],
|
|
134
|
+
palegoldenrod: [238, 232, 170],
|
|
135
|
+
palegreen: [152, 251, 152],
|
|
136
|
+
paleturquoise: [175, 238, 238],
|
|
137
|
+
palevioletred: [219, 112, 147],
|
|
138
|
+
papayawhip: [255, 239, 213],
|
|
139
|
+
peachpuff: [255, 218, 185],
|
|
140
|
+
peru: [205, 133, 63],
|
|
141
|
+
pink: [255, 192, 203],
|
|
142
|
+
plum: [221, 160, 221],
|
|
143
|
+
powderblue: [176, 224, 230],
|
|
144
|
+
purple: [128, 0, 128],
|
|
145
|
+
rebeccapurple: [102, 51, 153],
|
|
146
|
+
red: [255, 0, 0],
|
|
147
|
+
rosybrown: [188, 143, 143],
|
|
148
|
+
royalblue: [65, 105, 225],
|
|
149
|
+
saddlebrown: [139, 69, 19],
|
|
150
|
+
salmon: [250, 128, 114],
|
|
151
|
+
sandybrown: [244, 164, 96],
|
|
152
|
+
seagreen: [46, 139, 87],
|
|
153
|
+
seashell: [255, 245, 238],
|
|
154
|
+
sienna: [160, 82, 45],
|
|
155
|
+
silver: [192, 192, 192],
|
|
156
|
+
skyblue: [135, 206, 235],
|
|
157
|
+
slateblue: [106, 90, 205],
|
|
158
|
+
slategray: [112, 128, 144],
|
|
159
|
+
slategrey: [112, 128, 144],
|
|
160
|
+
snow: [255, 250, 250],
|
|
161
|
+
springgreen: [0, 255, 127],
|
|
162
|
+
steelblue: [70, 130, 180],
|
|
163
|
+
tan: [210, 180, 140],
|
|
164
|
+
teal: [0, 128, 128],
|
|
165
|
+
thistle: [216, 191, 216],
|
|
166
|
+
tomato: [255, 99, 71],
|
|
167
|
+
turquoise: [64, 224, 208],
|
|
168
|
+
violet: [238, 130, 238],
|
|
169
|
+
wheat: [245, 222, 179],
|
|
170
|
+
white: [255, 255, 255],
|
|
171
|
+
whitesmoke: [245, 245, 245],
|
|
172
|
+
yellow: [255, 255, 0],
|
|
173
|
+
yellowgreen: [154, 205, 50],
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Get RGB values for a CSS color name
|
|
177
|
+
* @param name - CSS color name (case-insensitive)
|
|
178
|
+
* @returns RGB tuple [r, g, b] or undefined if not found
|
|
179
|
+
*/
|
|
180
|
+
function getNamedColor(name) {
|
|
181
|
+
const color = CSS_COLORS[name.toLowerCase()];
|
|
182
|
+
return color;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Convert RGBA values to hex format
|
|
186
|
+
* @param r - Red channel (0-255)
|
|
187
|
+
* @param g - Green channel (0-255)
|
|
188
|
+
* @param b - Blue channel (0-255)
|
|
189
|
+
* @param a - Alpha channel (0-1)
|
|
190
|
+
* @returns Hex color string in format #RRGGBBAA
|
|
191
|
+
*/
|
|
192
|
+
function rgbaToHex(r, g, b, a) {
|
|
193
|
+
const red = channelToHex(r);
|
|
194
|
+
const green = channelToHex(g);
|
|
195
|
+
const blue = channelToHex(b);
|
|
196
|
+
const alpha = channelToHex(Math.round(a * 255));
|
|
197
|
+
return `#${red}${green}${blue}${alpha}`;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Convert a single color channel value to hex
|
|
201
|
+
* @param value - Channel value (0-255)
|
|
202
|
+
* @returns Two-digit hex string
|
|
203
|
+
*/
|
|
204
|
+
function channelToHex(value) {
|
|
205
|
+
const clamped = Math.max(0, Math.min(255, Math.round(value)));
|
|
206
|
+
return clamped.toString(16).padStart(2, '0').toUpperCase();
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Clamp RGB channel value to valid range
|
|
210
|
+
* @param value - Channel value
|
|
211
|
+
* @returns Clamped value (0-255)
|
|
212
|
+
*/
|
|
213
|
+
function clampColorChannel(value) {
|
|
214
|
+
if (Number.isNaN(value)) {
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
return Math.max(0, Math.min(255, value));
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Clamp alpha value to valid range
|
|
221
|
+
* @param value - Alpha value
|
|
222
|
+
* @returns Clamped value (0-1)
|
|
223
|
+
*/
|
|
224
|
+
function clampAlpha(value) {
|
|
225
|
+
if (Number.isNaN(value)) {
|
|
226
|
+
return 1;
|
|
227
|
+
}
|
|
228
|
+
return Math.max(0, Math.min(1, value));
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Convert any color format to hex
|
|
232
|
+
* Supports: hex (#RGB, #RRGGBB, #RRGGBBAA), RGB/RGBA, and CSS color names
|
|
233
|
+
* @param value - Color string in any supported format
|
|
234
|
+
* @returns Hex color string (#RRGGBBAA) or undefined if invalid
|
|
235
|
+
*/
|
|
236
|
+
function toHexColor(value) {
|
|
237
|
+
// Try hex format
|
|
238
|
+
const hexMatch = value.match(/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i);
|
|
239
|
+
if (hexMatch) {
|
|
240
|
+
const hex = hexMatch[1];
|
|
241
|
+
if (hex.length === 3 || hex.length === 4) {
|
|
242
|
+
return `#${hex
|
|
243
|
+
.split('')
|
|
244
|
+
.map((char) => char + char)
|
|
245
|
+
.join('')}`;
|
|
246
|
+
}
|
|
247
|
+
return `#${hex}`;
|
|
248
|
+
}
|
|
249
|
+
// Try RGB/RGBA format
|
|
250
|
+
const rgbMatch = value.match(/^rgba?\((.+)\)$/i);
|
|
251
|
+
if (rgbMatch) {
|
|
252
|
+
const parts = rgbMatch[1]
|
|
253
|
+
.split(',')
|
|
254
|
+
.map((part) => part.trim())
|
|
255
|
+
.filter(Boolean);
|
|
256
|
+
if (parts.length === 3 || parts.length === 4) {
|
|
257
|
+
const [r, g, b, a] = parts;
|
|
258
|
+
const red = clampColorChannel(parseFloat(r));
|
|
259
|
+
const green = clampColorChannel(parseFloat(g));
|
|
260
|
+
const blue = clampColorChannel(parseFloat(b));
|
|
261
|
+
const alpha = parts.length === 4 ? clampAlpha(parseFloat(a)) : 1;
|
|
262
|
+
return rgbaToHex(red, green, blue, alpha);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// Try CSS color name
|
|
266
|
+
const rgb = getNamedColor(value);
|
|
267
|
+
if (rgb) {
|
|
268
|
+
return rgbaToHex(rgb[0], rgb[1], rgb[2], 1);
|
|
269
|
+
}
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Darken a hex color by a specified amount
|
|
274
|
+
* @param hex - Hex color string
|
|
275
|
+
* @param amount - Amount to darken (0-255)
|
|
276
|
+
* @returns Darkened hex color
|
|
277
|
+
*/
|
|
278
|
+
function darkenColor(hex, amount) {
|
|
279
|
+
const normalized = ensureAlphaChannel(hex).substring(1); // strip #
|
|
280
|
+
const rgb = normalized.substring(0, 6);
|
|
281
|
+
const alpha = normalized.substring(6) || 'FF';
|
|
282
|
+
const r = parseInt(rgb.substring(0, 2), 16);
|
|
283
|
+
const g = parseInt(rgb.substring(2, 4), 16);
|
|
284
|
+
const b = parseInt(rgb.substring(4, 6), 16);
|
|
285
|
+
const clamp = (val) => Math.max(0, Math.min(255, val));
|
|
286
|
+
const newR = clamp(r - amount);
|
|
287
|
+
const newG = clamp(g - amount);
|
|
288
|
+
const newB = clamp(b - amount);
|
|
289
|
+
return `#${channelToHex(newR)}${channelToHex(newG)}${channelToHex(newB)}${alpha.toUpperCase()}`;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Normalize any color format to Grid3's 8-digit hex format
|
|
293
|
+
* @param input - Color string in any supported format
|
|
294
|
+
* @param fallback - Fallback color if input is invalid (default: white)
|
|
295
|
+
* @returns Normalized color in format #AARRGGBBFF
|
|
296
|
+
*/
|
|
297
|
+
function normalizeColor(input, fallback = '#FFFFFFFF') {
|
|
298
|
+
const trimmed = input.trim();
|
|
299
|
+
if (!trimmed) {
|
|
300
|
+
return fallback;
|
|
301
|
+
}
|
|
302
|
+
const hex = toHexColor(trimmed);
|
|
303
|
+
if (hex) {
|
|
304
|
+
return ensureAlphaChannel(hex).toUpperCase();
|
|
305
|
+
}
|
|
306
|
+
return fallback;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Ensure a color has an alpha channel (Grid3 format requires 8-digit ARGB)
|
|
310
|
+
* @param color - Color string (hex format)
|
|
311
|
+
* @returns Color with alpha channel in format #AARRGGBBFF
|
|
312
|
+
*/
|
|
313
|
+
function ensureAlphaChannel(color) {
|
|
314
|
+
if (!color)
|
|
315
|
+
return '#FFFFFFFF';
|
|
316
|
+
// If already 8 digits (with alpha), return as is
|
|
317
|
+
if (color.match(/^#[0-9A-Fa-f]{8}$/))
|
|
318
|
+
return color;
|
|
319
|
+
// If 6 digits (no alpha), add FF for fully opaque
|
|
320
|
+
if (color.match(/^#[0-9A-Fa-f]{6}$/))
|
|
321
|
+
return color + 'FF';
|
|
322
|
+
// If 3 digits (shorthand), expand to 8
|
|
323
|
+
if (color.match(/^#[0-9A-Fa-f]{3}$/)) {
|
|
324
|
+
const r = color[1];
|
|
325
|
+
const g = color[2];
|
|
326
|
+
const b = color[3];
|
|
327
|
+
return `#${r}${r}${g}${g}${b}${b}FF`;
|
|
328
|
+
}
|
|
329
|
+
// Invalid or unknown format, return white
|
|
330
|
+
return '#FFFFFFFF';
|
|
331
|
+
}
|
|
@@ -2,3 +2,33 @@ import { AACTree } from '../../core/treeStructure';
|
|
|
2
2
|
export declare function getPageTokenImageMap(tree: AACTree, pageId: string): Map<string, string>;
|
|
3
3
|
export declare function getAllowedImageEntries(tree: AACTree): Set<string>;
|
|
4
4
|
export declare function openImage(gridsetBuffer: Buffer, entryPath: string): Buffer | null;
|
|
5
|
+
/**
|
|
6
|
+
* Generate a random GUID for Grid3 elements
|
|
7
|
+
* Grid3 uses GUIDs for grid identification
|
|
8
|
+
* @returns A UUID v4-like string in the format xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateGrid3Guid(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Create Grid3 settings XML with start grid and common settings
|
|
13
|
+
* @param startGrid - Name of the grid to start on
|
|
14
|
+
* @param options - Optional settings (scan, hover, language, etc.)
|
|
15
|
+
* @returns XML string for Settings.xml
|
|
16
|
+
*/
|
|
17
|
+
export declare function createSettingsXml(startGrid: string, options?: {
|
|
18
|
+
scanEnabled?: boolean;
|
|
19
|
+
scanTimeoutMs?: number;
|
|
20
|
+
hoverEnabled?: boolean;
|
|
21
|
+
hoverTimeoutMs?: number;
|
|
22
|
+
mouseclickEnabled?: boolean;
|
|
23
|
+
language?: string;
|
|
24
|
+
}): string;
|
|
25
|
+
/**
|
|
26
|
+
* Create Grid3 FileMap.xml content
|
|
27
|
+
* @param grids - Array of grid configurations with name and path
|
|
28
|
+
* @returns XML string for FileMap.xml
|
|
29
|
+
*/
|
|
30
|
+
export declare function createFileMapXml(grids: Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
path: string;
|
|
33
|
+
dynamicFiles?: string[];
|
|
34
|
+
}>): string;
|
|
@@ -6,7 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.getPageTokenImageMap = getPageTokenImageMap;
|
|
7
7
|
exports.getAllowedImageEntries = getAllowedImageEntries;
|
|
8
8
|
exports.openImage = openImage;
|
|
9
|
+
exports.generateGrid3Guid = generateGrid3Guid;
|
|
10
|
+
exports.createSettingsXml = createSettingsXml;
|
|
11
|
+
exports.createFileMapXml = createFileMapXml;
|
|
9
12
|
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
13
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
10
14
|
function normalizeZipPath(p) {
|
|
11
15
|
const unified = p.replace(/\\/g, '/');
|
|
12
16
|
try {
|
|
@@ -46,3 +50,68 @@ function openImage(gridsetBuffer, entryPath) {
|
|
|
46
50
|
return null;
|
|
47
51
|
return entry.getData();
|
|
48
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Generate a random GUID for Grid3 elements
|
|
55
|
+
* Grid3 uses GUIDs for grid identification
|
|
56
|
+
* @returns A UUID v4-like string in the format xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
57
|
+
*/
|
|
58
|
+
function generateGrid3Guid() {
|
|
59
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
60
|
+
const r = (Math.random() * 16) | 0;
|
|
61
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
62
|
+
return v.toString(16);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create Grid3 settings XML with start grid and common settings
|
|
67
|
+
* @param startGrid - Name of the grid to start on
|
|
68
|
+
* @param options - Optional settings (scan, hover, language, etc.)
|
|
69
|
+
* @returns XML string for Settings.xml
|
|
70
|
+
*/
|
|
71
|
+
function createSettingsXml(startGrid, options) {
|
|
72
|
+
const builder = new fast_xml_parser_1.XMLBuilder({
|
|
73
|
+
ignoreAttributes: false,
|
|
74
|
+
format: true,
|
|
75
|
+
indentBy: ' ',
|
|
76
|
+
});
|
|
77
|
+
const settingsData = {
|
|
78
|
+
GridSetSettings: {
|
|
79
|
+
'@_xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
|
80
|
+
StartGrid: startGrid,
|
|
81
|
+
ScanEnabled: options?.scanEnabled?.toString() ?? 'false',
|
|
82
|
+
ScanTimeoutMs: options?.scanTimeoutMs?.toString() ?? '2000',
|
|
83
|
+
HoverEnabled: options?.hoverEnabled?.toString() ?? 'false',
|
|
84
|
+
HoverTimeoutMs: options?.hoverTimeoutMs?.toString() ?? '1000',
|
|
85
|
+
MouseclickEnabled: options?.mouseclickEnabled?.toString() ?? 'true',
|
|
86
|
+
Language: options?.language ?? 'en-US',
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
return builder.build(settingsData);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create Grid3 FileMap.xml content
|
|
93
|
+
* @param grids - Array of grid configurations with name and path
|
|
94
|
+
* @returns XML string for FileMap.xml
|
|
95
|
+
*/
|
|
96
|
+
function createFileMapXml(grids) {
|
|
97
|
+
const builder = new fast_xml_parser_1.XMLBuilder({
|
|
98
|
+
ignoreAttributes: false,
|
|
99
|
+
format: true,
|
|
100
|
+
indentBy: ' ',
|
|
101
|
+
});
|
|
102
|
+
const entries = grids.map((grid) => ({
|
|
103
|
+
'@_StaticFile': grid.path,
|
|
104
|
+
...(grid.dynamicFiles && grid.dynamicFiles.length > 0
|
|
105
|
+
? { DynamicFiles: { File: grid.dynamicFiles } }
|
|
106
|
+
: {}),
|
|
107
|
+
}));
|
|
108
|
+
const fileMapData = {
|
|
109
|
+
FileMap: {
|
|
110
|
+
'@_xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
|
111
|
+
Entries: {
|
|
112
|
+
Entry: entries,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
return builder.build(fileMapData);
|
|
117
|
+
}
|
|
@@ -25,11 +25,10 @@ export declare const DEFAULT_GRID3_STYLES: Record<string, Grid3Style>;
|
|
|
25
25
|
*/
|
|
26
26
|
export declare const CATEGORY_STYLES: Record<string, Grid3Style>;
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
29
|
-
* @
|
|
30
|
-
* @returns Color with alpha channel in format #AARRGGBBFF
|
|
28
|
+
* Re-export ensureAlphaChannel from colorUtils for backward compatibility
|
|
29
|
+
* @deprecated Use ensureAlphaChannel from colorUtils instead
|
|
31
30
|
*/
|
|
32
|
-
export
|
|
31
|
+
export { ensureAlphaChannel } from './colorUtils';
|
|
33
32
|
/**
|
|
34
33
|
* Create a Grid3 style XML string with default and category styles
|
|
35
34
|
* @param includeCategories - Whether to include category-specific styles (default: true)
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
* style XML generation, and style conversion utilities.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.CATEGORY_STYLES = exports.DEFAULT_GRID3_STYLES = void 0;
|
|
10
|
-
exports.ensureAlphaChannel = ensureAlphaChannel;
|
|
9
|
+
exports.ensureAlphaChannel = exports.CATEGORY_STYLES = exports.DEFAULT_GRID3_STYLES = void 0;
|
|
11
10
|
exports.createDefaultStylesXml = createDefaultStylesXml;
|
|
12
11
|
exports.createCategoryStyle = createCategoryStyle;
|
|
13
12
|
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
13
|
+
const colorUtils_1 = require("./colorUtils");
|
|
14
14
|
/**
|
|
15
15
|
* Default Grid3 styles for common use cases
|
|
16
16
|
* Colors are in 8-digit ARGB hex format (#AARRGGBBFF)
|
|
@@ -119,29 +119,11 @@ exports.CATEGORY_STYLES = {
|
|
|
119
119
|
},
|
|
120
120
|
};
|
|
121
121
|
/**
|
|
122
|
-
*
|
|
123
|
-
* @
|
|
124
|
-
* @returns Color with alpha channel in format #AARRGGBBFF
|
|
122
|
+
* Re-export ensureAlphaChannel from colorUtils for backward compatibility
|
|
123
|
+
* @deprecated Use ensureAlphaChannel from colorUtils instead
|
|
125
124
|
*/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return '#FFFFFFFF';
|
|
129
|
-
// If already 8 digits (with alpha), return as is
|
|
130
|
-
if (color.match(/^#[0-9A-Fa-f]{8}$/))
|
|
131
|
-
return color;
|
|
132
|
-
// If 6 digits (no alpha), add FF for fully opaque
|
|
133
|
-
if (color.match(/^#[0-9A-Fa-f]{6}$/))
|
|
134
|
-
return color + 'FF';
|
|
135
|
-
// If 3 digits (shorthand), expand to 8
|
|
136
|
-
if (color.match(/^#[0-9A-Fa-f]{3}$/)) {
|
|
137
|
-
const r = color[1];
|
|
138
|
-
const g = color[2];
|
|
139
|
-
const b = color[3];
|
|
140
|
-
return `#${r}${r}${g}${g}${b}${b}FF`;
|
|
141
|
-
}
|
|
142
|
-
// Invalid or unknown format, return white
|
|
143
|
-
return '#FFFFFFFF';
|
|
144
|
-
}
|
|
125
|
+
var colorUtils_2 = require("./colorUtils");
|
|
126
|
+
Object.defineProperty(exports, "ensureAlphaChannel", { enumerable: true, get: function () { return colorUtils_2.ensureAlphaChannel; } });
|
|
145
127
|
/**
|
|
146
128
|
* Create a Grid3 style XML string with default and category styles
|
|
147
129
|
* @param includeCategories - Whether to include category-specific styles (default: true)
|
|
@@ -185,27 +167,11 @@ function createDefaultStylesXml(includeCategories = true) {
|
|
|
185
167
|
*/
|
|
186
168
|
function createCategoryStyle(categoryName, backgroundColor, fontColor = '#FFFFFFFF') {
|
|
187
169
|
return {
|
|
188
|
-
BackColour: ensureAlphaChannel(backgroundColor),
|
|
189
|
-
TileColour: ensureAlphaChannel(backgroundColor),
|
|
190
|
-
BorderColour: ensureAlphaChannel(darkenColor(backgroundColor, 30)),
|
|
191
|
-
FontColour: ensureAlphaChannel(fontColor),
|
|
170
|
+
BackColour: (0, colorUtils_1.ensureAlphaChannel)(backgroundColor),
|
|
171
|
+
TileColour: (0, colorUtils_1.ensureAlphaChannel)(backgroundColor),
|
|
172
|
+
BorderColour: (0, colorUtils_1.ensureAlphaChannel)((0, colorUtils_1.darkenColor)(backgroundColor, 30)),
|
|
173
|
+
FontColour: (0, colorUtils_1.ensureAlphaChannel)(fontColor),
|
|
192
174
|
FontName: 'Arial',
|
|
193
175
|
FontSize: '16',
|
|
194
176
|
};
|
|
195
177
|
}
|
|
196
|
-
/**
|
|
197
|
-
* Darken a hex color by a given amount
|
|
198
|
-
* @param hexColor - Hex color string
|
|
199
|
-
* @param amount - Amount to darken (0-255)
|
|
200
|
-
* @returns Darkened hex color
|
|
201
|
-
*/
|
|
202
|
-
function darkenColor(hexColor, amount) {
|
|
203
|
-
const normalized = ensureAlphaChannel(hexColor);
|
|
204
|
-
const hex = normalized.slice(1, 7); // Extract RGB part (skip # and alpha)
|
|
205
|
-
const num = parseInt(hex, 16);
|
|
206
|
-
const clamp = (value) => Math.max(0, Math.min(255, value));
|
|
207
|
-
const r = clamp(((num >> 16) & 0xff) - amount);
|
|
208
|
-
const g = clamp(((num >> 8) & 0xff) - amount);
|
|
209
|
-
const b = clamp((num & 0xff) - amount);
|
|
210
|
-
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
|
|
211
|
-
}
|
|
@@ -7,10 +7,12 @@ export { OpmlProcessor } from './opmlProcessor';
|
|
|
7
7
|
export { SnapProcessor } from './snapProcessor';
|
|
8
8
|
export { TouchChatProcessor } from './touchchatProcessor';
|
|
9
9
|
export { AstericsGridProcessor } from './astericsGridProcessor';
|
|
10
|
-
export { getPageTokenImageMap, getAllowedImageEntries, openImage } from './gridset/helpers';
|
|
11
|
-
export { getPageTokenImageMap as getGridsetPageTokenImageMap, getAllowedImageEntries as getGridsetAllowedImageEntries, openImage as openGridsetImage, } from './gridset/helpers';
|
|
10
|
+
export { getPageTokenImageMap, getAllowedImageEntries, openImage, generateGrid3Guid, createSettingsXml, createFileMapXml, } from './gridset/helpers';
|
|
11
|
+
export { getPageTokenImageMap as getGridsetPageTokenImageMap, getAllowedImageEntries as getGridsetAllowedImageEntries, openImage as openGridsetImage, generateGrid3Guid as generateGridsetGuid, createSettingsXml as createGridsetSettingsXml, createFileMapXml as createGridsetFileMapXml, } from './gridset/helpers';
|
|
12
12
|
export { resolveGrid3CellImage } from './gridset/resolver';
|
|
13
13
|
export { createWordlist, extractWordlists, updateWordlist, wordlistToXml, type WordList, type WordListItem, } from './gridset/wordlistHelpers';
|
|
14
|
-
export {
|
|
14
|
+
export { getNamedColor, rgbaToHex, channelToHex, clampColorChannel, clampAlpha, toHexColor, darkenColor, normalizeColor, ensureAlphaChannel, } from './gridset/colorUtils';
|
|
15
|
+
export { DEFAULT_GRID3_STYLES, CATEGORY_STYLES, createDefaultStylesXml, createCategoryStyle, } from './gridset/styleHelpers';
|
|
16
|
+
export { ensureAlphaChannel as ensureAlphaChannelFromStyles } from './gridset/styleHelpers';
|
|
15
17
|
export { getPageTokenImageMap as getSnapPageTokenImageMap, getAllowedImageEntries as getSnapAllowedImageEntries, openImage as openSnapImage, } from './snap/helpers';
|
|
16
18
|
export { getPageTokenImageMap as getTouchChatPageTokenImageMap, getAllowedImageEntries as getTouchChatAllowedImageEntries, openImage as openTouchChatImage, } from './touchchat/helpers';
|
package/dist/processors/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.openTouchChatImage = exports.getTouchChatAllowedImageEntries = exports.getTouchChatPageTokenImageMap = exports.openSnapImage = exports.getSnapAllowedImageEntries = exports.getSnapPageTokenImageMap = exports.createCategoryStyle = exports.createDefaultStylesXml = exports.ensureAlphaChannel = exports.
|
|
3
|
+
exports.openTouchChatImage = exports.getTouchChatAllowedImageEntries = exports.getTouchChatPageTokenImageMap = exports.openSnapImage = exports.getSnapAllowedImageEntries = exports.getSnapPageTokenImageMap = exports.ensureAlphaChannelFromStyles = exports.createCategoryStyle = exports.createDefaultStylesXml = exports.CATEGORY_STYLES = exports.DEFAULT_GRID3_STYLES = exports.ensureAlphaChannel = exports.normalizeColor = exports.darkenColor = exports.toHexColor = exports.clampAlpha = exports.clampColorChannel = exports.channelToHex = exports.rgbaToHex = exports.getNamedColor = exports.wordlistToXml = exports.updateWordlist = exports.extractWordlists = exports.createWordlist = exports.resolveGrid3CellImage = exports.createGridsetFileMapXml = exports.createGridsetSettingsXml = exports.generateGridsetGuid = exports.openGridsetImage = exports.getGridsetAllowedImageEntries = exports.getGridsetPageTokenImageMap = exports.createFileMapXml = exports.createSettingsXml = exports.generateGrid3Guid = exports.openImage = exports.getAllowedImageEntries = exports.getPageTokenImageMap = exports.AstericsGridProcessor = exports.TouchChatProcessor = exports.SnapProcessor = exports.OpmlProcessor = exports.ObfProcessor = exports.GridsetProcessor = exports.ExcelProcessor = exports.DotProcessor = exports.ApplePanelsProcessor = void 0;
|
|
4
4
|
var applePanelsProcessor_1 = require("./applePanelsProcessor");
|
|
5
5
|
Object.defineProperty(exports, "ApplePanelsProcessor", { enumerable: true, get: function () { return applePanelsProcessor_1.ApplePanelsProcessor; } });
|
|
6
6
|
var dotProcessor_1 = require("./dotProcessor");
|
|
@@ -24,10 +24,16 @@ var helpers_1 = require("./gridset/helpers");
|
|
|
24
24
|
Object.defineProperty(exports, "getPageTokenImageMap", { enumerable: true, get: function () { return helpers_1.getPageTokenImageMap; } });
|
|
25
25
|
Object.defineProperty(exports, "getAllowedImageEntries", { enumerable: true, get: function () { return helpers_1.getAllowedImageEntries; } });
|
|
26
26
|
Object.defineProperty(exports, "openImage", { enumerable: true, get: function () { return helpers_1.openImage; } });
|
|
27
|
+
Object.defineProperty(exports, "generateGrid3Guid", { enumerable: true, get: function () { return helpers_1.generateGrid3Guid; } });
|
|
28
|
+
Object.defineProperty(exports, "createSettingsXml", { enumerable: true, get: function () { return helpers_1.createSettingsXml; } });
|
|
29
|
+
Object.defineProperty(exports, "createFileMapXml", { enumerable: true, get: function () { return helpers_1.createFileMapXml; } });
|
|
27
30
|
var helpers_2 = require("./gridset/helpers");
|
|
28
31
|
Object.defineProperty(exports, "getGridsetPageTokenImageMap", { enumerable: true, get: function () { return helpers_2.getPageTokenImageMap; } });
|
|
29
32
|
Object.defineProperty(exports, "getGridsetAllowedImageEntries", { enumerable: true, get: function () { return helpers_2.getAllowedImageEntries; } });
|
|
30
33
|
Object.defineProperty(exports, "openGridsetImage", { enumerable: true, get: function () { return helpers_2.openImage; } });
|
|
34
|
+
Object.defineProperty(exports, "generateGridsetGuid", { enumerable: true, get: function () { return helpers_2.generateGrid3Guid; } });
|
|
35
|
+
Object.defineProperty(exports, "createGridsetSettingsXml", { enumerable: true, get: function () { return helpers_2.createSettingsXml; } });
|
|
36
|
+
Object.defineProperty(exports, "createGridsetFileMapXml", { enumerable: true, get: function () { return helpers_2.createFileMapXml; } });
|
|
31
37
|
var resolver_1 = require("./gridset/resolver");
|
|
32
38
|
Object.defineProperty(exports, "resolveGrid3CellImage", { enumerable: true, get: function () { return resolver_1.resolveGrid3CellImage; } });
|
|
33
39
|
// Gridset (Grid 3) wordlist helpers
|
|
@@ -36,13 +42,26 @@ Object.defineProperty(exports, "createWordlist", { enumerable: true, get: functi
|
|
|
36
42
|
Object.defineProperty(exports, "extractWordlists", { enumerable: true, get: function () { return wordlistHelpers_1.extractWordlists; } });
|
|
37
43
|
Object.defineProperty(exports, "updateWordlist", { enumerable: true, get: function () { return wordlistHelpers_1.updateWordlist; } });
|
|
38
44
|
Object.defineProperty(exports, "wordlistToXml", { enumerable: true, get: function () { return wordlistHelpers_1.wordlistToXml; } });
|
|
45
|
+
// Gridset (Grid 3) color utilities
|
|
46
|
+
var colorUtils_1 = require("./gridset/colorUtils");
|
|
47
|
+
Object.defineProperty(exports, "getNamedColor", { enumerable: true, get: function () { return colorUtils_1.getNamedColor; } });
|
|
48
|
+
Object.defineProperty(exports, "rgbaToHex", { enumerable: true, get: function () { return colorUtils_1.rgbaToHex; } });
|
|
49
|
+
Object.defineProperty(exports, "channelToHex", { enumerable: true, get: function () { return colorUtils_1.channelToHex; } });
|
|
50
|
+
Object.defineProperty(exports, "clampColorChannel", { enumerable: true, get: function () { return colorUtils_1.clampColorChannel; } });
|
|
51
|
+
Object.defineProperty(exports, "clampAlpha", { enumerable: true, get: function () { return colorUtils_1.clampAlpha; } });
|
|
52
|
+
Object.defineProperty(exports, "toHexColor", { enumerable: true, get: function () { return colorUtils_1.toHexColor; } });
|
|
53
|
+
Object.defineProperty(exports, "darkenColor", { enumerable: true, get: function () { return colorUtils_1.darkenColor; } });
|
|
54
|
+
Object.defineProperty(exports, "normalizeColor", { enumerable: true, get: function () { return colorUtils_1.normalizeColor; } });
|
|
55
|
+
Object.defineProperty(exports, "ensureAlphaChannel", { enumerable: true, get: function () { return colorUtils_1.ensureAlphaChannel; } });
|
|
39
56
|
// Gridset (Grid 3) style helpers
|
|
40
57
|
var styleHelpers_1 = require("./gridset/styleHelpers");
|
|
41
58
|
Object.defineProperty(exports, "DEFAULT_GRID3_STYLES", { enumerable: true, get: function () { return styleHelpers_1.DEFAULT_GRID3_STYLES; } });
|
|
42
59
|
Object.defineProperty(exports, "CATEGORY_STYLES", { enumerable: true, get: function () { return styleHelpers_1.CATEGORY_STYLES; } });
|
|
43
|
-
Object.defineProperty(exports, "ensureAlphaChannel", { enumerable: true, get: function () { return styleHelpers_1.ensureAlphaChannel; } });
|
|
44
60
|
Object.defineProperty(exports, "createDefaultStylesXml", { enumerable: true, get: function () { return styleHelpers_1.createDefaultStylesXml; } });
|
|
45
61
|
Object.defineProperty(exports, "createCategoryStyle", { enumerable: true, get: function () { return styleHelpers_1.createCategoryStyle; } });
|
|
62
|
+
// Re-export ensureAlphaChannel from styleHelpers for backward compatibility
|
|
63
|
+
var styleHelpers_2 = require("./gridset/styleHelpers");
|
|
64
|
+
Object.defineProperty(exports, "ensureAlphaChannelFromStyles", { enumerable: true, get: function () { return styleHelpers_2.ensureAlphaChannel; } });
|
|
46
65
|
// Snap helpers (stubs)
|
|
47
66
|
var helpers_3 = require("./snap/helpers");
|
|
48
67
|
Object.defineProperty(exports, "getSnapPageTokenImageMap", { enumerable: true, get: function () { return helpers_3.getPageTokenImageMap; } });
|
|
@@ -144,12 +144,15 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
144
144
|
}
|
|
145
145
|
const obj = JSON.parse(str);
|
|
146
146
|
if (obj && typeof obj === 'object' && 'id' in obj && 'buttons' in obj) {
|
|
147
|
+
// Validate buttons is an array
|
|
148
|
+
if (!Array.isArray(obj.buttons)) {
|
|
149
|
+
throw new Error('Invalid OBF: buttons must be an array');
|
|
150
|
+
}
|
|
147
151
|
return obj;
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
154
|
catch (error) {
|
|
151
155
|
// Log parsing errors for debugging but don't throw
|
|
152
|
-
console.warn(`Failed to parse OBF JSON: ${error.message}`);
|
|
153
156
|
}
|
|
154
157
|
return null;
|
|
155
158
|
}
|
|
@@ -476,11 +476,33 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
476
476
|
serializedMetadata = audio.metadata || null;
|
|
477
477
|
useMessageRecording = 1;
|
|
478
478
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
479
|
+
// Retry logic for SQLite operations
|
|
480
|
+
let retries = 3;
|
|
481
|
+
while (retries > 0) {
|
|
482
|
+
try {
|
|
483
|
+
insertButton.run(buttonIdCounter++, button.label || '', button.message || button.label || '', navigatePageId, elementRefId, null, null, messageRecordingId, serializedMetadata, useMessageRecording, button.style?.fontColor
|
|
484
|
+
? parseInt(button.style.fontColor.replace('#', ''), 16)
|
|
485
|
+
: null, button.style?.backgroundColor
|
|
486
|
+
? parseInt(button.style.backgroundColor.replace('#', ''), 16)
|
|
487
|
+
: null, button.style?.borderColor
|
|
488
|
+
? parseInt(button.style.borderColor.replace('#', ''), 16)
|
|
489
|
+
: null, button.style?.borderWidth, button.style?.fontSize, button.style?.fontFamily, button.style?.fontStyle ? parseInt(button.style.fontStyle) : null);
|
|
490
|
+
break; // Success
|
|
491
|
+
}
|
|
492
|
+
catch (err) {
|
|
493
|
+
if (err.code === 'SQLITE_IOERR' && retries > 1) {
|
|
494
|
+
retries--;
|
|
495
|
+
// Wait a bit before retrying
|
|
496
|
+
const now = Date.now();
|
|
497
|
+
while (Date.now() - now < 100) {
|
|
498
|
+
/* busy wait */
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
throw err;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
484
506
|
// Insert ElementPlacement
|
|
485
507
|
const insertPlacement = db.prepare('INSERT INTO ElementPlacement (Id, ElementReferenceId, GridPosition) VALUES (?, ?, ?)');
|
|
486
508
|
insertPlacement.run(placementIdCounter++, elementRefId, gridPosition);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@willwade/aac-processors",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "A comprehensive TypeScript library for processing AAC (Augmentative and Alternative Communication) file formats with translation support",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|