@willwade/aac-processors 0.0.6 → 0.0.8
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 +2 -40
- package/dist/analytics/history.d.ts +57 -0
- package/dist/analytics/history.js +72 -0
- package/dist/core/analyze.d.ts +10 -0
- package/dist/core/analyze.js +10 -0
- package/dist/core/stringCasing.d.ts +11 -0
- package/dist/core/stringCasing.js +11 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- 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 +125 -0
- package/dist/processors/gridset/helpers.js +354 -0
- package/dist/processors/gridset/styleHelpers.d.ts +3 -4
- package/dist/processors/gridset/styleHelpers.js +10 -44
- package/dist/processors/index.d.ts +6 -4
- package/dist/processors/index.js +51 -3
- package/dist/processors/obfProcessor.js +10 -2
- package/dist/processors/snap/helpers.d.ts +85 -0
- package/dist/processors/snap/helpers.js +259 -2
- package/dist/processors/snapProcessor.js +27 -5
- package/dist/processors/touchchat/helpers.d.ts +12 -0
- package/dist/processors/touchchat/helpers.js +12 -2
- package/dist/utils/dotnetTicks.d.ts +13 -0
- package/dist/utils/dotnetTicks.js +21 -0
- package/package.json +8 -6
- package/docs/.keep +0 -1
- package/docs/ApplePanels.md +0 -309
- package/docs/Grid3-Styling-Guide.md +0 -287
- package/docs/Grid3-XML-Format.md +0 -1788
- package/docs/TobiiDynavox-Snap-Details.md +0 -394
- package/docs/asterics-Grid-fileformat-details.md +0 -443
- package/docs/obf_.obz Open Board File Formats.md +0 -432
- package/docs/touchchat.md +0 -520
package/README.md
CHANGED
|
@@ -404,8 +404,8 @@ processor.saveFromTree(tree, "styled-board.spb");
|
|
|
404
404
|
| **Grid3** | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Style references |
|
|
405
405
|
| **Asterics Grid** | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Metadata-based |
|
|
406
406
|
| **Apple Panels** | ✅ Yes | ✅ Size only | ❌ No | ✅ Display weight |
|
|
407
|
-
| **Dot** |
|
|
408
|
-
| **OPML** |
|
|
407
|
+
| **Dot** | ❌No | ❌ Yes | ❌ No | ❌ Basic only |
|
|
408
|
+
| **OPML** | ❌No | ❌ Yes | ❌ No | ❌ Basic only |
|
|
409
409
|
| **Excel** | ✅ Yes | ✅ Size only | ❌ No | ✅ Display weight |
|
|
410
410
|
|
|
411
411
|
#### Cross-Format Styling Conversion
|
|
@@ -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,16 +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
|
-
|
|
728
713
|
### Medium Priority
|
|
729
714
|
|
|
730
715
|
- [ ] **Performance optimization** - Optimize memory usage for very large communication boards (1000+ buttons)
|
|
@@ -749,29 +734,6 @@ Inspired by the Python AACProcessors project
|
|
|
749
734
|
- [ ] **CI/CD improvements** - Add automated releases and npm publishing
|
|
750
735
|
- [ ] **Documentation improvements** - Add more real-world examples and tutorials
|
|
751
736
|
|
|
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
737
|
## More enhancements
|
|
776
738
|
|
|
777
739
|
- Much more effort put into fixing the layout issues. Grid sizes are not reliably and X, Y positions too. Particularly in the Grid3
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { dotNetTicksToDate } from '../utils/dotnetTicks';
|
|
2
|
+
import { Grid3UserPath } from '../processors/gridset/helpers';
|
|
3
|
+
import { SnapUserInfo } from '../processors/snap/helpers';
|
|
4
|
+
export type HistorySource = 'Grid' | 'Snap';
|
|
5
|
+
export interface HistoryOccurrence {
|
|
6
|
+
timestamp: Date;
|
|
7
|
+
latitude?: number | null;
|
|
8
|
+
longitude?: number | null;
|
|
9
|
+
modeling?: boolean;
|
|
10
|
+
accessMethod?: number | null;
|
|
11
|
+
pageId?: string | null;
|
|
12
|
+
}
|
|
13
|
+
export interface HistoryPlatformExtras {
|
|
14
|
+
label?: string;
|
|
15
|
+
message?: string;
|
|
16
|
+
buttonId?: string;
|
|
17
|
+
contentXml?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface HistoryEntry {
|
|
20
|
+
id: string;
|
|
21
|
+
source: HistorySource;
|
|
22
|
+
content: string;
|
|
23
|
+
occurrences: HistoryOccurrence[];
|
|
24
|
+
raw?: unknown;
|
|
25
|
+
platform?: HistoryPlatformExtras;
|
|
26
|
+
}
|
|
27
|
+
export { dotNetTicksToDate };
|
|
28
|
+
/**
|
|
29
|
+
* Read Grid 3 phrase history from a history.sqlite database and tag entries with their source.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readGrid3History(historyDbPath: string): HistoryEntry[];
|
|
32
|
+
/**
|
|
33
|
+
* Read Grid 3 history for a specific user/language combination.
|
|
34
|
+
*/
|
|
35
|
+
export declare function readGrid3HistoryForUser(userName: string, langCode?: string): HistoryEntry[];
|
|
36
|
+
/**
|
|
37
|
+
* Read every available Grid 3 history database on the machine.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readAllGrid3History(): HistoryEntry[];
|
|
40
|
+
/**
|
|
41
|
+
* Read Snap button usage from a pageset database and tag entries with source.
|
|
42
|
+
*/
|
|
43
|
+
export declare function readSnapUsage(pagesetPath: string): HistoryEntry[];
|
|
44
|
+
/**
|
|
45
|
+
* Read Snap usage for a specific user across all discovered pagesets.
|
|
46
|
+
*/
|
|
47
|
+
export declare function readSnapUsageForUser(userId?: string, packageNamePattern?: string): HistoryEntry[];
|
|
48
|
+
export declare function listSnapUsers(): SnapUserInfo[];
|
|
49
|
+
/**
|
|
50
|
+
* List Grid 3 users on the current machine.
|
|
51
|
+
*/
|
|
52
|
+
export declare function listGrid3Users(): Grid3UserPath[];
|
|
53
|
+
/**
|
|
54
|
+
* Convenience helper to gather all available history across Grid 3 and Snap.
|
|
55
|
+
* Returns an empty array if no history files are present.
|
|
56
|
+
*/
|
|
57
|
+
export declare function collectUnifiedHistory(): HistoryEntry[];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dotNetTicksToDate = void 0;
|
|
4
|
+
exports.readGrid3History = readGrid3History;
|
|
5
|
+
exports.readGrid3HistoryForUser = readGrid3HistoryForUser;
|
|
6
|
+
exports.readAllGrid3History = readAllGrid3History;
|
|
7
|
+
exports.readSnapUsage = readSnapUsage;
|
|
8
|
+
exports.readSnapUsageForUser = readSnapUsageForUser;
|
|
9
|
+
exports.listSnapUsers = listSnapUsers;
|
|
10
|
+
exports.listGrid3Users = listGrid3Users;
|
|
11
|
+
exports.collectUnifiedHistory = collectUnifiedHistory;
|
|
12
|
+
const dotnetTicks_1 = require("../utils/dotnetTicks");
|
|
13
|
+
Object.defineProperty(exports, "dotNetTicksToDate", { enumerable: true, get: function () { return dotnetTicks_1.dotNetTicksToDate; } });
|
|
14
|
+
const helpers_1 = require("../processors/gridset/helpers");
|
|
15
|
+
const helpers_2 = require("../processors/snap/helpers");
|
|
16
|
+
/**
|
|
17
|
+
* Read Grid 3 phrase history from a history.sqlite database and tag entries with their source.
|
|
18
|
+
*/
|
|
19
|
+
function readGrid3History(historyDbPath) {
|
|
20
|
+
return (0, helpers_1.readGrid3History)(historyDbPath).map((e) => ({
|
|
21
|
+
...e,
|
|
22
|
+
source: 'Grid',
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Read Grid 3 history for a specific user/language combination.
|
|
27
|
+
*/
|
|
28
|
+
function readGrid3HistoryForUser(userName, langCode) {
|
|
29
|
+
return (0, helpers_1.readGrid3HistoryForUser)(userName, langCode).map((e) => ({
|
|
30
|
+
...e,
|
|
31
|
+
source: 'Grid',
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Read every available Grid 3 history database on the machine.
|
|
36
|
+
*/
|
|
37
|
+
function readAllGrid3History() {
|
|
38
|
+
return (0, helpers_1.readAllGrid3History)().map((e) => ({ ...e, source: 'Grid' }));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Read Snap button usage from a pageset database and tag entries with source.
|
|
42
|
+
*/
|
|
43
|
+
function readSnapUsage(pagesetPath) {
|
|
44
|
+
return (0, helpers_2.readSnapUsage)(pagesetPath).map((e) => ({ ...e, source: 'Snap' }));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Read Snap usage for a specific user across all discovered pagesets.
|
|
48
|
+
*/
|
|
49
|
+
function readSnapUsageForUser(userId, packageNamePattern = 'TobiiDynavox') {
|
|
50
|
+
return (0, helpers_2.readSnapUsageForUser)(userId, packageNamePattern).map((e) => ({
|
|
51
|
+
...e,
|
|
52
|
+
source: 'Snap',
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
function listSnapUsers() {
|
|
56
|
+
return (0, helpers_2.findSnapUsers)();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* List Grid 3 users on the current machine.
|
|
60
|
+
*/
|
|
61
|
+
function listGrid3Users() {
|
|
62
|
+
return (0, helpers_1.findGrid3Users)();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Convenience helper to gather all available history across Grid 3 and Snap.
|
|
66
|
+
* Returns an empty array if no history files are present.
|
|
67
|
+
*/
|
|
68
|
+
function collectUnifiedHistory() {
|
|
69
|
+
const gridHistory = readAllGrid3History();
|
|
70
|
+
const snapHistory = (0, helpers_2.findSnapUsers)().flatMap((u) => readSnapUsageForUser(u.userId));
|
|
71
|
+
return [...gridHistory, ...snapHistory];
|
|
72
|
+
}
|
package/dist/core/analyze.d.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { AACTree } from './treeStructure';
|
|
2
2
|
import { BaseProcessor, ProcessorOptions } from './baseProcessor';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a processor instance by friendly format name or common extension.
|
|
5
|
+
* @param format Format key or extension (e.g., 'snap', 'obf', 'xlsx')
|
|
6
|
+
* @param options Optional processor configuration
|
|
7
|
+
*/
|
|
3
8
|
export declare function getProcessor(format: string, options?: ProcessorOptions): BaseProcessor;
|
|
9
|
+
/**
|
|
10
|
+
* Convenience helper to load a file into an AACTree using the inferred processor.
|
|
11
|
+
* @param file Path to the source file
|
|
12
|
+
* @param format Format key or extension (passed to getProcessor)
|
|
13
|
+
*/
|
|
4
14
|
export declare function analyze(file: string, format: string): {
|
|
5
15
|
tree: AACTree;
|
|
6
16
|
};
|
package/dist/core/analyze.js
CHANGED
|
@@ -11,6 +11,11 @@ const snapProcessor_1 = require("../processors/snapProcessor");
|
|
|
11
11
|
const dotProcessor_1 = require("../processors/dotProcessor");
|
|
12
12
|
const excelProcessor_1 = require("../processors/excelProcessor");
|
|
13
13
|
const applePanelsProcessor_1 = require("../processors/applePanelsProcessor");
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a processor instance by friendly format name or common extension.
|
|
16
|
+
* @param format Format key or extension (e.g., 'snap', 'obf', 'xlsx')
|
|
17
|
+
* @param options Optional processor configuration
|
|
18
|
+
*/
|
|
14
19
|
function getProcessor(format, options) {
|
|
15
20
|
const normalizedFormat = (format || '').toLowerCase();
|
|
16
21
|
switch (normalizedFormat) {
|
|
@@ -42,6 +47,11 @@ function getProcessor(format, options) {
|
|
|
42
47
|
throw new Error('Unknown format: ' + format);
|
|
43
48
|
}
|
|
44
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Convenience helper to load a file into an AACTree using the inferred processor.
|
|
52
|
+
* @param file Path to the source file
|
|
53
|
+
* @param format Format key or extension (passed to getProcessor)
|
|
54
|
+
*/
|
|
45
55
|
function analyze(file, format) {
|
|
46
56
|
const processor = getProcessor(format);
|
|
47
57
|
const tree = processor.loadIntoTree(file);
|
|
@@ -20,6 +20,9 @@ export declare enum StringCasing {
|
|
|
20
20
|
* @param text - The text to analyze for casing pattern
|
|
21
21
|
* @returns StringCasing enum value representing the detected casing
|
|
22
22
|
*/
|
|
23
|
+
/**
|
|
24
|
+
* Infer the dominant casing style of a string (camel, pascal, snake, kebab, title, sentence, upper, lower).
|
|
25
|
+
*/
|
|
23
26
|
export declare function detectCasing(text: string): StringCasing;
|
|
24
27
|
/**
|
|
25
28
|
* Converts text to the specified casing
|
|
@@ -27,6 +30,11 @@ export declare function detectCasing(text: string): StringCasing;
|
|
|
27
30
|
* @param targetCasing - The desired casing format
|
|
28
31
|
* @returns The text converted to the target casing
|
|
29
32
|
*/
|
|
33
|
+
/**
|
|
34
|
+
* Convert a string into the requested casing style.
|
|
35
|
+
* @param text Input string
|
|
36
|
+
* @param targetCasing Desired casing variant
|
|
37
|
+
*/
|
|
30
38
|
export declare function convertCasing(text: string, targetCasing: StringCasing): string;
|
|
31
39
|
/**
|
|
32
40
|
* Utility function to check if text is primarily numeric or empty
|
|
@@ -34,4 +42,7 @@ export declare function convertCasing(text: string, targetCasing: StringCasing):
|
|
|
34
42
|
* @param text - The text to check
|
|
35
43
|
* @returns True if the text should be considered non-meaningful
|
|
36
44
|
*/
|
|
45
|
+
/**
|
|
46
|
+
* Check whether a string is empty or represents a numeric value.
|
|
47
|
+
*/
|
|
37
48
|
export declare function isNumericOrEmpty(text: string): boolean;
|
|
@@ -27,6 +27,9 @@ var StringCasing;
|
|
|
27
27
|
* @param text - The text to analyze for casing pattern
|
|
28
28
|
* @returns StringCasing enum value representing the detected casing
|
|
29
29
|
*/
|
|
30
|
+
/**
|
|
31
|
+
* Infer the dominant casing style of a string (camel, pascal, snake, kebab, title, sentence, upper, lower).
|
|
32
|
+
*/
|
|
30
33
|
function detectCasing(text) {
|
|
31
34
|
if (!text || text.length === 0)
|
|
32
35
|
return StringCasing.LOWER;
|
|
@@ -102,6 +105,11 @@ function detectCasing(text) {
|
|
|
102
105
|
* @param targetCasing - The desired casing format
|
|
103
106
|
* @returns The text converted to the target casing
|
|
104
107
|
*/
|
|
108
|
+
/**
|
|
109
|
+
* Convert a string into the requested casing style.
|
|
110
|
+
* @param text Input string
|
|
111
|
+
* @param targetCasing Desired casing variant
|
|
112
|
+
*/
|
|
105
113
|
function convertCasing(text, targetCasing) {
|
|
106
114
|
if (!text || text.length === 0)
|
|
107
115
|
return text;
|
|
@@ -164,6 +172,9 @@ function convertCasing(text, targetCasing) {
|
|
|
164
172
|
* @param text - The text to check
|
|
165
173
|
* @returns True if the text should be considered non-meaningful
|
|
166
174
|
*/
|
|
175
|
+
/**
|
|
176
|
+
* Check whether a string is empty or represents a numeric value.
|
|
177
|
+
*/
|
|
167
178
|
function isNumericOrEmpty(text) {
|
|
168
179
|
const trimmed = text.trim();
|
|
169
180
|
if (trimmed.length <= 1)
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './core/treeStructure';
|
|
|
2
2
|
export * from './core/baseProcessor';
|
|
3
3
|
export * from './core/stringCasing';
|
|
4
4
|
export * from './processors';
|
|
5
|
+
export { collectUnifiedHistory, listGrid3Users as listHistoryGrid3Users, listSnapUsers as listHistorySnapUsers, } from './analytics/history';
|
|
5
6
|
import { BaseProcessor } from './core/baseProcessor';
|
|
6
7
|
/**
|
|
7
8
|
* Factory function to get the appropriate processor for a file extension
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.listHistorySnapUsers = exports.listHistoryGrid3Users = exports.collectUnifiedHistory = void 0;
|
|
17
18
|
exports.getProcessor = getProcessor;
|
|
18
19
|
exports.getSupportedExtensions = getSupportedExtensions;
|
|
19
20
|
exports.isExtensionSupported = isExtensionSupported;
|
|
@@ -22,6 +23,10 @@ __exportStar(require("./core/treeStructure"), exports);
|
|
|
22
23
|
__exportStar(require("./core/baseProcessor"), exports);
|
|
23
24
|
__exportStar(require("./core/stringCasing"), exports);
|
|
24
25
|
__exportStar(require("./processors"), exports);
|
|
26
|
+
var history_1 = require("./analytics/history");
|
|
27
|
+
Object.defineProperty(exports, "collectUnifiedHistory", { enumerable: true, get: function () { return history_1.collectUnifiedHistory; } });
|
|
28
|
+
Object.defineProperty(exports, "listHistoryGrid3Users", { enumerable: true, get: function () { return history_1.listGrid3Users; } });
|
|
29
|
+
Object.defineProperty(exports, "listHistorySnapUsers", { enumerable: true, get: function () { return history_1.listSnapUsers; } });
|
|
25
30
|
const dotProcessor_1 = require("./processors/dotProcessor");
|
|
26
31
|
const excelProcessor_1 = require("./processors/excelProcessor");
|
|
27
32
|
const opmlProcessor_1 = require("./processors/opmlProcessor");
|
|
@@ -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;
|