@willwade/aac-processors 0.2.4 → 0.2.6

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.
@@ -936,7 +936,7 @@ class GridsetProcessor extends BaseProcessor {
936
936
  }
937
937
  // Parse all command types from Grid3 and create semantic actions
938
938
  let semanticAction;
939
- let legacyAction = null;
939
+ let _legacyAction = null;
940
940
  // infer action type implicitly from commands; no explicit enum needed
941
941
  let navigationTarget;
942
942
  let detectedCommands = []; // Store detected command metadata
@@ -1062,114 +1062,125 @@ class GridsetProcessor extends BaseProcessor {
1062
1062
  if (gridTarget) {
1063
1063
  // Resolve grid name to grid ID for navigation
1064
1064
  const targetGridId = gridNameToIdMap.get(gridTarget) || gridTarget;
1065
+ // Always set navigationTarget even if another command already
1066
+ // set semanticAction (e.g. Jump.SetBookmark + Jump.To).
1065
1067
  navigationTarget = targetGridId;
1066
- // navigate action
1068
+ // Only set semanticAction if not already set by a prior command
1069
+ if (!semanticAction) {
1070
+ semanticAction = {
1071
+ category: AACSemanticCategory.NAVIGATION,
1072
+ intent: AACSemanticIntent.NAVIGATE_TO,
1073
+ targetId: targetGridId,
1074
+ platformData: {
1075
+ grid3: {
1076
+ commandId,
1077
+ parameters: { grid: gridTarget },
1078
+ },
1079
+ },
1080
+ fallback: {
1081
+ type: 'NAVIGATE',
1082
+ targetPageId: targetGridId,
1083
+ },
1084
+ };
1085
+ _legacyAction = {
1086
+ type: 'NAVIGATE',
1087
+ targetPageId: targetGridId,
1088
+ };
1089
+ }
1090
+ }
1091
+ break;
1092
+ }
1093
+ case 'Jump.Back':
1094
+ if (!semanticAction) {
1067
1095
  semanticAction = {
1068
1096
  category: AACSemanticCategory.NAVIGATION,
1069
- intent: AACSemanticIntent.NAVIGATE_TO,
1070
- targetId: targetGridId,
1097
+ intent: AACSemanticIntent.GO_BACK,
1071
1098
  platformData: {
1072
1099
  grid3: {
1073
1100
  commandId,
1074
- parameters: { grid: gridTarget },
1101
+ parameters: {},
1075
1102
  },
1076
1103
  },
1077
1104
  fallback: {
1078
- type: 'NAVIGATE',
1079
- targetPageId: targetGridId,
1105
+ type: 'ACTION',
1106
+ message: 'Go back',
1080
1107
  },
1081
1108
  };
1082
- legacyAction = {
1083
- type: 'NAVIGATE',
1084
- targetPageId: targetGridId,
1109
+ _legacyAction = {
1110
+ type: 'GO_BACK',
1085
1111
  };
1086
1112
  }
1087
1113
  break;
1088
- }
1089
- case 'Jump.Back':
1090
- // action
1091
- semanticAction = {
1092
- category: AACSemanticCategory.NAVIGATION,
1093
- intent: AACSemanticIntent.GO_BACK,
1094
- platformData: {
1095
- grid3: {
1096
- commandId,
1097
- parameters: {},
1098
- },
1099
- },
1100
- fallback: {
1101
- type: 'ACTION',
1102
- message: 'Go back',
1103
- },
1104
- };
1105
- legacyAction = {
1106
- type: 'GO_BACK',
1107
- };
1108
- break;
1109
1114
  case 'Jump.Home':
1110
1115
  case 'Jump.SetHome':
