@willwade/aac-processors 0.2.20 → 0.3.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 +1 -0
- package/dist/browser/index.browser.js +17 -1
- package/dist/browser/processors/gotalkNow/nsKeyed.js +108 -0
- package/dist/browser/processors/gotalkNowProcessor.js +538 -0
- package/dist/browser/processors/gridsetProcessor.js +2 -2
- package/dist/browser/processors/obfProcessor.js +17 -6
- package/dist/browser/validation/gridsetValidator.js +54 -198
- package/dist/cli/index.js +3 -0
- package/dist/core/analyze.js +5 -0
- package/dist/core/treeStructure.d.ts +12 -0
- package/dist/gotalkNow.d.ts +6 -0
- package/dist/gotalkNow.js +11 -0
- package/dist/index.browser.d.ts +1 -0
- package/dist/index.browser.js +19 -2
- package/dist/index.node.d.ts +1 -0
- package/dist/index.node.js +6 -1
- package/dist/processors/gotalkNow/nsKeyed.d.ts +27 -0
- package/dist/processors/gotalkNow/nsKeyed.js +112 -0
- package/dist/processors/gotalkNowProcessor.d.ts +51 -0
- package/dist/processors/gotalkNowProcessor.js +544 -0
- package/dist/processors/gridsetProcessor.js +2 -2
- package/dist/processors/index.d.ts +1 -0
- package/dist/processors/index.js +3 -1
- package/dist/processors/obfProcessor.js +17 -6
- package/dist/validation/gridsetValidator.d.ts +8 -15
- package/dist/validation/gridsetValidator.js +54 -198
- package/package.json +5 -1
|
@@ -147,14 +147,21 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
147
147
|
const pageId = boardData?.id ? String(boardData.id) : _boardPath?.split(/[/\\]/).pop() || '';
|
|
148
148
|
const images = boardData.images;
|
|
149
149
|
const buttons = await Promise.all(sourceButtons.map(async (btn) => {
|
|
150
|
+
// Resolve load_board.path to a board ID (strip .obf suffix if present).
|
|
151
|
+
// The OBF spec says load_board.path is a file path, but internally we
|
|
152
|
+
// store the board ID as targetPageId.
|
|
153
|
+
const rawPath = btn.load_board?.path;
|
|
154
|
+
const boardRef = rawPath
|
|
155
|
+
? rawPath.replace(/\.obf$/i, '').replace(/\.obz$/i, '')
|
|
156
|
+
: undefined;
|
|
150
157
|
const semanticAction = btn.load_board
|
|
151
158
|
? {
|
|
152
159
|
category: treeStructure_1.AACSemanticCategory.NAVIGATION,
|
|
153
160
|
intent: treeStructure_1.AACSemanticIntent.NAVIGATE_TO,
|
|
154
|
-
targetId:
|
|
161
|
+
targetId: boardRef,
|
|
155
162
|
fallback: {
|
|
156
163
|
type: 'NAVIGATE',
|
|
157
|
-
targetPageId:
|
|
164
|
+
targetPageId: boardRef,
|
|
158
165
|
},
|
|
159
166
|
}
|
|
160
167
|
: {
|
|
@@ -202,7 +209,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
202
209
|
resolvedImageEntry: resolvedImage,
|
|
203
210
|
parameters: Object.keys(buttonParameters).length > 0 ? buttonParameters : undefined,
|
|
204
211
|
semanticAction,
|
|
205
|
-
targetPageId:
|
|
212
|
+
targetPageId: boardRef,
|
|
206
213
|
semantic_id: btn.semantic_id, // Extract semantic_id if present
|
|
207
214
|
});
|
|
208
215
|
}));
|
|
@@ -621,7 +628,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
621
628
|
vocalization: button.message || button.label,
|
|
622
629
|
load_board: button.semanticAction?.intent === treeStructure_1.AACSemanticIntent.NAVIGATE_TO && button.targetPageId
|
|
623
630
|
? {
|
|
624
|
-
path: button.targetPageId,
|
|
631
|
+
path: this.getPageFilename(button.targetPageId, metadata),
|
|
625
632
|
}
|
|
626
633
|
: undefined,
|
|
627
634
|
background_color: button.style?.backgroundColor,
|
|
@@ -691,7 +698,9 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
691
698
|
});
|
|
692
699
|
const manifest = {
|
|
693
700
|
format: OBF_FORMAT_VERSION,
|
|
694
|
-
root: tree.metadata.defaultHomePageId
|
|
701
|
+
root: tree.metadata.defaultHomePageId
|
|
702
|
+
? this.getPageFilename(tree.metadata.defaultHomePageId, tree.metadata)
|
|
703
|
+
: undefined,
|
|
695
704
|
paths: {
|
|
696
705
|
boards: Object.fromEntries(Object.entries(tree.pages).map(([id, page]) => [
|
|
697
706
|
id,
|
|
@@ -758,7 +767,9 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
758
767
|
if (Object.keys(tree.pages).length > 0) {
|
|
759
768
|
const manifest = {
|
|
760
769
|
format: OBF_FORMAT_VERSION,
|
|
761
|
-
root: tree.metadata.defaultHomePageId
|
|
770
|
+
root: tree.metadata.defaultHomePageId
|
|
771
|
+
? this.getPageFilename(tree.metadata.defaultHomePageId, tree.metadata)
|
|
772
|
+
: undefined,
|
|
762
773
|
paths: {
|
|
763
774
|
boards: Object.fromEntries(Object.entries(tree.pages).map(([id, page]) => [
|
|
764
775
|
id,
|
|
@@ -23,27 +23,20 @@ export declare class GridsetValidator extends BaseValidator {
|
|
|
23
23
|
*/
|
|
24
24
|
private isZip;
|
|
25
25
|
/**
|
|
26
|
-
* Validate a single
|
|
26
|
+
* Validate a single grid.xml file (exploded/non-zip format)
|
|
27
27
|
*/
|
|
28
28
|
private validateSingleXml;
|
|
29
29
|
/**
|
|
30
30
|
* Validate a ZIP archive (.gridset)
|
|
31
|
+
*
|
|
32
|
+
* Real Grid 3 archives do NOT contain a top-level gridset.xml. The required
|
|
33
|
+
* structure is: Settings0/settings.xml + FileMap.xml + Grids/<name>/grid.xml
|
|
34
|
+
* (+ optional Styles, images, thumbnails).
|
|
31
35
|
*/
|
|
32
36
|
private validateZipArchive;
|
|
33
37
|
/**
|
|
34
|
-
* Validate
|
|
38
|
+
* Validate a real Grid 3 <Grid> element (from grid.xml).
|
|
39
|
+
* Checks for GridGuid, Cells, and basic cell structure.
|
|
35
40
|
*/
|
|
36
|
-
private
|
|
37
|
-
/**
|
|
38
|
-
* Validate a single page
|
|
39
|
-
*/
|
|
40
|
-
private validatePage;
|
|
41
|
-
/**
|
|
42
|
-
* Validate a single cell
|
|
43
|
-
*/
|
|
44
|
-
private validateCell;
|
|
45
|
-
/**
|
|
46
|
-
* Validate color format (Grid3 uses ARGB format)
|
|
47
|
-
*/
|
|
48
|
-
private isValidGrid3Color;
|
|
41
|
+
private validateGridStructure;
|
|
49
42
|
}
|
|
@@ -55,12 +55,12 @@ class GridsetValidator extends baseValidator_1.BaseValidator {
|
|
|
55
55
|
if (name.endsWith('.gridset') || name.endsWith('.gridsetx')) {
|
|
56
56
|
return true;
|
|
57
57
|
}
|
|
58
|
-
// Try to parse as XML and check for
|
|
58
|
+
// Try to parse as XML and check for a Grid 3 <Grid> root element
|
|
59
59
|
try {
|
|
60
60
|
const contentStr = typeof content === 'string' ? content : (0, io_1.decodeText)((0, io_1.toUint8Array)(content));
|
|
61
61
|
const parser = new xml2js.Parser();
|
|
62
62
|
const result = await parser.parseStringPromise(contentStr);
|
|
63
|
-
return result && (result.
|
|
63
|
+
return !!(result && (result.Grid || result.grid));
|
|
64
64
|
}
|
|
65
65
|
catch {
|
|
66
66
|
return false;
|
|
@@ -104,7 +104,7 @@ class GridsetValidator extends baseValidator_1.BaseValidator {
|
|
|
104
104
|
return content[0] === 0x50 && content[1] === 0x4b && content[2] === 0x03 && content[3] === 0x04;
|
|
105
105
|
}
|
|
106
106
|
/**
|
|
107
|
-
* Validate a single
|
|
107
|
+
* Validate a single grid.xml file (exploded/non-zip format)
|
|
108
108
|
*/
|
|
109
109
|
async validateSingleXml(content, filename, _filesize) {
|
|
110
110
|
let xmlObj = null;
|
|
@@ -120,49 +120,57 @@ class GridsetValidator extends baseValidator_1.BaseValidator {
|
|
|
120
120
|
});
|
|
121
121
|
if (!xmlObj)
|
|
122
122
|
return;
|
|
123
|
-
await this.add_check('xml_structure', '
|
|
124
|
-
if (!xmlObj.
|
|
125
|
-
this.err('missing root
|
|
123
|
+
await this.add_check('xml_structure', 'Grid root element', async () => {
|
|
124
|
+
if (!xmlObj.Grid && !xmlObj.grid) {
|
|
125
|
+
this.err('missing root Grid element', true);
|
|
126
126
|
}
|
|
127
127
|
});
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
130
|
-
await this.
|
|
128
|
+
const grid = xmlObj.Grid || xmlObj.grid;
|
|
129
|
+
if (grid) {
|
|
130
|
+
await this.validateGridStructure(grid, filename);
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
134
|
* Validate a ZIP archive (.gridset)
|
|
135
|
+
*
|
|
136
|
+
* Real Grid 3 archives do NOT contain a top-level gridset.xml. The required
|
|
137
|
+
* structure is: Settings0/settings.xml + FileMap.xml + Grids/<name>/grid.xml
|
|
138
|
+
* (+ optional Styles, images, thumbnails).
|
|
135
139
|
*/
|
|
136
|
-
async validateZipArchive(content,
|
|
140
|
+
async validateZipArchive(content, _filename, _filesize) {
|
|
137
141
|
const zip = await this._options.zipAdapter(content);
|
|
138
142
|
const entries = zip.listFiles();
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (
|
|
143
|
-
this.err('
|
|
143
|
+
// --- Required: at least one Grids/<name>/grid.xml ---
|
|
144
|
+
const gridEntries = entries.filter((e) => /^Grids\/.+\/grid\.xml$/i.test(e));
|
|
145
|
+
await this.add_check('grid_xml_presence', 'Grids/*/grid.xml presence', async () => {
|
|
146
|
+
if (gridEntries.length === 0) {
|
|
147
|
+
this.err('No Grids/<name>/grid.xml found in archive', true);
|
|
144
148
|
}
|
|
145
|
-
|
|
149
|
+
});
|
|
150
|
+
// Validate the <Grid> structure of each grid.xml (sample up to 5)
|
|
151
|
+
for (let i = 0; i < Math.min(gridEntries.length, 5); i++) {
|
|
152
|
+
const entry = gridEntries[i];
|
|
153
|
+
await this.add_check(`grid_xml[${entry}]`, `grid structure: ${entry}`, async () => {
|
|
146
154
|
try {
|
|
147
|
-
const
|
|
155
|
+
const gridXml = await zip.readFile(entry);
|
|
148
156
|
const parser = new xml2js.Parser();
|
|
149
|
-
const xmlObj = await parser.parseStringPromise(
|
|
150
|
-
const
|
|
151
|
-
if (!
|
|
152
|
-
this.err(
|
|
157
|
+
const xmlObj = await parser.parseStringPromise(gridXml);
|
|
158
|
+
const grid = xmlObj.Grid || xmlObj.grid;
|
|
159
|
+
if (!grid) {
|
|
160
|
+
this.err(`${entry}: missing root <Grid> element`);
|
|
153
161
|
}
|
|
154
162
|
else {
|
|
155
|
-
await this.
|
|
163
|
+
await this.validateGridStructure(grid, entry);
|
|
156
164
|
}
|
|
157
165
|
}
|
|
158
166
|
catch (e) {
|
|
159
|
-
this.err(
|
|
167
|
+
this.err(`${entry}: failed to parse XML: ${e.message}`);
|
|
160
168
|
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
//
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// --- Recommended: Settings0/settings.xml ---
|
|
164
172
|
await this.add_check('settings_xml_presence', 'settings.xml presence', async () => {
|
|
165
|
-
const settingsEntry = entries.find((e) => e.toLowerCase() === 'settings.xml');
|
|
173
|
+
const settingsEntry = entries.find((e) => e.toLowerCase() === 'settings.xml' || e.toLowerCase().endsWith('/settings.xml'));
|
|
166
174
|
if (!settingsEntry) {
|
|
167
175
|
this.warn('Missing settings.xml in archive (required for full metadata)');
|
|
168
176
|
}
|
|
@@ -187,188 +195,36 @@ class GridsetValidator extends baseValidator_1.BaseValidator {
|
|
|
187
195
|
}
|
|
188
196
|
}
|
|
189
197
|
});
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// Check for required elements
|
|
196
|
-
await this.add_check('gridset_id', 'gridset id', async () => {
|
|
197
|
-
const id = gridset.$.id || gridset.$.Id;
|
|
198
|
-
if (!id) {
|
|
199
|
-
this.warn('gridset should have an id attribute');
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
await this.add_check('gridset_name', 'gridset name', async () => {
|
|
203
|
-
const name = gridset.$.name || gridset.$.Name || gridset.name?.[0];
|
|
204
|
-
if (!name) {
|
|
205
|
-
this.warn('gridset should have a name attribute or element');
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
// Check for pages
|
|
209
|
-
await this.add_check('pages', 'pages element', async () => {
|
|
210
|
-
if (!gridset.pages && !gridset.Pages) {
|
|
211
|
-
this.err('gridset must have a pages element');
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
const pages = gridset.pages || gridset.Pages;
|
|
215
|
-
if (!pages[0] || !Array.isArray(pages[0].page)) {
|
|
216
|
-
this.warn('pages should contain at least one page element');
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
// Validate individual pages
|
|
221
|
-
const pages = gridset.pages?.[0] || gridset.Pages?.[0];
|
|
222
|
-
if (pages && Array.isArray(pages.page)) {
|
|
223
|
-
await this.add_check('page_count', 'page count', async () => {
|
|
224
|
-
if (pages.page.length === 0) {
|
|
225
|
-
this.err('gridset must contain at least one page');
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
for (let i = 0; i < Math.min(pages.page.length, 10); i++) {
|
|
229
|
-
// Limit to first 10 pages to avoid excessive validation
|
|
230
|
-
const page = pages.page[i];
|
|
231
|
-
await this.validatePage(page, i);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
// Check for fixedCellSize
|
|
235
|
-
await this.add_check('fixed_cell_size', 'fixedCellSize element', async () => {
|
|
236
|
-
const fixedSize = gridset.fixedCellSize || gridset.FixedCellSize;
|
|
237
|
-
if (!fixedSize) {
|
|
238
|
-
this.warn('gridset should have a fixedCellSize element for consistency');
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
// Validate fixedCellSize structure
|
|
242
|
-
const size = fixedSize[0];
|
|
243
|
-
if (size) {
|
|
244
|
-
const width = size.$.width || size.$.Width;
|
|
245
|
-
const height = size.$.height || size.$.Height;
|
|
246
|
-
if (!width || !height) {
|
|
247
|
-
this.warn('fixedCellSize should have both width and height attributes');
|
|
248
|
-
}
|
|
249
|
-
else if (isNaN(parseInt(width)) || isNaN(parseInt(height))) {
|
|
250
|
-
this.err('fixedCellSize width and height must be valid numbers');
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
// Check for styles
|
|
256
|
-
await this.add_check('styles', 'styles element', async () => {
|
|
257
|
-
const styles = gridset.styles || gridset.Styles;
|
|
258
|
-
if (!styles) {
|
|
259
|
-
this.warn('gridset should have a styles element for consistent formatting');
|
|
198
|
+
// --- Recommended: FileMap.xml (used for image resolution) ---
|
|
199
|
+
await this.add_check('filemap_presence', 'FileMap.xml presence', async () => {
|
|
200
|
+
const filemapEntry = entries.find((e) => e.toLowerCase() === 'filemap.xml');
|
|
201
|
+
if (!filemapEntry) {
|
|
202
|
+
this.warn('Missing FileMap.xml in archive (used for image resolution)');
|
|
260
203
|
}
|
|
261
204
|
});
|
|
262
205
|
}
|
|
263
206
|
/**
|
|
264
|
-
* Validate a
|
|
207
|
+
* Validate a real Grid 3 <Grid> element (from grid.xml).
|
|
208
|
+
* Checks for GridGuid, Cells, and basic cell structure.
|
|
265
209
|
*/
|
|
266
|
-
async
|
|
267
|
-
await this.add_check(
|
|
268
|
-
const
|
|
269
|
-
if (!
|
|
270
|
-
this.
|
|
210
|
+
async validateGridStructure(grid, label) {
|
|
211
|
+
await this.add_check(`${label}_gridguid`, 'GridGuid', async () => {
|
|
212
|
+
const guid = grid.GridGuid || grid.gridGuid;
|
|
213
|
+
if (!guid) {
|
|
214
|
+
this.warn(`${label}: missing <GridGuid> element`);
|
|
271
215
|
}
|
|
272
216
|
});
|
|
273
|
-
await this.add_check(
|
|
274
|
-
const
|
|
275
|
-
if (!name) {
|
|
276
|
-
this.warn(`page ${index} should have a name`);
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
// Check for cells
|
|
280
|
-
await this.add_check(`page[${index}]_cells`, `page ${index} cells`, async () => {
|
|
281
|
-
const cells = page.cells || page.Cells;
|
|
217
|
+
await this.add_check(`${label}_cells`, 'Cells element', async () => {
|
|
218
|
+
const cells = grid.Cells || grid.cells;
|
|
282
219
|
if (!cells) {
|
|
283
|
-
this.warn(
|
|
220
|
+
this.warn(`${label}: missing <Cells> element`);
|
|
221
|
+
return;
|
|
284
222
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
this.warn(`page ${index} should contain at least one cell`);
|
|
289
|
-
}
|
|
223
|
+
const cellArray = cells[0]?.Cell || cells[0]?.cell;
|
|
224
|
+
if (!cellArray || !Array.isArray(cellArray) || cellArray.length === 0) {
|
|
225
|
+
this.warn(`${label}: <Cells> should contain at least one <Cell>`);
|
|
290
226
|
}
|
|
291
227
|
});
|
|
292
|
-
// Validate cells if present
|
|
293
|
-
const cells = page.cells?.[0] || page.Cells?.[0];
|
|
294
|
-
if (cells) {
|
|
295
|
-
const cellArray = cells.cell || cells.Cell;
|
|
296
|
-
if (Array.isArray(cellArray) && cellArray.length > 0) {
|
|
297
|
-
// Sample a few cells to validate
|
|
298
|
-
const sampleSize = Math.min(cellArray.length, 5);
|
|
299
|
-
for (let i = 0; i < sampleSize; i++) {
|
|
300
|
-
await this.validateCell(cellArray[i], index, i);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Validate a single cell
|
|
307
|
-
*/
|
|
308
|
-
async validateCell(cell, pageIdx, cellIdx) {
|
|
309
|
-
await this.add_check(`page[${pageIdx}]_cell[${cellIdx}]_id`, `cell id`, async () => {
|
|
310
|
-
const id = cell.$.id || cell.$.Id;
|
|
311
|
-
if (!id) {
|
|
312
|
-
this.warn(`cell ${cellIdx} on page ${pageIdx} is missing id attribute`);
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
await this.add_check(`page[${pageIdx}]_cell[${cellIdx}]_content`, `cell content`, async () => {
|
|
316
|
-
const label = cell.$.label || cell.$.Label;
|
|
317
|
-
const image = cell.$.image || cell.$.Image;
|
|
318
|
-
if (!label && !image) {
|
|
319
|
-
this.warn(`cell ${cellIdx} on page ${pageIdx} should have a label or image`);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
// Validate scan block number (Grid 3 attribute)
|
|
323
|
-
await this.add_check(`page[${pageIdx}]_cell[${cellIdx}]_scanblock`, `cell scan block`, async () => {
|
|
324
|
-
const scanBlock = cell.$.scanBlock || cell.$.ScanBlock;
|
|
325
|
-
if (scanBlock !== undefined) {
|
|
326
|
-
const blockNum = parseInt(scanBlock, 10);
|
|
327
|
-
if (isNaN(blockNum) || blockNum < 1 || blockNum > 8) {
|
|
328
|
-
this.err(`cell ${cellIdx} on page ${pageIdx} has invalid scanBlock value: ${scanBlock} (must be 1-8)`, false);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
// Check for color attributes
|
|
333
|
-
const backgroundColor = cell.$.backgroundColor || cell.$.BackgroundColor;
|
|
334
|
-
const _color = cell.$.color || cell.$.Color;
|
|
335
|
-
if (backgroundColor) {
|
|
336
|
-
await this.add_check(`page[${pageIdx}]_cell[${cellIdx}]_bg_color`, `cell background color`, async () => {
|
|
337
|
-
// Grid3 colors can be in various formats: named colors, hex, ARGB
|
|
338
|
-
// We just check it's not empty
|
|
339
|
-
if (backgroundColor.length === 0) {
|
|
340
|
-
this.warn(`cell ${cellIdx} has empty background color`);
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
// Check for valid jump references
|
|
345
|
-
const jump = cell.$.jump || cell.$.Jump;
|
|
346
|
-
if (jump) {
|
|
347
|
-
await this.add_check(`page[${pageIdx}]_cell[${cellIdx}]_jump`, `cell jump reference`, async () => {
|
|
348
|
-
if (typeof jump !== 'string' || jump.length === 0) {
|
|
349
|
-
this.warn(`cell ${cellIdx} has invalid jump reference`);
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Validate color format (Grid3 uses ARGB format)
|
|
356
|
-
*/
|
|
357
|
-
isValidGrid3Color(color) {
|
|
358
|
-
if (!color || color.length === 0)
|
|
359
|
-
return false;
|
|
360
|
-
// Named colors are valid
|
|
361
|
-
if (/^[a-zA-Z]+$/.test(color))
|
|
362
|
-
return true;
|
|
363
|
-
// ARGB format: #AARRGGBB or #RRGGBB
|
|
364
|
-
if (color.startsWith('#')) {
|
|
365
|
-
return color.length === 7 || color.length === 9;
|
|
366
|
-
}
|
|
367
|
-
// RGB format: rgb(r,g,b) or rgba(r,g,b,a)
|
|
368
|
-
if (color.startsWith('rgb')) {
|
|
369
|
-
return true; // Simplified check
|
|
370
|
-
}
|
|
371
|
-
return false;
|
|
372
228
|
}
|
|
373
229
|
}
|
|
374
230
|
exports.GridsetValidator = GridsetValidator;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@willwade/aac-processors",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
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",
|
|
@@ -60,6 +60,10 @@
|
|
|
60
60
|
"types": "./dist/astericsGrid.d.ts",
|
|
61
61
|
"default": "./dist/astericsGrid.js"
|
|
62
62
|
},
|
|
63
|
+
"./gotalkNow": {
|
|
64
|
+
"types": "./dist/gotalkNow.d.ts",
|
|
65
|
+
"default": "./dist/gotalkNow.js"
|
|
66
|
+
},
|
|
63
67
|
"./translation": {
|
|
64
68
|
"types": "./dist/translation.d.ts",
|
|
65
69
|
"default": "./dist/translation.js"
|