@willwade/aac-processors 0.2.4 → 0.2.5

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