@willwade/aac-processors 0.2.12 → 0.2.14
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/dist/browser/core/treeStructure.js +60 -0
- package/dist/browser/processors/applePanelsProcessor.js +7 -1
- package/dist/browser/processors/astericsGridProcessor.js +7 -1
- package/dist/browser/processors/dotProcessor.js +9 -2
- package/dist/browser/processors/gridset/saveMutations.js +212 -0
- package/dist/browser/processors/gridsetProcessor.js +37 -39
- package/dist/browser/processors/obfProcessor.js +51 -1
- package/dist/browser/processors/opmlProcessor.js +7 -1
- package/dist/browser/processors/snapProcessor.js +7 -1
- package/dist/browser/processors/touchchatProcessor.js +8 -3
- package/dist/core/baseProcessor.d.ts +2 -0
- package/dist/core/treeStructure.d.ts +43 -2
- package/dist/core/treeStructure.js +60 -0
- package/dist/processors/applePanelsProcessor.d.ts +5 -0
- package/dist/processors/applePanelsProcessor.js +7 -1
- package/dist/processors/astericsGridProcessor.d.ts +5 -0
- package/dist/processors/astericsGridProcessor.js +7 -1
- package/dist/processors/dotProcessor.d.ts +5 -0
- package/dist/processors/dotProcessor.js +9 -2
- package/dist/processors/excelProcessor.d.ts +5 -0
- package/dist/processors/excelProcessor.js +8 -0
- package/dist/processors/gridset/saveMutations.d.ts +39 -0
- package/dist/processors/gridset/saveMutations.js +216 -0
- package/dist/processors/gridsetProcessor.d.ts +5 -0
- package/dist/processors/gridsetProcessor.js +37 -39
- package/dist/processors/obfProcessor.d.ts +14 -0
- package/dist/processors/obfProcessor.js +51 -1
- package/dist/processors/obfsetProcessor.d.ts +5 -0
- package/dist/processors/obfsetProcessor.js +5 -0
- package/dist/processors/opmlProcessor.d.ts +5 -0
- package/dist/processors/opmlProcessor.js +7 -1
- package/dist/processors/snapProcessor.d.ts +5 -0
- package/dist/processors/snapProcessor.js +7 -1
- package/dist/processors/touchchatProcessor.d.ts +5 -0
- package/dist/processors/touchchatProcessor.js +8 -3
- package/dist/types/aac.d.ts +54 -0
- package/package.json +1 -1
|
@@ -4,6 +4,11 @@ import { ValidationResult } from '../validation/validationTypes';
|
|
|
4
4
|
import { type ButtonForTranslation, type LLMLTranslationResult } from '../utilities/translation/translationProcessor';
|
|
5
5
|
import { ProcessorInput } from '../utils/io';
|
|
6
6
|
declare class ObfProcessor extends BaseProcessor {
|
|
7
|
+
readonly capabilities: {
|
|
8
|
+
wordList: "none";
|
|
9
|
+
preservesAssetsOnSave: boolean;
|
|
10
|
+
newCellCreation: "allowed";
|
|
11
|
+
};
|
|
7
12
|
private zipFile?;
|
|
8
13
|
private imageCache;
|
|
9
14
|
constructor(options?: ProcessorOptions);
|
|
@@ -21,6 +26,15 @@ declare class ObfProcessor extends BaseProcessor {
|
|
|
21
26
|
extractTexts(filePathOrBuffer: ProcessorInput): Promise<string[]>;
|
|
22
27
|
loadIntoTree(filePathOrBuffer: ProcessorInput): Promise<AACTree>;
|
|
23
28
|
private buildGridMetadata;
|
|
29
|
+
/**
|
|
30
|
+
* Apply mutations to a buttons array for OBF export
|
|
31
|
+
* Returns a modified copy of the buttons array with mutations applied
|
|
32
|
+
*
|
|
33
|
+
* Note: addButton mutations are NOT applied because the button is already
|
|
34
|
+
* in the buttons array (added by page.addButton()). We only apply
|
|
35
|
+
* removeButton and updateButton mutations.
|
|
36
|
+
*/
|
|
37
|
+
private applyMutationsToButtons;
|
|
24
38
|
private createObfBoardFromPage;
|
|
25
39
|
processTexts(filePathOrBuffer: ProcessorInput, translations: Map<string, string>, outputPath: string): Promise<Uint8Array>;
|
|
26
40
|
saveFromTree(tree: AACTree, outputPath: string, embedData?: boolean): Promise<void>;
|
|
@@ -44,6 +44,11 @@ function mapObfVisibility(hidden) {
|
|
|
44
44
|
class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
45
45
|
constructor(options) {
|
|
46
46
|
super(options);
|
|
47
|
+
this.capabilities = {
|
|
48
|
+
wordList: 'none',
|
|
49
|
+
preservesAssetsOnSave: true,
|
|
50
|
+
newCellCreation: 'allowed',
|
|
51
|
+
};
|
|
47
52
|
this.imageCache = new Map(); // Cache for data URLs
|
|
48
53
|
}
|
|
49
54
|
/**
|
|
@@ -557,6 +562,46 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
557
562
|
}
|
|
558
563
|
return { rows: totalRows, columns: totalColumns, order, buttonPositions };
|
|
559
564
|
}
|
|
565
|
+
/**
|
|
566
|
+
* Apply mutations to a buttons array for OBF export
|
|
567
|
+
* Returns a modified copy of the buttons array with mutations applied
|
|
568
|
+
*
|
|
569
|
+
* Note: addButton mutations are NOT applied because the button is already
|
|
570
|
+
* in the buttons array (added by page.addButton()). We only apply
|
|
571
|
+
* removeButton and updateButton mutations.
|
|
572
|
+
*/
|
|
573
|
+
applyMutationsToButtons(buttons, mutations) {
|
|
574
|
+
let modifiedButtons = [...buttons];
|
|
575
|
+
for (const mutation of mutations) {
|
|
576
|
+
switch (mutation.type) {
|
|
577
|
+
case 'addButton':
|
|
578
|
+
// Skip - button is already in the array from page.addButton()
|
|
579
|
+
break;
|
|
580
|
+
case 'removeButton': {
|
|
581
|
+
modifiedButtons = modifiedButtons.filter((b) => b.id !== mutation.buttonId);
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
case 'updateButton': {
|
|
585
|
+
modifiedButtons = modifiedButtons.map((b) => {
|
|
586
|
+
if (b.id === mutation.buttonId) {
|
|
587
|
+
// Create a new AACButton instance with the patched properties
|
|
588
|
+
const patched = Object.create(Object.getPrototypeOf(b));
|
|
589
|
+
Object.assign(patched, b, mutation.patch);
|
|
590
|
+
return patched;
|
|
591
|
+
}
|
|
592
|
+
return b;
|
|
593
|
+
});
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
case 'addWordListItem':
|
|
597
|
+
case 'removeWordListItem':
|
|
598
|
+
case 'clearWordList':
|
|
599
|
+
// OBF doesn't have WordList - skip
|
|
600
|
+
break;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return modifiedButtons;
|
|
604
|
+
}
|
|
560
605
|
createObfBoardFromPage(page, fallbackName, metadata, embedData = false) {
|
|
561
606
|
const { rows, columns, order, buttonPositions } = this.buildGridMetadata(page);
|
|
562
607
|
const boardName = metadata?.name && page.id === metadata?.defaultHomePageId
|
|
@@ -569,6 +614,10 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
569
614
|
return image;
|
|
570
615
|
});
|
|
571
616
|
}
|
|
617
|
+
// Apply mutations if present
|
|
618
|
+
const buttons = page.pendingMutations.length > 0
|
|
619
|
+
? this.applyMutationsToButtons(page.buttons, page.pendingMutations)
|
|
620
|
+
: page.buttons;
|
|
572
621
|
return {
|
|
573
622
|
format: OBF_FORMAT_VERSION,
|
|
574
623
|
id: page.id,
|
|
@@ -583,7 +632,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
583
632
|
columns,
|
|
584
633
|
order,
|
|
585
634
|
},
|
|
586
|
-
buttons:
|
|
635
|
+
buttons: buttons.map((button) => {
|
|
587
636
|
const extraButtonInfo = button;
|
|
588
637
|
const imageId = button.parameters?.image_id ||
|
|
589
638
|
button.parameters?.imageId ||
|
|
@@ -728,6 +777,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
728
777
|
for (const page of Object.values(tree.pages)) {
|
|
729
778
|
const obfFilename = this.getPageFilename(page.id, tree.metadata);
|
|
730
779
|
modifiedObfFiles.add(obfFilename);
|
|
780
|
+
// createObfBoardFromPage will automatically apply mutations if present
|
|
731
781
|
const obfBoard = this.createObfBoardFromPage(page, 'Board', tree.metadata);
|
|
732
782
|
const obfContent = JSON.stringify(obfBoard, null, 2);
|
|
733
783
|
newObfFiles.set(obfFilename, obfContent);
|
|
@@ -6,6 +6,11 @@ import { AACTree } from '../core/treeStructure';
|
|
|
6
6
|
import { BaseProcessor, ProcessorOptions } from '../core/baseProcessor';
|
|
7
7
|
import { ProcessorInput } from '../utils/io';
|
|
8
8
|
export declare class ObfsetProcessor extends BaseProcessor {
|
|
9
|
+
readonly capabilities: {
|
|
10
|
+
wordList: "none";
|
|
11
|
+
preservesAssetsOnSave: boolean;
|
|
12
|
+
newCellCreation: "allowed";
|
|
13
|
+
};
|
|
9
14
|
constructor(options?: ProcessorOptions);
|
|
10
15
|
/**
|
|
11
16
|
* Extract all text content
|
|
@@ -11,6 +11,11 @@ const baseProcessor_1 = require("../core/baseProcessor");
|
|
|
11
11
|
class ObfsetProcessor extends baseProcessor_1.BaseProcessor {
|
|
12
12
|
constructor(options = {}) {
|
|
13
13
|
super(options);
|
|
14
|
+
this.capabilities = {
|
|
15
|
+
wordList: 'none',
|
|
16
|
+
preservesAssetsOnSave: false,
|
|
17
|
+
newCellCreation: 'allowed',
|
|
18
|
+
};
|
|
14
19
|
}
|
|
15
20
|
/**
|
|
16
21
|
* Extract all text content
|
|
@@ -2,6 +2,11 @@ import { BaseProcessor, ProcessorOptions, ExtractStringsResult, TranslatedString
|
|
|
2
2
|
import { AACTree } from '../core/treeStructure';
|
|
3
3
|
import { ProcessorInput } from '../utils/io';
|
|
4
4
|
declare class OpmlProcessor extends BaseProcessor {
|
|
5
|
+
readonly capabilities: {
|
|
6
|
+
wordList: "none";
|
|
7
|
+
preservesAssetsOnSave: boolean;
|
|
8
|
+
newCellCreation: "allowed";
|
|
9
|
+
};
|
|
5
10
|
constructor(options?: ProcessorOptions);
|
|
6
11
|
private processOutline;
|
|
7
12
|
extractTexts(filePathOrBuffer: ProcessorInput): Promise<string[]>;
|
|
@@ -9,6 +9,11 @@ const io_1 = require("../utils/io");
|
|
|
9
9
|
class OpmlProcessor extends baseProcessor_1.BaseProcessor {
|
|
10
10
|
constructor(options) {
|
|
11
11
|
super(options);
|
|
12
|
+
this.capabilities = {
|
|
13
|
+
wordList: 'none',
|
|
14
|
+
preservesAssetsOnSave: false,
|
|
15
|
+
newCellCreation: 'allowed',
|
|
16
|
+
};
|
|
12
17
|
}
|
|
13
18
|
processOutline(outline, parentId = null) {
|
|
14
19
|
if (!outline || typeof outline !== 'object') {
|
|
@@ -40,7 +45,8 @@ class OpmlProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
40
45
|
message: '',
|
|
41
46
|
targetPageId: childText.replace(/[^a-zA-Z0-9]/g, '_'),
|
|
42
47
|
});
|
|
43
|
-
|
|
48
|
+
// Load path: do not record as a user mutation
|
|
49
|
+
page._loadButton(button);
|
|
44
50
|
const { page: childPage, childPages: grandChildren } = this.processOutline(child, page.id);
|
|
45
51
|
if (childPage && childPage.id)
|
|
46
52
|
childPages.push(childPage, ...grandChildren);
|
|
@@ -3,6 +3,11 @@ import { AACTree } from '../core/treeStructure';
|
|
|
3
3
|
import { ValidationResult } from '../validation/validationTypes';
|
|
4
4
|
import { ProcessorInput } from '../utils/io';
|
|
5
5
|
declare class SnapProcessor extends BaseProcessor {
|
|
6
|
+
readonly capabilities: {
|
|
7
|
+
wordList: "none";
|
|
8
|
+
preservesAssetsOnSave: boolean;
|
|
9
|
+
newCellCreation: "allowed";
|
|
10
|
+
};
|
|
6
11
|
private symbolResolver;
|
|
7
12
|
private loadAudio;
|
|
8
13
|
private pageLayoutPreference;
|
|
@@ -40,6 +40,11 @@ function mapSnapVisibility(visible) {
|
|
|
40
40
|
class SnapProcessor extends baseProcessor_1.BaseProcessor {
|
|
41
41
|
constructor(symbolResolver = null, options) {
|
|
42
42
|
super(options);
|
|
43
|
+
this.capabilities = {
|
|
44
|
+
wordList: 'none',
|
|
45
|
+
preservesAssetsOnSave: false,
|
|
46
|
+
newCellCreation: 'allowed',
|
|
47
|
+
};
|
|
43
48
|
this.symbolResolver = null;
|
|
44
49
|
this.loadAudio = false;
|
|
45
50
|
this.pageLayoutPreference = 'scanning'; // Default to scanning for metrics
|
|
@@ -577,7 +582,8 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
577
582
|
// Add to the intended parent page
|
|
578
583
|
const parentPage = tree.getPage(parentUniqueId);
|
|
579
584
|
if (parentPage) {
|
|
580
|
-
|
|
585
|
+
// Load path: do not record as a user mutation
|
|
586
|
+
parentPage._loadButton(button);
|
|
581
587
|
// Add button to grid layout if position data is available
|
|
582
588
|
const gridPositionStr = String(btnRow.GridPosition || '');
|
|
583
589
|
if (gridPositionStr && gridPositionStr.includes(',')) {
|
|
@@ -4,6 +4,11 @@ import { ValidationResult } from '../validation/validationTypes';
|
|
|
4
4
|
import { ProcessorInput } from '../utils/io';
|
|
5
5
|
import { type ButtonForTranslation, type LLMLTranslationResult } from '../utilities/translation/translationProcessor';
|
|
6
6
|
declare class TouchChatProcessor extends BaseProcessor {
|
|
7
|
+
readonly capabilities: {
|
|
8
|
+
wordList: "none";
|
|
9
|
+
preservesAssetsOnSave: boolean;
|
|
10
|
+
newCellCreation: "allowed";
|
|
11
|
+
};
|
|
7
12
|
private tree;
|
|
8
13
|
private sourceFile;
|
|
9
14
|
constructor(options?: ProcessorOptions);
|
|
@@ -34,6 +34,11 @@ function mapTouchChatVisibility(visible) {
|
|
|
34
34
|
class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
35
35
|
constructor(options) {
|
|
36
36
|
super(options);
|
|
37
|
+
this.capabilities = {
|
|
38
|
+
wordList: 'none',
|
|
39
|
+
preservesAssetsOnSave: false,
|
|
40
|
+
newCellCreation: 'allowed',
|
|
41
|
+
};
|
|
37
42
|
this.tree = null;
|
|
38
43
|
this.sourceFile = null;
|
|
39
44
|
}
|
|
@@ -264,8 +269,8 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
264
269
|
// Set button's x and y coordinates
|
|
265
270
|
button.x = absoluteX;
|
|
266
271
|
button.y = absoluteY;
|
|
267
|
-
// Add button to page
|
|
268
|
-
page.
|
|
272
|
+
// Add button to page (load path: do not record as a user mutation)
|
|
273
|
+
page._loadButton(button);
|
|
269
274
|
// Place button in grid (handle span)
|
|
270
275
|
for (let r = absoluteY; r < absoluteY + safeSpanY && r < 10; r++) {
|
|
271
276
|
for (let c = absoluteX; c < absoluteX + safeSpanX && c < 10; c++) {
|
|
@@ -366,7 +371,7 @@ class TouchChatProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
366
371
|
// Find the page that references this resource
|
|
367
372
|
const page = Object.values(tree.pages).find((p) => p.id === (numericToRid.get(btnRow.id) || String(btnRow.id)));
|
|
368
373
|
if (page)
|
|
369
|
-
page.
|
|
374
|
+
page._loadButton(button); // load path: do not record as a user mutation
|
|
370
375
|
});
|
|
371
376
|
}
|
|
372
377
|
catch (_e) {
|
package/dist/types/aac.d.ts
CHANGED
|
@@ -206,3 +206,57 @@ export interface AACProcessor {
|
|
|
206
206
|
extractTexts(filePath: string | Buffer): Promise<string[]>;
|
|
207
207
|
loadIntoTree(filePath: string | Buffer): Promise<AACTree>;
|
|
208
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Word List Item for dynamic content cells (e.g., Grid 3 WordLists)
|
|
211
|
+
*/
|
|
212
|
+
export interface AACWordListItem {
|
|
213
|
+
text: string;
|
|
214
|
+
image?: string;
|
|
215
|
+
partOfSpeech?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Mutation types for page modifications
|
|
219
|
+
*/
|
|
220
|
+
export type AACPageMutation = {
|
|
221
|
+
type: 'addButton';
|
|
222
|
+
button: AACButton;
|
|
223
|
+
} | {
|
|
224
|
+
type: 'removeButton';
|
|
225
|
+
buttonId: string;
|
|
226
|
+
} | {
|
|
227
|
+
type: 'updateButton';
|
|
228
|
+
buttonId: string;
|
|
229
|
+
patch: Partial<AACButton>;
|
|
230
|
+
} | {
|
|
231
|
+
type: 'addWordListItem';
|
|
232
|
+
item: AACWordListItem;
|
|
233
|
+
} | {
|
|
234
|
+
type: 'removeWordListItem';
|
|
235
|
+
match: string | ((item: AACWordListItem) => boolean);
|
|
236
|
+
} | {
|
|
237
|
+
type: 'clearWordList';
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Processor capabilities declaration
|
|
241
|
+
*/
|
|
242
|
+
export interface ProcessorCapabilities {
|
|
243
|
+
/**
|
|
244
|
+
* WordList support level
|
|
245
|
+
* - 'native': addWordListItem writes a real WordList structure on disk
|
|
246
|
+
* - 'fallback': addWordListItem becomes addButton (still useful, just not dynamic)
|
|
247
|
+
* - 'none': addWordListItem throws CapabilityError
|
|
248
|
+
*/
|
|
249
|
+
wordList: 'native' | 'fallback' | 'none';
|
|
250
|
+
/**
|
|
251
|
+
* Whether the processor has a real saveModifiedTree that keeps original images/settings
|
|
252
|
+
* If false, saveModifiedTree falls back to saveFromTree with a warning
|
|
253
|
+
*/
|
|
254
|
+
preservesAssetsOnSave: boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Rules for creating new cells
|
|
257
|
+
* - 'allowed': addButton at any (x,y) creates a cell on save
|
|
258
|
+
* - 'restricted': addButton routes to a WordList if (x,y) is a WordList cell, else dropped with warning
|
|
259
|
+
* - 'forbidden': addButton requires explicit (x,y) of an existing cell; otherwise CapabilityError
|
|
260
|
+
*/
|
|
261
|
+
newCellCreation: 'allowed' | 'restricted' | 'forbidden';
|
|
262
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@willwade/aac-processors",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
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
|
"browser": "dist/browser/index.browser.js",
|