@willwade/aac-processors 0.0.21 → 0.0.23
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 +19 -27
- package/dist/core/treeStructure.d.ts +2 -2
- package/dist/core/treeStructure.js +4 -1
- package/dist/processors/applePanelsProcessor.js +166 -123
- package/dist/processors/astericsGridProcessor.js +121 -105
- package/dist/processors/dotProcessor.js +83 -65
- package/dist/processors/gridsetProcessor.js +2 -0
- package/dist/processors/obfProcessor.js +11 -4
- package/dist/processors/opmlProcessor.js +82 -44
- package/dist/processors/snapProcessor.js +19 -9
- package/dist/processors/touchchatProcessor.js +72 -21
- package/dist/utilities/analytics/metrics/core.d.ts +1 -1
- package/dist/utilities/analytics/metrics/core.js +191 -212
- package/dist/validation/applePanelsValidator.d.ts +10 -0
- package/dist/validation/applePanelsValidator.js +124 -0
- package/dist/validation/astericsValidator.d.ts +16 -0
- package/dist/validation/astericsValidator.js +115 -0
- package/dist/validation/dotValidator.d.ts +10 -0
- package/dist/validation/dotValidator.js +113 -0
- package/dist/validation/excelValidator.d.ts +10 -0
- package/dist/validation/excelValidator.js +89 -0
- package/dist/validation/index.d.ts +14 -1
- package/dist/validation/index.js +104 -1
- package/dist/validation/obfsetValidator.d.ts +10 -0
- package/dist/validation/obfsetValidator.js +103 -0
- package/dist/validation/opmlValidator.d.ts +10 -0
- package/dist/validation/opmlValidator.js +107 -0
- package/dist/validation/validationTypes.d.ts +22 -0
- package/dist/validation/validationTypes.js +38 -1
- package/dist/validation.d.ts +8 -2
- package/dist/validation.js +16 -1
- package/package.json +1 -1
|
@@ -104,7 +104,8 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
104
104
|
// Set toolbarId if there's a global toolbar
|
|
105
105
|
if (hasGlobalToolbar) {
|
|
106
106
|
tree.toolbarId = toolbarId || null;
|
|
107
|
-
|
|
107
|
+
// Use defaultHomePageId as root (the content pageset), not the toolbar
|
|
108
|
+
tree.rootId = defaultHomePageId || null;
|
|
108
109
|
}
|
|
109
110
|
else if (defaultHomePageId) {
|
|
110
111
|
tree.rootId = defaultHomePageId;
|
|
@@ -114,14 +115,7 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
114
115
|
catch (e) {
|
|
115
116
|
console.warn('[SnapProcessor] Failed to load PageSetProperties:', e);
|
|
116
117
|
}
|
|
117
|
-
// If still no root,
|
|
118
|
-
if (!tree.rootId || tree.rootId === defaultHomePageId) {
|
|
119
|
-
const toolbarPage = pages.find((p) => p.Title === 'Tool Bar' || p.Name === 'Tool Bar');
|
|
120
|
-
if (toolbarPage) {
|
|
121
|
-
tree.rootId = String(toolbarPage.UniqueId || toolbarPage.Id);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
// If still no root, fallback to first page
|
|
118
|
+
// If still no root, fallback to first page (but don't override a valid defaultHomePageId)
|
|
125
119
|
if (!tree.rootId && pages.length > 0) {
|
|
126
120
|
tree.rootId = String(pages[0].UniqueId || pages[0].Id);
|
|
127
121
|
}
|
|
@@ -144,6 +138,22 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
144
138
|
});
|
|
145
139
|
tree.addPage(page);
|
|
146
140
|
});
|
|
141
|
+
// Try to find toolbar page even if not set in PageSetProperties
|
|
142
|
+
// Some SNAP files have a toolbar page but don't set ToolBarUniqueId
|
|
143
|
+
// This must be done AFTER pages are added to the tree
|
|
144
|
+
if (!tree.toolbarId || tree.toolbarId === '00000000-0000-0000-0000-000000000000') {
|
|
145
|
+
const toolbarPage = Object.values(tree.pages).find((p) => {
|
|
146
|
+
const name = (p.name || '').toLowerCase();
|
|
147
|
+
return name === 'tool bar' || name === 'toolbar';
|
|
148
|
+
});
|
|
149
|
+
if (toolbarPage) {
|
|
150
|
+
tree.toolbarId = toolbarPage.id;
|
|
151
|
+
// Update metadata to reflect toolbar detection
|
|
152
|
+
if (tree.metadata) {
|
|
153
|
+
tree.metadata.hasGlobalToolbar = true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
147
157
|
const scanGroupsByPageLayout = new Map();
|
|
148
158
|
try {
|
|
149
159
|
const scanGroupRows = db
|
|
@@ -159,7 +159,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
159
159
|
});
|
|
160
160
|
// Load button boxes and their cells
|
|
161
161
|
const buttonBoxQuery = `
|
|
162
|
-
SELECT bbc.*, b.*, bb.id as box_id
|
|
162
|
+
SELECT bbc.*, b.*, bb.id as box_id, bb.layout_x, bb.layout_y
|
|
163
163
|
FROM button_box_cells bbc
|
|
164
164
|
JOIN buttons b ON b.resource_id = bbc.resource_id
|
|
165
165
|
JOIN button_boxes bb ON bb.id = bbc.button_box_id
|
|
@@ -168,8 +168,14 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
168
168
|
const buttonBoxCells = db.prepare(buttonBoxQuery).all();
|
|
169
169
|
const buttonBoxes = new Map();
|
|
170
170
|
buttonBoxCells.forEach((cell) => {
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
let boxData = buttonBoxes.get(cell.box_id);
|
|
172
|
+
if (!boxData) {
|
|
173
|
+
boxData = {
|
|
174
|
+
layoutX: cell.layout_x || 10,
|
|
175
|
+
layoutY: cell.layout_y || 6,
|
|
176
|
+
buttons: [],
|
|
177
|
+
};
|
|
178
|
+
buttonBoxes.set(cell.box_id, boxData);
|
|
173
179
|
}
|
|
174
180
|
const style = buttonStyles.get(cell.button_style_id);
|
|
175
181
|
// Create semantic action for TouchChat button
|
|
@@ -213,7 +219,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
213
219
|
labelOnTop: toBooleanOrUndefined(style?.label_on_top),
|
|
214
220
|
},
|
|
215
221
|
});
|
|
216
|
-
|
|
222
|
+
boxData.buttons.push({
|
|
217
223
|
button,
|
|
218
224
|
location: cell.location || 0,
|
|
219
225
|
spanX: cell.span_x || 1,
|
|
@@ -228,8 +234,8 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
228
234
|
// Use mapped string ID if available, otherwise use numeric ID as string
|
|
229
235
|
const pageId = numericToRid.get(instance.page_id) || String(instance.page_id);
|
|
230
236
|
const page = tree.getPage(pageId);
|
|
231
|
-
const
|
|
232
|
-
if (page &&
|
|
237
|
+
const boxData = buttonBoxes.get(instance.button_box_id);
|
|
238
|
+
if (page && boxData) {
|
|
233
239
|
// Initialize page grid if not exists (assume max 10x10 grid)
|
|
234
240
|
if (!pageGrids.has(pageId)) {
|
|
235
241
|
const grid = [];
|
|
@@ -243,15 +249,13 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
243
249
|
return;
|
|
244
250
|
const boxX = Number(instance.position_x) || 0;
|
|
245
251
|
const boxY = Number(instance.position_y) || 0;
|
|
246
|
-
const boxWidth =
|
|
252
|
+
const boxWidth = boxData.layoutX; // Use layout_x from button_boxes, not size_x from instance
|
|
247
253
|
// boxHeight not currently used but kept for future span calculations
|
|
248
|
-
// const boxHeight =
|
|
249
|
-
buttons.forEach(({ button, location, spanX, spanY }) => {
|
|
254
|
+
// const boxHeight = boxData.layoutY;
|
|
255
|
+
boxData.buttons.forEach(({ button, location, spanX, spanY }) => {
|
|
250
256
|
const safeLocation = Number(location) || 0;
|
|
251
257
|
const safeSpanX = Number(spanX) || 1;
|
|
252
258
|
const safeSpanY = Number(spanY) || 1;
|
|
253
|
-
// Add button to page
|
|
254
|
-
page.addButton(button);
|
|
255
259
|
// Calculate button position within the button box
|
|
256
260
|
// location is a linear index, convert to grid coordinates
|
|
257
261
|
const buttonX = safeLocation % boxWidth;
|
|
@@ -259,6 +263,11 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
259
263
|
// Calculate absolute position on page
|
|
260
264
|
const absoluteX = boxX + buttonX;
|
|
261
265
|
const absoluteY = boxY + buttonY;
|
|
266
|
+
// Set button's x and y coordinates
|
|
267
|
+
button.x = absoluteX;
|
|
268
|
+
button.y = absoluteY;
|
|
269
|
+
// Add button to page
|
|
270
|
+
page.addButton(button);
|
|
262
271
|
// Place button in grid (handle span)
|
|
263
272
|
for (let r = absoluteY; r < absoluteY + safeSpanY && r < 10; r++) {
|
|
264
273
|
for (let c = absoluteX; c < absoluteX + safeSpanX && c < 10; c++) {
|
|
@@ -412,21 +421,49 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
412
421
|
catch (e) {
|
|
413
422
|
// console.log('No navigation actions found:', e);
|
|
414
423
|
}
|
|
415
|
-
// Try to load root ID from
|
|
424
|
+
// Try to load root ID from multiple sources in order of priority
|
|
416
425
|
try {
|
|
417
|
-
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
426
|
+
// First, try to get HOME page from special_pages table (TouchChat specific)
|
|
427
|
+
const specialPagesQuery = "SELECT page_id FROM special_pages WHERE name = 'HOME'";
|
|
428
|
+
const homePageRow = db.prepare(specialPagesQuery).get();
|
|
429
|
+
if (homePageRow) {
|
|
430
|
+
// The page_id is the page's id (not resource_id), need to get the RID
|
|
431
|
+
const homePageIdQuery = `
|
|
432
|
+
SELECT p.id, r.rid
|
|
433
|
+
FROM pages p
|
|
434
|
+
JOIN resources r ON r.id = p.resource_id
|
|
435
|
+
WHERE p.id = ?
|
|
436
|
+
LIMIT 1
|
|
437
|
+
`;
|
|
438
|
+
const homePage = db.prepare(homePageIdQuery).get(homePageRow.page_id);
|
|
439
|
+
if (homePage) {
|
|
440
|
+
const homePageUUID = homePage.rid || String(homePage.id);
|
|
441
|
+
if (tree.getPage(homePageUUID)) {
|
|
442
|
+
tree.rootId = homePageUUID;
|
|
443
|
+
tree.metadata.defaultHomePageId = homePageUUID;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// If no HOME page found, try tree_metadata table (general fallback)
|
|
448
|
+
if (!tree.rootId) {
|
|
449
|
+
const metadataQuery = "SELECT value FROM tree_metadata WHERE key = 'rootId'";
|
|
450
|
+
const rootIdRow = db.prepare(metadataQuery).get();
|
|
451
|
+
if (rootIdRow && tree.getPage(rootIdRow.value)) {
|
|
452
|
+
tree.rootId = rootIdRow.value;
|
|
453
|
+
tree.metadata.defaultHomePageId = rootIdRow.value;
|
|
454
|
+
}
|
|
421
455
|
}
|
|
422
|
-
|
|
456
|
+
// Final fallback: first page
|
|
457
|
+
if (!tree.rootId && rootPageId) {
|
|
423
458
|
tree.rootId = rootPageId;
|
|
459
|
+
tree.metadata.defaultHomePageId = rootPageId;
|
|
424
460
|
}
|
|
425
461
|
}
|
|
426
462
|
catch (e) {
|
|
427
|
-
// No metadata table, use first page as root
|
|
463
|
+
// No metadata table or other error, use first page as root
|
|
428
464
|
if (rootPageId) {
|
|
429
465
|
tree.rootId = rootPageId;
|
|
466
|
+
tree.metadata.defaultHomePageId = rootPageId;
|
|
430
467
|
}
|
|
431
468
|
}
|
|
432
469
|
// Set metadata for TouchChat files
|
|
@@ -519,7 +556,14 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
519
556
|
);
|
|
520
557
|
|
|
521
558
|
CREATE TABLE IF NOT EXISTS button_boxes (
|
|
522
|
-
id INTEGER PRIMARY KEY
|
|
559
|
+
id INTEGER PRIMARY KEY,
|
|
560
|
+
resource_id INTEGER,
|
|
561
|
+
layout_x INTEGER DEFAULT 10,
|
|
562
|
+
layout_y INTEGER DEFAULT 6,
|
|
563
|
+
init_size_x INTEGER DEFAULT 10000,
|
|
564
|
+
init_size_y INTEGER DEFAULT 10000,
|
|
565
|
+
scan_pattern_id INTEGER DEFAULT 0,
|
|
566
|
+
FOREIGN KEY (resource_id) REFERENCES resources (id)
|
|
523
567
|
);
|
|
524
568
|
|
|
525
569
|
CREATE TABLE IF NOT EXISTS button_box_cells (
|
|
@@ -677,8 +721,15 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
677
721
|
}
|
|
678
722
|
// Create a button box for this page's buttons
|
|
679
723
|
const buttonBoxId = buttonBoxIdCounter++;
|
|
680
|
-
|
|
681
|
-
|
|
724
|
+
// Create a resource for the button box
|
|
725
|
+
const buttonBoxResourceId = resourceIdCounter++;
|
|
726
|
+
const insertButtonBoxResource = db.prepare('INSERT INTO resources (id, name, type) VALUES (?, ?, ?)');
|
|
727
|
+
insertButtonBoxResource.run(buttonBoxResourceId, page.name || 'ButtonBox', 0);
|
|
728
|
+
// Insert button box with layout dimensions
|
|
729
|
+
const insertButtonBox = db.prepare('INSERT INTO button_boxes (id, resource_id, layout_x, layout_y, init_size_x, init_size_y) VALUES (?, ?, ?, ?, ?, ?)');
|
|
730
|
+
insertButtonBox.run(buttonBoxId, buttonBoxResourceId, gridWidth, gridHeight, 10000, // init_size_x in internal units
|
|
731
|
+
10000 // init_size_y in internal units
|
|
732
|
+
);
|
|
682
733
|
// Create button box instance with calculated dimensions
|
|
683
734
|
const insertButtonBoxInstance = db.prepare('INSERT INTO button_box_instances (id, page_id, button_box_id, position_x, position_y, size_x, size_y) VALUES (?, ?, ?, ?, ?, ?, ?)');
|
|
684
735
|
insertButtonBoxInstance.run(buttonBoxInstanceIdCounter++, numericPageId, buttonBoxId, 0, // Box starts at origin
|
|
@@ -30,7 +30,7 @@ export declare class MetricsCalculator {
|
|
|
30
30
|
* Count scan items for visual scanning effort
|
|
31
31
|
* When block scanning is enabled, count unique scan blocks instead of individual buttons
|
|
32
32
|
*/
|
|
33
|
-
private
|
|
33
|
+
private countScanBlocks;
|
|
34
34
|
/**
|
|
35
35
|
* Analyze starting from a specific board
|
|
36
36
|
*/
|