@willwade/aac-processors 0.0.30 → 0.1.1
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 +52 -852
- package/dist/browser/core/baseProcessor.js +241 -0
- package/dist/browser/core/stringCasing.js +179 -0
- package/dist/browser/core/treeStructure.js +255 -0
- package/dist/browser/index.browser.js +73 -0
- package/dist/browser/processors/applePanelsProcessor.js +582 -0
- package/dist/browser/processors/astericsGridProcessor.js +1509 -0
- package/dist/browser/processors/dotProcessor.js +221 -0
- package/dist/browser/processors/gridset/commands.js +962 -0
- package/dist/browser/processors/gridset/crypto.js +53 -0
- package/dist/browser/processors/gridset/password.js +49 -0
- package/dist/browser/processors/gridset/pluginTypes.js +277 -0
- package/dist/browser/processors/gridset/resolver.js +137 -0
- package/dist/browser/processors/gridset/symbolAlignment.js +276 -0
- package/dist/browser/processors/gridset/symbols.js +464 -0
- package/dist/browser/processors/gridsetProcessor.js +2002 -0
- package/dist/browser/processors/obfProcessor.js +705 -0
- package/dist/browser/processors/opmlProcessor.js +274 -0
- package/dist/browser/types/aac.js +38 -0
- package/dist/browser/utilities/analytics/utils/idGenerator.js +89 -0
- package/dist/browser/utilities/translation/translationProcessor.js +200 -0
- package/dist/browser/utils/io.js +95 -0
- package/dist/browser/validation/baseValidator.js +156 -0
- package/dist/browser/validation/gridsetValidator.js +356 -0
- package/dist/browser/validation/obfValidator.js +500 -0
- package/dist/browser/validation/validationTypes.js +46 -0
- package/dist/cli/index.js +5 -5
- package/dist/core/analyze.d.ts +2 -2
- package/dist/core/analyze.js +2 -2
- package/dist/core/baseProcessor.d.ts +5 -4
- package/dist/core/baseProcessor.js +22 -27
- package/dist/core/treeStructure.d.ts +5 -5
- package/dist/core/treeStructure.js +1 -4
- package/dist/index.browser.d.ts +37 -0
- package/dist/index.browser.js +99 -0
- package/dist/index.d.ts +1 -48
- package/dist/index.js +1 -136
- package/dist/index.node.d.ts +48 -0
- package/dist/index.node.js +152 -0
- package/dist/processors/applePanelsProcessor.d.ts +5 -4
- package/dist/processors/applePanelsProcessor.js +58 -62
- package/dist/processors/astericsGridProcessor.d.ts +7 -6
- package/dist/processors/astericsGridProcessor.js +31 -42
- package/dist/processors/dotProcessor.d.ts +5 -4
- package/dist/processors/dotProcessor.js +25 -33
- package/dist/processors/excelProcessor.d.ts +4 -3
- package/dist/processors/excelProcessor.js +6 -3
- package/dist/processors/gridset/crypto.d.ts +18 -0
- package/dist/processors/gridset/crypto.js +57 -0
- package/dist/processors/gridset/helpers.d.ts +1 -1
- package/dist/processors/gridset/helpers.js +18 -8
- package/dist/processors/gridset/password.d.ts +20 -3
- package/dist/processors/gridset/password.js +29 -12
- package/dist/processors/gridset/symbols.js +63 -46
- package/dist/processors/gridset/wordlistHelpers.d.ts +3 -3
- package/dist/processors/gridset/wordlistHelpers.js +21 -20
- package/dist/processors/gridsetProcessor.d.ts +7 -12
- package/dist/processors/gridsetProcessor.js +116 -77
- package/dist/processors/obfProcessor.d.ts +9 -7
- package/dist/processors/obfProcessor.js +131 -56
- package/dist/processors/obfsetProcessor.d.ts +5 -4
- package/dist/processors/obfsetProcessor.js +10 -16
- package/dist/processors/opmlProcessor.d.ts +5 -4
- package/dist/processors/opmlProcessor.js +27 -34
- package/dist/processors/snapProcessor.d.ts +8 -7
- package/dist/processors/snapProcessor.js +15 -12
- package/dist/processors/touchchatProcessor.d.ts +8 -7
- package/dist/processors/touchchatProcessor.js +22 -17
- package/dist/types/aac.d.ts +0 -2
- package/dist/types/aac.js +2 -0
- package/dist/utils/io.d.ts +12 -0
- package/dist/utils/io.js +107 -0
- package/dist/validation/gridsetValidator.js +10 -9
- package/dist/validation/snapValidator.js +28 -35
- package/docs/BROWSER_USAGE.md +618 -0
- package/docs/PAGESET_GETTING_STARTED.md +185 -0
- package/examples/README.md +77 -0
- package/examples/browser-test-server.js +81 -0
- package/examples/browser-test.html +331 -0
- package/examples/vitedemo/QUICKSTART.md +75 -0
- package/examples/vitedemo/README.md +157 -0
- package/examples/vitedemo/index.html +531 -0
- package/examples/vitedemo/package-lock.json +1221 -0
- package/examples/vitedemo/package.json +18 -0
- package/examples/vitedemo/src/main.ts +871 -0
- package/examples/vitedemo/test-files/example.dot +14 -0
- package/examples/vitedemo/test-files/example.grd +1 -0
- package/examples/vitedemo/test-files/example.gridset +0 -0
- package/examples/vitedemo/test-files/example.obz +0 -0
- package/examples/vitedemo/test-files/example.opml +18 -0
- package/examples/vitedemo/test-files/simple.obf +53 -0
- package/examples/vitedemo/tsconfig.json +24 -0
- package/examples/vitedemo/vite.config.ts +34 -0
- package/package.json +21 -4
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# AAC Pageset Quickstart (Node + Browser)
|
|
2
|
+
|
|
3
|
+
This guide shows two simple ways to generate or convert AAC pagesets using `aac-processors`:
|
|
4
|
+
|
|
5
|
+
- Node.js: full conversion between formats (read + write)
|
|
6
|
+
- Browser: generate or export to OBF/OBZ in-memory (downloadable)
|
|
7
|
+
|
|
8
|
+
If you need lossless conversion in the browser, use a Node/worker service for the save step (file I/O is required for most formats).
|
|
9
|
+
|
|
10
|
+
## Node.js: Convert and Generate Pagesets
|
|
11
|
+
|
|
12
|
+
### Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install aac-processors
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Convert a Gridset to OBF
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { getProcessor, ObfProcessor } from 'aac-processors';
|
|
22
|
+
|
|
23
|
+
async function convertGridsetToObf() {
|
|
24
|
+
const sourcePath = './input/example.gridset';
|
|
25
|
+
const targetPath = './output/example.obf';
|
|
26
|
+
|
|
27
|
+
const sourceProcessor = getProcessor(sourcePath); // GridsetProcessor
|
|
28
|
+
const tree = await sourceProcessor.loadIntoTree(sourcePath);
|
|
29
|
+
|
|
30
|
+
const obf = new ObfProcessor();
|
|
31
|
+
await obf.saveFromTree(tree, targetPath);
|
|
32
|
+
|
|
33
|
+
console.log('Saved:', targetPath);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
convertGridsetToObf().catch(console.error);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Generate a Simple Pageset and Save as OBZ
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { AACTree, AACPage, AACButton, ObfProcessor } from 'aac-processors';
|
|
43
|
+
|
|
44
|
+
async function generateObz() {
|
|
45
|
+
const tree = new AACTree();
|
|
46
|
+
tree.metadata = { name: 'Starter Demo', locale: 'en' };
|
|
47
|
+
|
|
48
|
+
const hello = new AACButton({ id: 'hello', label: 'Hello', message: 'Hello' });
|
|
49
|
+
const thanks = new AACButton({ id: 'thanks', label: 'Thanks', message: 'Thank you' });
|
|
50
|
+
|
|
51
|
+
const home = new AACPage({
|
|
52
|
+
id: 'home',
|
|
53
|
+
name: 'Home',
|
|
54
|
+
buttons: [hello, thanks],
|
|
55
|
+
grid: [[hello, thanks]],
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
tree.addPage(home);
|
|
59
|
+
tree.rootId = 'home';
|
|
60
|
+
|
|
61
|
+
const obf = new ObfProcessor();
|
|
62
|
+
await obf.saveFromTree(tree, './output/starter.obz');
|
|
63
|
+
|
|
64
|
+
console.log('Saved: ./output/starter.obz');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
generateObz().catch(console.error);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Browser: Generate or Convert to OBF/OBZ
|
|
71
|
+
|
|
72
|
+
In the browser you can still parse files and build an `AACTree`, but most processors cannot write to disk (no `fs`).
|
|
73
|
+
The example below generates an `AACTree`, converts it to OBF JSON in-memory, and downloads it.
|
|
74
|
+
|
|
75
|
+
If you need full conversions in a browser app, do the save step in Node (server or worker).
|
|
76
|
+
|
|
77
|
+
### Generate a Pageset and Download as OBF
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { AACTree, AACPage, AACButton, ObfProcessor } from 'aac-processors';
|
|
81
|
+
|
|
82
|
+
function downloadBlob(data: BlobPart, filename: string, type: string) {
|
|
83
|
+
const blob = new Blob([data], { type });
|
|
84
|
+
const url = URL.createObjectURL(blob);
|
|
85
|
+
const a = document.createElement('a');
|
|
86
|
+
a.href = url;
|
|
87
|
+
a.download = filename;
|
|
88
|
+
a.click();
|
|
89
|
+
URL.revokeObjectURL(url);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function buildSampleTree() {
|
|
93
|
+
const tree = new AACTree();
|
|
94
|
+
tree.metadata = { name: 'Browser Demo', locale: 'en' };
|
|
95
|
+
|
|
96
|
+
const hello = new AACButton({ id: 'hello', label: 'Hello', message: 'Hello' });
|
|
97
|
+
const yes = new AACButton({ id: 'yes', label: 'Yes', message: 'Yes' });
|
|
98
|
+
|
|
99
|
+
const home = new AACPage({
|
|
100
|
+
id: 'home',
|
|
101
|
+
name: 'Home',
|
|
102
|
+
buttons: [hello, yes],
|
|
103
|
+
grid: [[hello, yes]],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
tree.addPage(home);
|
|
107
|
+
tree.rootId = 'home';
|
|
108
|
+
return tree;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function exportObf(tree: AACTree) {
|
|
112
|
+
// This mirrors the browser demo approach: create OBF JSON and download.
|
|
113
|
+
// ObfProcessor.saveFromTree writes to disk, so we build a board in-memory.
|
|
114
|
+
const obf = new ObfProcessor() as ObfProcessor & {
|
|
115
|
+
createObfBoardFromPage?: (page: AACPage, fallbackName: string, metadata?: AACTree['metadata']) => any;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const rootPage = tree.rootId ? tree.getPage(tree.rootId) : Object.values(tree.pages)[0];
|
|
119
|
+
const board = obf.createObfBoardFromPage
|
|
120
|
+
? obf.createObfBoardFromPage(rootPage!, 'Board', tree.metadata)
|
|
121
|
+
: {
|
|
122
|
+
format: 'open-board-0.1',
|
|
123
|
+
id: rootPage?.id ?? 'board',
|
|
124
|
+
name: rootPage?.name ?? 'Board',
|
|
125
|
+
locale: tree.metadata?.locale || 'en',
|
|
126
|
+
grid: { rows: 1, columns: rootPage?.buttons.length ?? 0, order: [] },
|
|
127
|
+
buttons: (rootPage?.buttons || []).map((button) => ({
|
|
128
|
+
id: button.id,
|
|
129
|
+
label: button.label,
|
|
130
|
+
vocalization: button.message || button.label,
|
|
131
|
+
})),
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const json = JSON.stringify(board, null, 2);
|
|
135
|
+
downloadBlob(json, 'browser-demo.obf', 'application/json');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const tree = buildSampleTree();
|
|
139
|
+
exportObf(tree);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Convert an Uploaded Pageset to OBZ (Browser)
|
|
143
|
+
|
|
144
|
+
This uses the same idea as the Vite demo: parse any supported file into a tree,
|
|
145
|
+
then export OBF/OBZ in-memory and download.
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
import { getProcessor, ObfProcessor, type AACTree, type AACPage } from 'aac-processors';
|
|
149
|
+
import JSZip from 'jszip';
|
|
150
|
+
|
|
151
|
+
async function convertToObz(file: File) {
|
|
152
|
+
const extension = '.' + file.name.split('.').pop();
|
|
153
|
+
const processor = getProcessor(extension);
|
|
154
|
+
const buffer = await file.arrayBuffer();
|
|
155
|
+
const tree = await processor.loadIntoTree(buffer);
|
|
156
|
+
|
|
157
|
+
const obf = new ObfProcessor() as ObfProcessor & {
|
|
158
|
+
createObfBoardFromPage?: (page: AACPage, fallbackName: string, metadata?: AACTree['metadata']) => any;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const zip = new JSZip();
|
|
162
|
+
Object.values(tree.pages).forEach((page) => {
|
|
163
|
+
const board = obf.createObfBoardFromPage
|
|
164
|
+
? obf.createObfBoardFromPage(page, 'Board', tree.metadata)
|
|
165
|
+
: { format: 'open-board-0.1', id: page.id, name: page.name, grid: { rows: 0, columns: 0, order: [] }, buttons: [] };
|
|
166
|
+
zip.file(`${page.id}.obf`, JSON.stringify(board, null, 2));
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const data = await zip.generateAsync({ type: 'uint8array' });
|
|
170
|
+
const blob = new Blob([data], { type: 'application/zip' });
|
|
171
|
+
const url = URL.createObjectURL(blob);
|
|
172
|
+
const a = document.createElement('a');
|
|
173
|
+
a.href = url;
|
|
174
|
+
a.download = 'converted.obz';
|
|
175
|
+
a.click();
|
|
176
|
+
URL.revokeObjectURL(url);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Tips
|
|
181
|
+
|
|
182
|
+
- Use `loadIntoTree()` to normalize different AAC formats into one structure.
|
|
183
|
+
- In Node, `saveFromTree()` lets you write to OBF, OBZ, Gridset, etc.
|
|
184
|
+
- In the browser, build the output in memory and offer it for download.
|
|
185
|
+
- For full-fidelity conversions in the browser, use a server-side endpoint to save files.
|
package/examples/README.md
CHANGED
|
@@ -48,3 +48,80 @@ These pagesets are used by:
|
|
|
48
48
|
- Integration examples
|
|
49
49
|
|
|
50
50
|
To run demo scripts that use these pagesets, see the [scripts/README.md](../scripts/README.md).
|
|
51
|
+
|
|
52
|
+
## Browser Testing
|
|
53
|
+
|
|
54
|
+
### ⚠️ Important Note
|
|
55
|
+
|
|
56
|
+
AACProcessors is built with TypeScript and outputs CommonJS modules. To use it in a browser, you **must use a bundler** (Vite, Webpack, Rollup, etc.). The browser test page below only validates the library structure - it cannot run actual processors without a bundler.
|
|
57
|
+
|
|
58
|
+
### Browser Test Page
|
|
59
|
+
|
|
60
|
+
A dedicated browser test page is available for validating the library structure:
|
|
61
|
+
|
|
62
|
+
**Start the test server:**
|
|
63
|
+
```bash
|
|
64
|
+
node examples/browser-test-server.js
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Open in your browser:**
|
|
68
|
+
```
|
|
69
|
+
http://localhost:8080/examples/browser-test.html
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**What it tests:**
|
|
73
|
+
- ✅ Browser build files exist and are accessible
|
|
74
|
+
- ✅ Type definitions are present
|
|
75
|
+
- ✅ Processor exports are available
|
|
76
|
+
- ❌ **Does NOT run actual processors** (requires bundler)
|
|
77
|
+
|
|
78
|
+
### What Gets Tested
|
|
79
|
+
|
|
80
|
+
The browser test page (`browser-test.html`) verifies:
|
|
81
|
+
|
|
82
|
+
1. **Module Loading** - Can the browser load the ES modules?
|
|
83
|
+
2. **Factory Functions** - Do `getProcessor()` and `getSupportedExtensions()` work?
|
|
84
|
+
3. **Processor Instantiation** - Can processors be created?
|
|
85
|
+
4. **File Loading** - Can files be loaded from `<input type="file">`?
|
|
86
|
+
5. **Buffer Handling** - Do ArrayBuffers/Uint8Arrays work correctly?
|
|
87
|
+
6. **Tree Structure** - Can AACTree be created from files?
|
|
88
|
+
7. **Text Extraction** - Can texts be extracted from files?
|
|
89
|
+
|
|
90
|
+
### Supported File Types in Browser
|
|
91
|
+
|
|
92
|
+
The browser test page supports all browser-compatible processors:
|
|
93
|
+
|
|
94
|
+
- **DotProcessor** (.dot) - OpenSymbols Board files
|
|
95
|
+
- **OpmlProcessor** (.opml) - OPML outline files
|
|
96
|
+
- **ObfProcessor** (.obf/.obz) - Open Board Format files
|
|
97
|
+
- **GridsetProcessor** (.gridset) - Grid 3 gridset files (not .gridsetx)
|
|
98
|
+
- **ApplePanelsProcessor** (.plist) - Apple Panels files
|
|
99
|
+
- **AstericsGridProcessor** (.grd) - Asterics Grid files
|
|
100
|
+
|
|
101
|
+
### Manual Testing
|
|
102
|
+
|
|
103
|
+
1. Open the browser console (F12 or Cmd+Option+I)
|
|
104
|
+
2. Click "Select a file to test" to upload an AAC file
|
|
105
|
+
3. Click "Test File" to process it
|
|
106
|
+
4. Check the results panel for page count, button count, and extracted texts
|
|
107
|
+
|
|
108
|
+
### Automated Tests
|
|
109
|
+
|
|
110
|
+
Click "Run All Browser Tests" to run automated checks:
|
|
111
|
+
- Factory function tests
|
|
112
|
+
- Extension support tests
|
|
113
|
+
- Processor instantiation tests
|
|
114
|
+
- Buffer handling tests
|
|
115
|
+
|
|
116
|
+
### Node-Only Processors
|
|
117
|
+
|
|
118
|
+
The following processors are **not available** in the browser:
|
|
119
|
+
- **SnapProcessor** (.spb/.sps) - Requires SQLite
|
|
120
|
+
- **TouchChatProcessor** (.ce) - Requires SQLite
|
|
121
|
+
- **ExcelProcessor** (.xlsx) - Uses fs at top level
|
|
122
|
+
|
|
123
|
+
### Notes
|
|
124
|
+
|
|
125
|
+
- Gridset `.gridsetx` files (encrypted) are not supported in browser
|
|
126
|
+
- All processors work with Buffer, Uint8Array, and ArrayBuffer inputs
|
|
127
|
+
- File paths are not supported in browser (use file inputs or fetch)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Simple HTTP server for testing AACProcessors in a browser
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node examples/browser-test-server.js
|
|
8
|
+
*
|
|
9
|
+
* Then open: http://localhost:8080/examples/browser-test.html
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const http = require('http');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
const PORT = 8080;
|
|
17
|
+
const MIME_TYPES = {
|
|
18
|
+
'.html': 'text/html',
|
|
19
|
+
'.js': 'text/javascript',
|
|
20
|
+
'.css': 'text/css',
|
|
21
|
+
'.json': 'application/json',
|
|
22
|
+
'.png': 'image/png',
|
|
23
|
+
'.jpg': 'image/jpg',
|
|
24
|
+
'.gif': 'image/gif',
|
|
25
|
+
'.svg': 'image/svg+xml',
|
|
26
|
+
'.ico': 'image/x-icon',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const server = http.createServer((req, res) => {
|
|
30
|
+
// Enable CORS
|
|
31
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
32
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
33
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
34
|
+
|
|
35
|
+
if (req.method === 'OPTIONS') {
|
|
36
|
+
res.writeHead(200);
|
|
37
|
+
res.end();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Parse URL
|
|
42
|
+
let filePath = '.' + req.url;
|
|
43
|
+
if (filePath === './') {
|
|
44
|
+
filePath = './examples/browser-test.html';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Get file extension
|
|
48
|
+
const extname = String(path.extname(filePath)).toLowerCase();
|
|
49
|
+
const contentType = MIME_TYPES[extname] || 'application/octet-stream';
|
|
50
|
+
|
|
51
|
+
// Read and serve file
|
|
52
|
+
fs.readFile(filePath, (error, content) => {
|
|
53
|
+
if (error) {
|
|
54
|
+
if (error.code === 'ENOENT') {
|
|
55
|
+
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
56
|
+
res.end('<h1>404 Not Found</h1>', 'utf-8');
|
|
57
|
+
} else {
|
|
58
|
+
res.writeHead(500);
|
|
59
|
+
res.end(`Server Error: ${error.code}`, 'utf-8');
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
63
|
+
res.end(content, 'utf-8');
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
server.listen(PORT, () => {
|
|
69
|
+
console.log(`
|
|
70
|
+
╔════════════════════════════════════════════════════════════╗
|
|
71
|
+
║ AACProcessors Browser Test Server ║
|
|
72
|
+
╠════════════════════════════════════════════════════════════╣
|
|
73
|
+
║ ║
|
|
74
|
+
║ Server running at: ║
|
|
75
|
+
║ 🌐 http://localhost:${PORT}/examples/browser-test.html ║
|
|
76
|
+
║ ║
|
|
77
|
+
║ Press Ctrl+C to stop ║
|
|
78
|
+
║ ║
|
|
79
|
+
╚════════════════════════════════════════════════════════════╝
|
|
80
|
+
`);
|
|
81
|
+
});
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>AAC Processors - Browser Compatibility Test</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
10
|
+
max-width: 1200px;
|
|
11
|
+
margin: 0 auto;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
background: #f5f5f5;
|
|
14
|
+
}
|
|
15
|
+
h1 {
|
|
16
|
+
color: #333;
|
|
17
|
+
border-bottom: 2px solid #007bff;
|
|
18
|
+
padding-bottom: 10px;
|
|
19
|
+
}
|
|
20
|
+
.test-section {
|
|
21
|
+
background: white;
|
|
22
|
+
border-radius: 8px;
|
|
23
|
+
padding: 20px;
|
|
24
|
+
margin: 20px 0;
|
|
25
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
26
|
+
}
|
|
27
|
+
.file-input {
|
|
28
|
+
margin: 10px 0;
|
|
29
|
+
}
|
|
30
|
+
.file-input label {
|
|
31
|
+
display: block;
|
|
32
|
+
font-weight: 600;
|
|
33
|
+
margin-bottom: 5px;
|
|
34
|
+
color: #555;
|
|
35
|
+
}
|
|
36
|
+
.file-input input {
|
|
37
|
+
display: block;
|
|
38
|
+
width: 100%;
|
|
39
|
+
padding: 8px;
|
|
40
|
+
border: 2px solid #ddd;
|
|
41
|
+
border-radius: 4px;
|
|
42
|
+
}
|
|
43
|
+
.test-button {
|
|
44
|
+
background: #007bff;
|
|
45
|
+
color: white;
|
|
46
|
+
border: none;
|
|
47
|
+
padding: 10px 20px;
|
|
48
|
+
border-radius: 4px;
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
font-size: 14px;
|
|
51
|
+
margin-top: 10px;
|
|
52
|
+
}
|
|
53
|
+
.test-button:hover {
|
|
54
|
+
background: #0056b3;
|
|
55
|
+
}
|
|
56
|
+
.test-button:disabled {
|
|
57
|
+
background: #ccc;
|
|
58
|
+
cursor: not-allowed;
|
|
59
|
+
}
|
|
60
|
+
.result {
|
|
61
|
+
margin-top: 15px;
|
|
62
|
+
padding: 15px;
|
|
63
|
+
border-radius: 4px;
|
|
64
|
+
font-family: 'Monaco', 'Menlo', monospace;
|
|
65
|
+
font-size: 13px;
|
|
66
|
+
white-space: pre-wrap;
|
|
67
|
+
word-wrap: break-word;
|
|
68
|
+
}
|
|
69
|
+
.result.success {
|
|
70
|
+
background: #d4edda;
|
|
71
|
+
border: 1px solid #c3e6cb;
|
|
72
|
+
color: #155724;
|
|
73
|
+
}
|
|
74
|
+
.result.error {
|
|
75
|
+
background: #f8d7da;
|
|
76
|
+
border: 1px solid #f5c6cb;
|
|
77
|
+
color: #721c24;
|
|
78
|
+
}
|
|
79
|
+
.result.info {
|
|
80
|
+
background: #d1ecf1;
|
|
81
|
+
border: 1px solid #bee5eb;
|
|
82
|
+
color: #0c5460;
|
|
83
|
+
}
|
|
84
|
+
.info-box {
|
|
85
|
+
background: #fff3cd;
|
|
86
|
+
border: 1px solid #ffc107;
|
|
87
|
+
border-radius: 4px;
|
|
88
|
+
padding: 15px;
|
|
89
|
+
margin: 20px 0;
|
|
90
|
+
}
|
|
91
|
+
.info-box strong {
|
|
92
|
+
display: block;
|
|
93
|
+
margin-bottom: 5px;
|
|
94
|
+
}
|
|
95
|
+
.processor-list {
|
|
96
|
+
display: grid;
|
|
97
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
98
|
+
gap: 10px;
|
|
99
|
+
margin: 15px 0;
|
|
100
|
+
}
|
|
101
|
+
.processor-item {
|
|
102
|
+
background: #e7f3ff;
|
|
103
|
+
padding: 10px;
|
|
104
|
+
border-radius: 4px;
|
|
105
|
+
border-left: 3px solid #007bff;
|
|
106
|
+
}
|
|
107
|
+
.processor-item.supported {
|
|
108
|
+
border-left-color: #28a745;
|
|
109
|
+
background: #d4edda;
|
|
110
|
+
}
|
|
111
|
+
</style>
|
|
112
|
+
</head>
|
|
113
|
+
<body>
|
|
114
|
+
<h1>🧪 AAC Processors - Browser Compatibility Test</h1>
|
|
115
|
+
|
|
116
|
+
<div class="info-box">
|
|
117
|
+
<strong>ℹ️ About this test page</strong>
|
|
118
|
+
This page tests AACProcessors in a real browser environment. It verifies that processors
|
|
119
|
+
can load files using browser APIs (File, Blob, ArrayBuffer) without any Node.js dependencies.
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div class="test-section">
|
|
123
|
+
<h2>Supported Processors</h2>
|
|
124
|
+
<div class="processor-list">
|
|
125
|
+
<div class="processor-item supported">✅ DotProcessor (.dot)</div>
|
|
126
|
+
<div class="processor-item supported">✅ OpmlProcessor (.opml)</div>
|
|
127
|
+
<div class="processor-item supported">✅ ObfProcessor (.obf/.obz)</div>
|
|
128
|
+
<div class="processor-item supported">✅ GridsetProcessor (.gridset)</div>
|
|
129
|
+
<div class="processor-item supported">✅ ApplePanelsProcessor (.plist)</div>
|
|
130
|
+
<div class="processor-item supported">✅ AstericsGridProcessor (.grd)</div>
|
|
131
|
+
</div>
|
|
132
|
+
<p style="color: #666; font-size: 14px;">
|
|
133
|
+
<strong>Note:</strong> SnapProcessor and TouchChatProcessor require Node.js (sqlite).
|
|
134
|
+
GridsetProcessor .gridsetx files require Node.js (crypto).
|
|
135
|
+
</p>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div class="test-section">
|
|
139
|
+
<h2>📁 Load and Test Files</h2>
|
|
140
|
+
|
|
141
|
+
<div class="file-input">
|
|
142
|
+
<label for="fileInput">Select a file to test:</label>
|
|
143
|
+
<input type="file" id="fileInput" accept=".dot,.opml,.obf,.obz,.gridset,.plist,.grd">
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<button id="testButton" class="test-button" disabled>Test File</button>
|
|
147
|
+
<button id="clearButton" class="test-button">Clear Results</button>
|
|
148
|
+
|
|
149
|
+
<div id="result" class="result" style="display: none;"></div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div class="test-section">
|
|
153
|
+
<h2>🧪 Automated Tests</h2>
|
|
154
|
+
<button id="runAllTests" class="test-button">Run All Browser Tests</button>
|
|
155
|
+
<div id="testResults" class="result" style="display: none;"></div>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<!-- Note: Using a module loader to handle CommonJS exports -->
|
|
159
|
+
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
|
160
|
+
<script data-type="module" type="text/babel" data-presets="env">
|
|
161
|
+
// Since the build outputs CommonJS, we need to dynamically import the processors
|
|
162
|
+
// For now, we'll use a simpler approach with inline test code
|
|
163
|
+
|
|
164
|
+
class AACProcessorsTest {
|
|
165
|
+
constructor() {
|
|
166
|
+
this.processors = {};
|
|
167
|
+
this.init();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async init() {
|
|
171
|
+
// Initialize processors after DOM is ready
|
|
172
|
+
const fileInput = document.getElementById('fileInput');
|
|
173
|
+
const testButton = document.getElementById('testButton');
|
|
174
|
+
const clearButton = document.getElementById('clearButton');
|
|
175
|
+
const runAllTestsButton = document.getElementById('runAllTests');
|
|
176
|
+
|
|
177
|
+
fileInput.addEventListener('change', (e) => this.handleFileSelect(e));
|
|
178
|
+
testButton.addEventListener('click', () => this.testFile());
|
|
179
|
+
clearButton.addEventListener('click', () => this.clearResults());
|
|
180
|
+
runAllTestsButton.addEventListener('click', () => this.runAutomatedTests());
|
|
181
|
+
|
|
182
|
+
console.log('AAC Processors Browser Test Page Ready');
|
|
183
|
+
console.log('Note: This page tests the library structure but cannot run actual processors without a bundler.');
|
|
184
|
+
console.log('For actual browser usage, see docs/BROWSER_USAGE.md for bundler setup.');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
showMessage(message, type = 'info') {
|
|
188
|
+
const resultDiv = document.getElementById('result');
|
|
189
|
+
resultDiv.style.display = 'block';
|
|
190
|
+
resultDiv.className = `result ${type}`;
|
|
191
|
+
resultDiv.textContent = message;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
showTestResults(results) {
|
|
195
|
+
const testResultsDiv = document.getElementById('testResults');
|
|
196
|
+
testResultsDiv.style.display = 'block';
|
|
197
|
+
testResultsDiv.className = 'result info';
|
|
198
|
+
testResultsDiv.textContent = results;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
handleFileSelect(event) {
|
|
202
|
+
const file = event.target.files[0];
|
|
203
|
+
const testButton = document.getElementById('testButton');
|
|
204
|
+
|
|
205
|
+
if (file) {
|
|
206
|
+
testButton.disabled = false;
|
|
207
|
+
this.showMessage(`Selected: ${file.name} (${file.size} bytes)\n\nNote: Actual processing requires a bundler (webpack/vite/rollup) to bundle the library for browser use.`, 'info');
|
|
208
|
+
} else {
|
|
209
|
+
testButton.disabled = true;
|
|
210
|
+
document.getElementById('result').style.display = 'none';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async testFile() {
|
|
215
|
+
this.showMessage(
|
|
216
|
+
'⚠️ Browser Build Note\n\n' +
|
|
217
|
+
'The current build outputs CommonJS modules which require a bundler.\n\n' +
|
|
218
|
+
'To use AACProcessors in a browser:\n\n' +
|
|
219
|
+
'1. Use a bundler (webpack, vite, rollup, etc.)\n' +
|
|
220
|
+
'2. Or use a CDN bundle (when available)\n' +
|
|
221
|
+
'3. See docs/BROWSER_USAGE.md for complete setup instructions\n\n' +
|
|
222
|
+
'Example with Vite:\n' +
|
|
223
|
+
'```js\n' +
|
|
224
|
+
'import { getProcessor } from "aac-processors";\n' +
|
|
225
|
+
'const processor = getProcessor(".obf");\n' +
|
|
226
|
+
'```',
|
|
227
|
+
'info'
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
clearResults() {
|
|
232
|
+
document.getElementById('result').style.display = 'none';
|
|
233
|
+
document.getElementById('testResults').style.display = 'none';
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async runAutomatedTests() {
|
|
237
|
+
const results = [];
|
|
238
|
+
results.push('=== AACProcessors Browser Test ===\n');
|
|
239
|
+
results.push('\nℹ️ Library Structure Tests:\n');
|
|
240
|
+
|
|
241
|
+
// Test 1: Check if dist files exist
|
|
242
|
+
results.push('1. Checking build files...');
|
|
243
|
+
try {
|
|
244
|
+
const response = await fetch('../dist/index.browser.js');
|
|
245
|
+
if (response.ok) {
|
|
246
|
+
const content = await response.text();
|
|
247
|
+
const hasExports = content.includes('exports.getProcessor') &&
|
|
248
|
+
content.includes('exports.GridsetProcessor') &&
|
|
249
|
+
content.includes('exports.ObfProcessor');
|
|
250
|
+
|
|
251
|
+
if (hasExports) {
|
|
252
|
+
results.push(' ✅ PASS: Browser build exists with expected exports');
|
|
253
|
+
results.push(` ✅ Size: ${(content.length / 1024).toFixed(2)} KB`);
|
|
254
|
+
} else {
|
|
255
|
+
results.push(' ⚠️ WARNING: Some exports may be missing');
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
results.push(' ❌ FAIL: Browser build not found');
|
|
259
|
+
}
|
|
260
|
+
} catch (error) {
|
|
261
|
+
results.push(` ❌ FAIL: ${error.message}`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Test 2: Check type definitions
|
|
265
|
+
results.push('\n2. Checking TypeScript definitions...');
|
|
266
|
+
try {
|
|
267
|
+
const response = await fetch('../dist/index.browser.d.ts');
|
|
268
|
+
if (response.ok) {
|
|
269
|
+
const content = await response.text();
|
|
270
|
+
const hasTypes = content.includes('getProcessor') &&
|
|
271
|
+
content.includes('DotProcessor') &&
|
|
272
|
+
content.includes('GridsetProcessor');
|
|
273
|
+
|
|
274
|
+
if (hasTypes) {
|
|
275
|
+
results.push(' ✅ PASS: Type definitions exist');
|
|
276
|
+
} else {
|
|
277
|
+
results.push(' ⚠️ WARNING: Some type definitions may be missing');
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
results.push(' ❌ FAIL: Type definitions not found');
|
|
281
|
+
}
|
|
282
|
+
} catch (error) {
|
|
283
|
+
results.push(` ❌ FAIL: ${error.message}`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Test 3: Processor count
|
|
287
|
+
results.push('\n3. Counting processors...');
|
|
288
|
+
try {
|
|
289
|
+
const response = await fetch('../dist/index.browser.js');
|
|
290
|
+
const content = await response.text();
|
|
291
|
+
const processorExports = content.match(/exports\.\w+Processor/g);
|
|
292
|
+
|
|
293
|
+
if (processorExports) {
|
|
294
|
+
const uniqueProcessors = [...new Set(processorExports)];
|
|
295
|
+
results.push(` ✅ Found ${uniqueProcessors.length} processor exports:`);
|
|
296
|
+
uniqueProcessors.forEach(p => results.push(` - ${p.replace('exports.', '')}`));
|
|
297
|
+
}
|
|
298
|
+
} catch (error) {
|
|
299
|
+
results.push(` ❌ FAIL: ${error.message}`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
results.push('\n=== Setup Instructions ===\n');
|
|
303
|
+
results.push('To use AACProcessors in your browser project:\n\n');
|
|
304
|
+
results.push('1. Install with npm: npm install @willwade/aac-processors\n');
|
|
305
|
+
results.push('2. Use a bundler (Vite example):\n');
|
|
306
|
+
results.push(' ```js\n');
|
|
307
|
+
results.push(' // vite.config.js\n');
|
|
308
|
+
results.push(' export default {\n');
|
|
309
|
+
results.push(' resolve: {\n');
|
|
310
|
+
results.push(' alias: {\n');
|
|
311
|
+
results.push(' "aac-processors": path.resolve(__dirname, "node_modules/@willwade/aac-processors/src/index.browser.ts")\n');
|
|
312
|
+
results.push(' }\n');
|
|
313
|
+
results.push(' }\n');
|
|
314
|
+
results.push(' }\n');
|
|
315
|
+
results.push(' ```\n\n');
|
|
316
|
+
results.push('3. Or use a CDN bundle (when available)\n\n');
|
|
317
|
+
results.push('See docs/BROWSER_USAGE.md for complete guide.');
|
|
318
|
+
|
|
319
|
+
this.showTestResults(results.join('\n'));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Initialize when DOM is ready
|
|
324
|
+
if (document.readyState === 'loading') {
|
|
325
|
+
document.addEventListener('DOMContentLoaded', () => new AACProcessorsTest());
|
|
326
|
+
} else {
|
|
327
|
+
new AACProcessorsTest();
|
|
328
|
+
}
|
|
329
|
+
</script>
|
|
330
|
+
</body>
|
|
331
|
+
</html>
|