1111
- // action
1112
- navigationTarget = tree.rootId || undefined;
1113
- semanticAction = {
1114
- category: AACSemanticCategory.NAVIGATION,
1115
- intent: AACSemanticIntent.GO_HOME,
1116
- targetId: tree.rootId || undefined,
1117
- platformData: {
1118
- grid3: {
1119
- commandId,
1120
- parameters: {},
1116
+ if (!navigationTarget)
1117
+ navigationTarget = tree.rootId || undefined;
1118
+ if (!semanticAction) {
1119
+ semanticAction = {
1120
+ category: AACSemanticCategory.NAVIGATION,
1121
+ intent: AACSemanticIntent.GO_HOME,
1122
+ targetId: tree.rootId || undefined,
1123
+ platformData: {
1124
+ grid3: {
1125
+ commandId,
1126
+ parameters: {},
1127
+ },
1121
1128
  },
1122
- },
1123
- fallback: {
1124
- type: 'ACTION',
1125
- message: 'Go home',
1126
- },
1127
- };
1128
- legacyAction = {
1129
- type: 'GO_HOME',
1130
- };
1129
+ fallback: {
1130
+ type: 'ACTION',
1131
+ message: 'Go home',
1132
+ },
1133
+ };
1134
+ _legacyAction = {
1135
+ type: 'GO_HOME',
1136
+ };
1137
+ }
1131
1138
  break;
1132
1139
  case 'Jump.ToKeyboard': {
1133
1140
  // Navigate to the set keyboard if we found one in settings
1134
1141
  const keyboardGridName = tree.keyboardGridName;
1135
1142
  const keyboardPageId = gridNameToIdMap.get(keyboardGridName);
1136
- if (keyboardPageId) {
1143
+ if (keyboardPageId && !navigationTarget) {
1137
1144
  navigationTarget = keyboardPageId;
1138
1145
  }
1139
- semanticAction = {
1140
- category: AACSemanticCategory.NAVIGATION,
1141
- intent: AACSemanticIntent.GO_HOME, // Close enough to 'navigation to keyboard'
1142
- targetId: keyboardPageId,
1143
- platformData: {
1144
- grid3: {
1145
- commandId,
1146
- parameters: {},
1146
+ if (!semanticAction) {
1147
+ semanticAction = {
1148
+ category: AACSemanticCategory.NAVIGATION,
1149
+ intent: AACSemanticIntent.GO_HOME, // Close enough to 'navigation to keyboard'
1150
+ targetId: keyboardPageId,
1151
+ platformData: {
1152
+ grid3: {
1153
+ commandId,
1154
+ parameters: {},
1155
+ },
1147
1156
  },
1148
- },
1149
- fallback: {
1150
- type: 'NAVIGATE',
1151
- targetPageId: keyboardPageId,
1152
- },
1153
- };
1157
+ fallback: {
1158
+ type: 'NAVIGATE',
1159
+ targetPageId: keyboardPageId,
1160
+ },
1161
+ };
1162
+ }
1154
1163
  break;
1155
1164
  }
1156
1165
  case 'Action.InsertTextAndSpeak': {
1157
- const insertText = getParam('text');
1158
- semanticAction = {
1159
- category: AACSemanticCategory.COMMUNICATION,
1160
- intent: AACSemanticIntent.SPEAK_IMMEDIATE,
1161
- text: insertText,
1162
- platformData: {
1163
- grid3: {
1164
- commandId,
1165
- parameters: { text: insertText },
1166
+ if (!semanticAction) {
1167
+ const insertText = getParam('text');
1168
+ semanticAction = {
1169
+ category: AACSemanticCategory.COMMUNICATION,
1170
+ intent: AACSemanticIntent.SPEAK_IMMEDIATE,
1171
+ text: insertText,
1172
+ platformData: {
1173
+ grid3: {
1174
+ commandId,
1175
+ parameters: { text: insertText },
1176
+ },
1166
1177
  },
1167
- },
1168
- fallback: {
1169
- type: 'SPEAK',
1170
- message: insertText,
1171
- },
1172
- };
1178
+ fallback: {
1179
+ type: 'SPEAK',
1180
+ message: insertText,
1181
+ },
1182
+ };
1183
+ }
1173
1184
  break;
1174
1185
  }
1175
1186
  case 'Prediction.PredictThis': {
@@ -1202,193 +1213,207 @@ class GridsetProcessor extends BaseProcessor {
1202
1213
  // speak
1203
1214
  const speakUnit = getParam('unit');
1204
1215
  const moveCaret = getParam('movecaret');
1205
- semanticAction = {
1206
- category: AACSemanticCategory.COMMUNICATION,
1207
- intent: AACSemanticIntent.SPEAK_TEXT,
1208
- platformData: {
1209
- grid3: {
1210
- commandId,
1211
- parameters: {
1212
- unit: speakUnit,
1213
- movecaret: moveCaret,
1216
+ if (!semanticAction) {
1217
+ semanticAction = {
1218
+ category: AACSemanticCategory.COMMUNICATION,
1219
+ intent: AACSemanticIntent.SPEAK_TEXT,
1220
+ platformData: {
1221
+ grid3: {
1222
+ commandId,
1223
+ parameters: {
1224
+ unit: speakUnit,
1225
+ movecaret: moveCaret,
1226
+ },
1214
1227
  },
1215
1228
  },
1216
- },
1217
- fallback: {
1229
+ fallback: {
1230
+ type: 'SPEAK',
1231
+ message: 'Speak text',
1232
+ },
1233
+ };
1234
+ _legacyAction = {
1218
1235
  type: 'SPEAK',
1219
- message: 'Speak text',
1220
- },
1221
- };
1222
- legacyAction = {
1223
- type: 'SPEAK',
1224
- unit: speakUnit,
1225
- moveCaret: moveCaret ? parseInt(String(moveCaret)) : undefined,
1226
- };
1236
+ unit: speakUnit,
1237
+ moveCaret: moveCaret ? parseInt(String(moveCaret)) : undefined,
1238
+ };
1239
+ }
1227
1240
  break;
1228
1241
  }
1229
1242
  case 'Action.InsertText': {
1230
1243
  const insertText = getParam('text');
1231
1244
  const posParam = getParam('pos');
1245
+ // Always extract POS even if semanticAction is already set
1232
1246
  if (posParam) {
1233
1247
  buttonPos = posParam;
1234
1248
  }
1235
- semanticAction = {
1236
- category: AACSemanticCategory.COMMUNICATION,
1237
- intent: AACSemanticIntent.INSERT_TEXT,
1238
- text: insertText,
1239
- platformData: {
1240
- grid3: {
1241
- commandId,
1242
- parameters: { text: insertText, pos: posParam },
1249
+ if (!semanticAction) {
1250
+ semanticAction = {
1251
+ category: AACSemanticCategory.COMMUNICATION,
1252
+ intent: AACSemanticIntent.INSERT_TEXT,
1253
+ text: insertText,
1254
+ platformData: {
1255
+ grid3: {
1256
+ commandId,
1257
+ parameters: { text: insertText, pos: posParam },
1258
+ },
1243
1259
  },
1244
- },
1245
- fallback: {
1246
- type: 'SPEAK',
1247
- message: insertText,
1248
- },
1249
- };
1250
- legacyAction = {
1251
- type: 'INSERT_TEXT',
1252
- text: insertText,
1253
- };
1260
+ fallback: {
1261
+ type: 'SPEAK',
1262
+ message: insertText,
1263
+ },
1264
+ };
1265
+ _legacyAction = {
1266
+ type: 'INSERT_TEXT',
1267
+ text: insertText,
1268
+ };
1269
+ }
1254
1270
  break;
1255
1271
  }
1256
1272
  case 'Action.DeleteWord':
1257
- // action
1258
- semanticAction = {
1259
- category: AACSemanticCategory.TEXT_EDITING,
1260
- intent: AACSemanticIntent.DELETE_WORD,
1261
- platformData: {
1262
- grid3: {
1263
- commandId,
1264
- parameters: {},
1273
+ if (!semanticAction) {
1274
+ semanticAction = {
1275
+ category: AACSemanticCategory.TEXT_EDITING,
1276
+ intent: AACSemanticIntent.DELETE_WORD,
1277
+ platformData: {
1278
+ grid3: {
1279
+ commandId,
1280
+ parameters: {},
1281
+ },
1265
1282
  },
1266
- },
1267
- fallback: {
1268
- type: 'ACTION',
1269
- message: 'Delete word',
1270
- },
1271
- };
1272
- legacyAction = {
1273
- type: 'DELETE_WORD',
1274
- };
1283
+ fallback: {
1284
+ type: 'ACTION',
1285
+ message: 'Delete word',
1286
+ },
1287
+ };
1288
+ _legacyAction = {
1289
+ type: 'DELETE_WORD',
1290
+ };
1291
+ }
1275
1292
  break;
1276
1293
  case 'Action.DeleteLetter':
1277
- // action
1278
- semanticAction = {
1279
- category: AACSemanticCategory.TEXT_EDITING,
1280
- intent: AACSemanticIntent.DELETE_CHARACTER,
1281
- platformData: {
1282
- grid3: {
1283
- commandId,
1284
- parameters: {},
1294
+ if (!semanticAction) {
1295
+ semanticAction = {
1296
+ category: AACSemanticCategory.TEXT_EDITING,
1297
+ intent: AACSemanticIntent.DELETE_CHARACTER,
1298
+ platformData: {
1299
+ grid3: {
1300
+ commandId,
1301
+ parameters: {},
1302
+ },
1285
1303
  },
1286
- },
1287
- fallback: {
1288
- type: 'ACTION',
1289
- message: 'Delete character',
1290
- },
1291
- };
1292
- legacyAction = {
1293
- type: 'DELETE_CHARACTER',
1294
- };
1304
+ fallback: {
1305
+ type: 'ACTION',
1306
+ message: 'Delete character',
1307
+ },
1308
+ };
1309
+ _legacyAction = {
1310
+ type: 'DELETE_CHARACTER',
1311
+ };
1312
+ }
1295
1313
  break;
1296
1314
  case 'Action.Clear':
1297
1315
  // action
1298
- semanticAction = {
1299
- category: AACSemanticCategory.TEXT_EDITING,
1300
- intent: AACSemanticIntent.CLEAR_TEXT,
1301
- platformData: {
1302
- grid3: {
1303
- commandId,
1304
- parameters: {},
1316
+ if (!semanticAction) {
1317
+ semanticAction = {
1318
+ category: AACSemanticCategory.TEXT_EDITING,
1319
+ intent: AACSemanticIntent.CLEAR_TEXT,
1320
+ platformData: {
1321
+ grid3: {
1322
+ commandId,
1323
+ parameters: {},
1324
+ },
1305
1325
  },
1306
- },
1307
- fallback: {
1308
- type: 'ACTION',
1309
- message: 'Clear text',
1310
- },
1311
- };
1312
- legacyAction = {
1313
- type: 'CLEAR_TEXT',
1314
- };
1326
+ fallback: {
1327
+ type: 'ACTION',
1328
+ message: 'Clear text',
1329
+ },
1330
+ };
1331
+ _legacyAction = {
1332
+ type: 'CLEAR_TEXT',
1333
+ };
1334
+ }
1315
1335
  break;
1316
1336
  case 'Action.Letter': {
1317
1337
  // action
1318
1338
  const letter = getParam('letter');
1319
- semanticAction = {
1320
- category: AACSemanticCategory.TEXT_EDITING,
1321
- intent: AACSemanticIntent.INSERT_TEXT,
1322
- text: letter,
1323
- platformData: {
1324
- grid3: {
1325
- commandId,
1326
- parameters: { letter },
1339
+ if (!semanticAction) {
1340
+ semanticAction = {
1341
+ category: AACSemanticCategory.TEXT_EDITING,
1342
+ intent: AACSemanticIntent.INSERT_TEXT,
1343
+ text: letter,
1344
+ platformData: {
1345
+ grid3: {
1346
+ commandId,
1347
+ parameters: { letter },
1348
+ },
1327
1349
  },
1328
- },
1329
- fallback: {
1330
- type: 'ACTION',
1331
- message: letter,
1332
- },
1333
- };
1334
- legacyAction = {
1335
- type: 'INSERT_LETTER',
1336
- letter,
1337
- };
1350
+ fallback: {
1351
+ type: 'ACTION',
1352
+ message: letter,
1353
+ },
1354
+ };
1355
+ _legacyAction = {
1356
+ type: 'INSERT_LETTER',
1357
+ letter,
1358
+ };
1359
+ }
1338
1360
  break;
1339
1361
  }
1340
1362
  case 'Settings.RestAll':
1341
1363
  // action
1342
- semanticAction = {
1343
- category: AACSemanticCategory.CUSTOM,
1344
- intent: AACSemanticIntent.PLATFORM_SPECIFIC,
1345
- platformData: {
1346
- grid3: {
1347
- commandId,
1348
- parameters: {
1349
- indicatorenabled: getParam('indicatorenabled'),
1350
- action: getParam('action'),
1364
+ if (!semanticAction) {
1365
+ semanticAction = {
1366
+ category: AACSemanticCategory.CUSTOM,
1367
+ intent: AACSemanticIntent.PLATFORM_SPECIFIC,
1368
+ platformData: {
1369
+ grid3: {
1370
+ commandId,
1371
+ parameters: {
1372
+ indicatorenabled: getParam('indicatorenabled'),
1373
+ action: getParam('action'),
1374
+ },
1351
1375
  },
1352
1376
  },
1353
- },
1354
- fallback: {
1355
- type: 'ACTION',
1356
- message: 'Settings action',
1357
- },
1358
- };
1359
- legacyAction = {
1360
- type: 'SETTINGS',
1361
- indicatorEnabled: getParam('indicatorenabled') === '1',
1362
- settingsAction: getParam('action'),
1363
- };
1377
+ fallback: {
1378
+ type: 'ACTION',
1379
+ message: 'Settings action',
1380
+ },
1381
+ };
1382
+ _legacyAction = {
1383
+ type: 'SETTINGS',
1384
+ indicatorEnabled: getParam('indicatorenabled') === '1',
1385
+ settingsAction: getParam('action'),
1386
+ };
1387
+ }
1364
1388
  break;
1365
1389
  case 'AutoContent.Activate':
1366
1390
  // action
1367
- semanticAction = {
1368
- category: AACSemanticCategory.CUSTOM,
1369
- intent: AACSemanticIntent.PLATFORM_SPECIFIC,
1370
- platformData: {
1371
- grid3: {
1372
- commandId,
1373
- parameters: {
1374
- autocontenttype: getParam('autocontenttype'),
1391
+ if (!semanticAction) {
1392
+ semanticAction = {
1393
+ category: AACSemanticCategory.CUSTOM,
1394
+ intent: AACSemanticIntent.PLATFORM_SPECIFIC,
1395
+ platformData: {
1396
+ grid3: {
1397
+ commandId,
1398
+ parameters: {
1399
+ autocontenttype: getParam('autocontenttype'),
1400
+ },
1375
1401
  },
1376
1402
  },
1377
- },
1378
- fallback: {
1379
- type: 'ACTION',
1380
- message: 'Auto content',
1381
- },
1382
- };
1383
- legacyAction = {
1384
- type: 'AUTO_CONTENT',
1385
- autoContentType: getParam('autocontenttype'),
1386
- };
1403
+ fallback: {
1404
+ type: 'ACTION',
1405
+ message: 'Auto content',
1406
+ },
1407
+ };
1408
+ _legacyAction = {
1409
+ type: 'AUTO_CONTENT',
1410
+ autoContentType: getParam('autocontenttype'),
1411
+ };
1412
+ }
1387
1413
  break;
1388
1414
  default:
1389
1415
  // Unknown command - preserve as generic action
1390
- if (commandId) {
1391
- // action
1416
+ if (commandId && !semanticAction) {
1392
1417
  const allParams = Object.fromEntries(paramArr.map((p) => [p.Key || p.key, p['#text']]));
1393
1418
  semanticAction = {
1394
1419
  category: AACSemanticCategory.CUSTOM,
@@ -1404,16 +1429,13 @@ class GridsetProcessor extends BaseProcessor {
1404
1429
  message: 'Unknown command',
1405
1430
  },
1406
1431
  };
1407
- legacyAction = {
1408
- type: 'SPEAK',
1409
- parameters: { commandId, ...allParams },
1410
- };
1432
+ // legacy action not needed for unknown commands
1411
1433
  }
1412
1434
  break;
1413
1435
  }
1414
- // Use first recognized command
1415
- if (semanticAction || legacyAction)
1416
- break;
1436
+ // Continue processing remaining commands so that navigation
1437
+ // targets (Jump.To) are discovered even when a non-navigation
1438
+ // command (e.g. Jump.SetBookmark, Action.InsertText) appears first.
1417
1439
  }
1418
1440
  }
1419
1441
  // Create default semantic action if none was created from commands