@optique/core 1.1.2 → 1.1.3

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.
@@ -581,6 +581,35 @@ function createExclusiveState(parentState, index, parser, result) {
581
581
  return require_internal_annotations.annotateFreshArray(parentState, [index, annotatedResult]);
582
582
  }
583
583
  /**
584
+ * Detects a branch result that handled only the global options terminator.
585
+ * Such a result advances the shared parser context, but does not identify
586
+ * which exclusive branch matched.
587
+ * @internal
588
+ */
589
+ function isOptionsTerminatorOnlyResult(context, result) {
590
+ return !context.optionsTerminated && context.buffer[0] === "--" && result.success && result.next.optionsTerminated && result.consumed.length === 1 && result.consumed[0] === "--";
591
+ }
592
+ function isUnselectedBooleanOptionState(state) {
593
+ return state != null && typeof state === "object" && "success" in state && state.success === true && "value" in state && state.value === false;
594
+ }
595
+ function preserveExclusiveStateAfterOptionsTerminator(context, result) {
596
+ const mergedExec = require_execution_context.mergeChildExec(context.exec, result.next.exec);
597
+ return {
598
+ success: true,
599
+ next: {
600
+ ...context,
601
+ buffer: result.next.buffer,
602
+ optionsTerminated: true,
603
+ state: context.state,
604
+ ...mergedExec != null ? {
605
+ exec: mergedExec,
606
+ dependencyRegistry: mergedExec.dependencyRegistry
607
+ } : {}
608
+ },
609
+ consumed: result.consumed
610
+ };
611
+ }
612
+ /**
584
613
  * Creates a complete() method shared by or() and longestMatch().
585
614
  * @internal
586
615
  */
@@ -818,9 +847,15 @@ function or(...args) {
818
847
  let zeroConsumedBranch = null;
819
848
  let zeroConsumedCount = 0;
820
849
  let provisionalConsuming = null;
850
+ let optionsTerminatorResult = null;
821
851
  let provisionalAmbiguous = false;
822
852
  for (const [parser, i] of orderedParsers) {
823
853
  const result = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
854
+ if (isOptionsTerminatorOnlyResult(context, result)) {
855
+ if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
856
+ optionsTerminatorResult ??= result;
857
+ continue;
858
+ }
824
859
  if (result.success && result.consumed.length > 0) {
825
860
  if (result.provisional) {
826
861
  const activeBranchLocked = activeState != null && activeState[1].success && activeState[1].consumed.length > 0;
@@ -1001,6 +1036,7 @@ function or(...args) {
1001
1036
  }
1002
1037
  }
1003
1038
  }
1039
+ if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
1004
1040
  return {
1005
1041
  ...error,
1006
1042
  success: false
@@ -1014,10 +1050,16 @@ function or(...args) {
1014
1050
  let zeroConsumedBranch = null;
1015
1051
  let zeroConsumedCount = 0;
1016
1052
  let provisionalConsuming = null;
1053
+ let optionsTerminatorResult = null;
1017
1054
  let provisionalAmbiguous = false;
1018
1055
  for (const [parser, i] of orderedParsers) {
1019
1056
  const resultOrPromise = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1020
1057
  const result = await resultOrPromise;
1058
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1059
+ if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
1060
+ optionsTerminatorResult ??= result;
1061
+ continue;
1062
+ }
1021
1063
  if (result.success && result.consumed.length > 0) {
1022
1064
  if (result.provisional) {
1023
1065
  const activeBranchLocked = activeState != null && activeState[1].success && activeState[1].consumed.length > 0;
@@ -1200,6 +1242,7 @@ function or(...args) {
1200
1242
  }
1201
1243
  }
1202
1244
  }
1245
+ if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
1203
1246
  return {
1204
1247
  ...error,
1205
1248
  success: false
@@ -1301,82 +1344,122 @@ function createLongestMatch(...args) {
1301
1344
  return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
1302
1345
  })()
1303
1346
  });
1304
- const parseSync = (context) => {
1347
+ const commitLongestMatch = (context, match, optionsTerminatorResult) => {
1348
+ const selectedResult = optionsTerminatorResult == null ? match.result : {
1349
+ ...match.result,
1350
+ next: {
1351
+ ...match.result.next,
1352
+ buffer: optionsTerminatorResult.next.buffer,
1353
+ optionsTerminated: true
1354
+ },
1355
+ consumed: [...optionsTerminatorResult.consumed, ...match.result.consumed]
1356
+ };
1357
+ const parser = parsers[match.index];
1358
+ const mergedExec = require_execution_context.mergeChildExec(context.exec, selectedResult.next.exec);
1359
+ return {
1360
+ success: true,
1361
+ next: {
1362
+ ...context,
1363
+ buffer: selectedResult.next.buffer,
1364
+ optionsTerminated: selectedResult.next.optionsTerminated,
1365
+ state: createExclusiveState(context.state, match.index, parser, selectedResult),
1366
+ ...mergedExec != null ? {
1367
+ exec: mergedExec,
1368
+ dependencyRegistry: mergedExec.dependencyRegistry
1369
+ } : {}
1370
+ },
1371
+ consumed: selectedResult.consumed
1372
+ };
1373
+ };
1374
+ const resolveLongestMatchOptionsTerminator = (context, bestMatch, optionsTerminatorMatches) => {
1375
+ if (optionsTerminatorMatches.length < 1) return null;
1376
+ if (bestMatch != null && bestMatch.consumed > 0) return null;
1377
+ const activeState = normalizeExclusiveState(context.state);
1378
+ if (activeState != null && activeState[1].success && activeState[1].consumed.length > 0) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorMatches[0].result);
1379
+ let selected = bestMatch == null ? null : {
1380
+ match: bestMatch,
1381
+ fromTerminator: false
1382
+ };
1383
+ for (const match of optionsTerminatorMatches) {
1384
+ if (!match.selectedAfterTerminator && (extractRequiredUsage(parsers[match.index].usage).length > 0 || isUnselectedBooleanOptionState(match.result.next.state))) continue;
1385
+ const selectedIsProvisional = selected != null && !!selected.match.result.provisional;
1386
+ const matchIsProvisional = !!match.result.provisional;
1387
+ if (selected == null || selectedIsProvisional && !matchIsProvisional || selectedIsProvisional === matchIsProvisional && match.index < selected.match.index) selected = {
1388
+ match,
1389
+ fromTerminator: true
1390
+ };
1391
+ }
1392
+ if (selected != null) return commitLongestMatch(context, selected.match, selected.fromTerminator ? void 0 : optionsTerminatorMatches[0].result);
1393
+ return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorMatches[0].result);
1394
+ };
1395
+ const parseSyncBranches = (context) => {
1305
1396
  let bestMatch = null;
1397
+ const optionsTerminatorMatches = [];
1306
1398
  let error = getInitialError(context);
1307
1399
  const activeState = normalizeExclusiveState(context.state);
1308
1400
  for (let i = 0; i < syncParsers.length; i++) {
1309
1401
  const parser = syncParsers[i];
1310
- const result = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1402
+ const childContext = withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
1403
+ const result = parser.parse(childContext);
1404
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1405
+ optionsTerminatorMatches.push({
1406
+ index: i,
1407
+ result,
1408
+ consumed: 1,
1409
+ ...normalizeExclusiveState(result.next.state) != null ? { selectedAfterTerminator: true } : {}
1410
+ });
1411
+ continue;
1412
+ }
1311
1413
  if (result.success) {
1312
1414
  const consumed = context.buffer.length - result.next.buffer.length;
1313
1415
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
1314
1416
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
1315
1417
  index: i,
1316
- parser,
1317
1418
  result,
1318
1419
  consumed
1319
1420
  };
1320
1421
  } else if (error.consumed < result.consumed) error = result;
1321
1422
  }
1322
- if (bestMatch && bestMatch.result.success) {
1323
- const mergedExec = require_execution_context.mergeChildExec(context.exec, bestMatch.result.next.exec);
1324
- return {
1325
- success: true,
1326
- next: {
1327
- ...context,
1328
- buffer: bestMatch.result.next.buffer,
1329
- optionsTerminated: bestMatch.result.next.optionsTerminated,
1330
- state: createExclusiveState(context.state, bestMatch.index, bestMatch.parser, bestMatch.result),
1331
- ...mergedExec != null ? {
1332
- exec: mergedExec,
1333
- dependencyRegistry: mergedExec.dependencyRegistry
1334
- } : {}
1335
- },
1336
- consumed: bestMatch.result.consumed
1337
- };
1338
- }
1423
+ const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
1424
+ if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
1425
+ if (bestMatch != null) return commitLongestMatch(context, bestMatch);
1339
1426
  return {
1340
1427
  ...error,
1341
1428
  success: false
1342
1429
  };
1343
1430
  };
1344
- const parseAsync = async (context) => {
1431
+ const parseAsyncBranches = async (context) => {
1345
1432
  let bestMatch = null;
1433
+ const optionsTerminatorMatches = [];
1346
1434
  let error = getInitialError(context);
1347
1435
  const activeState = normalizeExclusiveState(context.state);
1348
1436
  for (let i = 0; i < parsers.length; i++) {
1349
1437
  const parser = parsers[i];
1350
- const resultOrPromise = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1438
+ const childContext = withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
1439
+ const resultOrPromise = parser.parse(childContext);
1351
1440
  const result = await resultOrPromise;
1441
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1442
+ optionsTerminatorMatches.push({
1443
+ index: i,
1444
+ result,
1445
+ consumed: 1,
1446
+ ...normalizeExclusiveState(result.next.state) != null ? { selectedAfterTerminator: true } : {}
1447
+ });
1448
+ continue;
1449
+ }
1352
1450
  if (result.success) {
1353
1451
  const consumed = context.buffer.length - result.next.buffer.length;
1354
1452
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
1355
1453
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
1356
1454
  index: i,
1357
- parser,
1358
1455
  result,
1359
1456
  consumed
1360
1457
  };
1361
1458
  } else if (error.consumed < result.consumed) error = result;
1362
1459
  }
1363
- if (bestMatch && bestMatch.result.success) {
1364
- const mergedExec = require_execution_context.mergeChildExec(context.exec, bestMatch.result.next.exec);
1365
- return {
1366
- success: true,
1367
- next: {
1368
- ...context,
1369
- buffer: bestMatch.result.next.buffer,
1370
- optionsTerminated: bestMatch.result.next.optionsTerminated,
1371
- state: createExclusiveState(context.state, bestMatch.index, bestMatch.parser, bestMatch.result),
1372
- ...mergedExec != null ? {
1373
- exec: mergedExec,
1374
- dependencyRegistry: mergedExec.dependencyRegistry
1375
- } : {}
1376
- },
1377
- consumed: bestMatch.result.consumed
1378
- };
1379
- }
1460
+ const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
1461
+ if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
1462
+ if (bestMatch != null) return commitLongestMatch(context, bestMatch);
1380
1463
  return {
1381
1464
  ...error,
1382
1465
  success: false
@@ -1399,7 +1482,7 @@ function createLongestMatch(...args) {
1399
1482
  return extractExclusivePhase2Seed(parsers, state, exec, combinedMode);
1400
1483
  },
1401
1484
  parse(context) {
1402
- return require_mode_dispatch.dispatchByMode(combinedMode, () => parseSync(context), () => parseAsync(context));
1485
+ return require_mode_dispatch.dispatchByMode(combinedMode, () => parseSyncBranches(context), () => parseAsyncBranches(context));
1403
1486
  },
1404
1487
  getSuggestRuntimeNodes(state, path) {
1405
1488
  return getExclusiveSuggestRuntimeNodes(parsers, state, path);
@@ -581,6 +581,35 @@ function createExclusiveState(parentState, index, parser, result) {
581
581
  return annotateFreshArray(parentState, [index, annotatedResult]);
582
582
  }
583
583
  /**
584
+ * Detects a branch result that handled only the global options terminator.
585
+ * Such a result advances the shared parser context, but does not identify
586
+ * which exclusive branch matched.
587
+ * @internal
588
+ */
589
+ function isOptionsTerminatorOnlyResult(context, result) {
590
+ return !context.optionsTerminated && context.buffer[0] === "--" && result.success && result.next.optionsTerminated && result.consumed.length === 1 && result.consumed[0] === "--";
591
+ }
592
+ function isUnselectedBooleanOptionState(state) {
593
+ return state != null && typeof state === "object" && "success" in state && state.success === true && "value" in state && state.value === false;
594
+ }
595
+ function preserveExclusiveStateAfterOptionsTerminator(context, result) {
596
+ const mergedExec = mergeChildExec(context.exec, result.next.exec);
597
+ return {
598
+ success: true,
599
+ next: {
600
+ ...context,
601
+ buffer: result.next.buffer,
602
+ optionsTerminated: true,
603
+ state: context.state,
604
+ ...mergedExec != null ? {
605
+ exec: mergedExec,
606
+ dependencyRegistry: mergedExec.dependencyRegistry
607
+ } : {}
608
+ },
609
+ consumed: result.consumed
610
+ };
611
+ }
612
+ /**
584
613
  * Creates a complete() method shared by or() and longestMatch().
585
614
  * @internal
586
615
  */
@@ -818,9 +847,15 @@ function or(...args) {
818
847
  let zeroConsumedBranch = null;
819
848
  let zeroConsumedCount = 0;
820
849
  let provisionalConsuming = null;
850
+ let optionsTerminatorResult = null;
821
851
  let provisionalAmbiguous = false;
822
852
  for (const [parser, i] of orderedParsers) {
823
853
  const result = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
854
+ if (isOptionsTerminatorOnlyResult(context, result)) {
855
+ if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
856
+ optionsTerminatorResult ??= result;
857
+ continue;
858
+ }
824
859
  if (result.success && result.consumed.length > 0) {
825
860
  if (result.provisional) {
826
861
  const activeBranchLocked = activeState != null && activeState[1].success && activeState[1].consumed.length > 0;
@@ -1001,6 +1036,7 @@ function or(...args) {
1001
1036
  }
1002
1037
  }
1003
1038
  }
1039
+ if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
1004
1040
  return {
1005
1041
  ...error,
1006
1042
  success: false
@@ -1014,10 +1050,16 @@ function or(...args) {
1014
1050
  let zeroConsumedBranch = null;
1015
1051
  let zeroConsumedCount = 0;
1016
1052
  let provisionalConsuming = null;
1053
+ let optionsTerminatorResult = null;
1017
1054
  let provisionalAmbiguous = false;
1018
1055
  for (const [parser, i] of orderedParsers) {
1019
1056
  const resultOrPromise = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1020
1057
  const result = await resultOrPromise;
1058
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1059
+ if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
1060
+ optionsTerminatorResult ??= result;
1061
+ continue;
1062
+ }
1021
1063
  if (result.success && result.consumed.length > 0) {
1022
1064
  if (result.provisional) {
1023
1065
  const activeBranchLocked = activeState != null && activeState[1].success && activeState[1].consumed.length > 0;
@@ -1200,6 +1242,7 @@ function or(...args) {
1200
1242
  }
1201
1243
  }
1202
1244
  }
1245
+ if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
1203
1246
  return {
1204
1247
  ...error,
1205
1248
  success: false
@@ -1301,82 +1344,122 @@ function createLongestMatch(...args) {
1301
1344
  return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
1302
1345
  })()
1303
1346
  });
1304
- const parseSync = (context) => {
1347
+ const commitLongestMatch = (context, match, optionsTerminatorResult) => {
1348
+ const selectedResult = optionsTerminatorResult == null ? match.result : {
1349
+ ...match.result,
1350
+ next: {
1351
+ ...match.result.next,
1352
+ buffer: optionsTerminatorResult.next.buffer,
1353
+ optionsTerminated: true
1354
+ },
1355
+ consumed: [...optionsTerminatorResult.consumed, ...match.result.consumed]
1356
+ };
1357
+ const parser = parsers[match.index];
1358
+ const mergedExec = mergeChildExec(context.exec, selectedResult.next.exec);
1359
+ return {
1360
+ success: true,
1361
+ next: {
1362
+ ...context,
1363
+ buffer: selectedResult.next.buffer,
1364
+ optionsTerminated: selectedResult.next.optionsTerminated,
1365
+ state: createExclusiveState(context.state, match.index, parser, selectedResult),
1366
+ ...mergedExec != null ? {
1367
+ exec: mergedExec,
1368
+ dependencyRegistry: mergedExec.dependencyRegistry
1369
+ } : {}
1370
+ },
1371
+ consumed: selectedResult.consumed
1372
+ };
1373
+ };
1374
+ const resolveLongestMatchOptionsTerminator = (context, bestMatch, optionsTerminatorMatches) => {
1375
+ if (optionsTerminatorMatches.length < 1) return null;
1376
+ if (bestMatch != null && bestMatch.consumed > 0) return null;
1377
+ const activeState = normalizeExclusiveState(context.state);
1378
+ if (activeState != null && activeState[1].success && activeState[1].consumed.length > 0) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorMatches[0].result);
1379
+ let selected = bestMatch == null ? null : {
1380
+ match: bestMatch,
1381
+ fromTerminator: false
1382
+ };
1383
+ for (const match of optionsTerminatorMatches) {
1384
+ if (!match.selectedAfterTerminator && (extractRequiredUsage(parsers[match.index].usage).length > 0 || isUnselectedBooleanOptionState(match.result.next.state))) continue;
1385
+ const selectedIsProvisional = selected != null && !!selected.match.result.provisional;
1386
+ const matchIsProvisional = !!match.result.provisional;
1387
+ if (selected == null || selectedIsProvisional && !matchIsProvisional || selectedIsProvisional === matchIsProvisional && match.index < selected.match.index) selected = {
1388
+ match,
1389
+ fromTerminator: true
1390
+ };
1391
+ }
1392
+ if (selected != null) return commitLongestMatch(context, selected.match, selected.fromTerminator ? void 0 : optionsTerminatorMatches[0].result);
1393
+ return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorMatches[0].result);
1394
+ };
1395
+ const parseSyncBranches = (context) => {
1305
1396
  let bestMatch = null;
1397
+ const optionsTerminatorMatches = [];
1306
1398
  let error = getInitialError(context);
1307
1399
  const activeState = normalizeExclusiveState(context.state);
1308
1400
  for (let i = 0; i < syncParsers.length; i++) {
1309
1401
  const parser = syncParsers[i];
1310
- const result = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1402
+ const childContext = withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
1403
+ const result = parser.parse(childContext);
1404
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1405
+ optionsTerminatorMatches.push({
1406
+ index: i,
1407
+ result,
1408
+ consumed: 1,
1409
+ ...normalizeExclusiveState(result.next.state) != null ? { selectedAfterTerminator: true } : {}
1410
+ });
1411
+ continue;
1412
+ }
1311
1413
  if (result.success) {
1312
1414
  const consumed = context.buffer.length - result.next.buffer.length;
1313
1415
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
1314
1416
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
1315
1417
  index: i,
1316
- parser,
1317
1418
  result,
1318
1419
  consumed
1319
1420
  };
1320
1421
  } else if (error.consumed < result.consumed) error = result;
1321
1422
  }
1322
- if (bestMatch && bestMatch.result.success) {
1323
- const mergedExec = mergeChildExec(context.exec, bestMatch.result.next.exec);
1324
- return {
1325
- success: true,
1326
- next: {
1327
- ...context,
1328
- buffer: bestMatch.result.next.buffer,
1329
- optionsTerminated: bestMatch.result.next.optionsTerminated,
1330
- state: createExclusiveState(context.state, bestMatch.index, bestMatch.parser, bestMatch.result),
1331
- ...mergedExec != null ? {
1332
- exec: mergedExec,
1333
- dependencyRegistry: mergedExec.dependencyRegistry
1334
- } : {}
1335
- },
1336
- consumed: bestMatch.result.consumed
1337
- };
1338
- }
1423
+ const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
1424
+ if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
1425
+ if (bestMatch != null) return commitLongestMatch(context, bestMatch);
1339
1426
  return {
1340
1427
  ...error,
1341
1428
  success: false
1342
1429
  };
1343
1430
  };
1344
- const parseAsync = async (context) => {
1431
+ const parseAsyncBranches = async (context) => {
1345
1432
  let bestMatch = null;
1433
+ const optionsTerminatorMatches = [];
1346
1434
  let error = getInitialError(context);
1347
1435
  const activeState = normalizeExclusiveState(context.state);
1348
1436
  for (let i = 0; i < parsers.length; i++) {
1349
1437
  const parser = parsers[i];
1350
- const resultOrPromise = parser.parse(withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1438
+ const childContext = withChildContext$1(context, i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
1439
+ const resultOrPromise = parser.parse(childContext);
1351
1440
  const result = await resultOrPromise;
1441
+ if (isOptionsTerminatorOnlyResult(context, result)) {
1442
+ optionsTerminatorMatches.push({
1443
+ index: i,
1444
+ result,
1445
+ consumed: 1,
1446
+ ...normalizeExclusiveState(result.next.state) != null ? { selectedAfterTerminator: true } : {}
1447
+ });
1448
+ continue;
1449
+ }
1352
1450
  if (result.success) {
1353
1451
  const consumed = context.buffer.length - result.next.buffer.length;
1354
1452
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
1355
1453
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
1356
1454
  index: i,
1357
- parser,
1358
1455
  result,
1359
1456
  consumed
1360
1457
  };
1361
1458
  } else if (error.consumed < result.consumed) error = result;
1362
1459
  }
1363
- if (bestMatch && bestMatch.result.success) {
1364
- const mergedExec = mergeChildExec(context.exec, bestMatch.result.next.exec);
1365
- return {
1366
- success: true,
1367
- next: {
1368
- ...context,
1369
- buffer: bestMatch.result.next.buffer,
1370
- optionsTerminated: bestMatch.result.next.optionsTerminated,
1371
- state: createExclusiveState(context.state, bestMatch.index, bestMatch.parser, bestMatch.result),
1372
- ...mergedExec != null ? {
1373
- exec: mergedExec,
1374
- dependencyRegistry: mergedExec.dependencyRegistry
1375
- } : {}
1376
- },
1377
- consumed: bestMatch.result.consumed
1378
- };
1379
- }
1460
+ const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
1461
+ if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
1462
+ if (bestMatch != null) return commitLongestMatch(context, bestMatch);
1380
1463
  return {
1381
1464
  ...error,
1382
1465
  success: false
@@ -1399,7 +1482,7 @@ function createLongestMatch(...args) {
1399
1482
  return extractExclusivePhase2Seed(parsers, state, exec, combinedMode);
1400
1483
  },
1401
1484
  parse(context) {
1402
- return dispatchByMode(combinedMode, () => parseSync(context), () => parseAsync(context));
1485
+ return dispatchByMode(combinedMode, () => parseSyncBranches(context), () => parseAsyncBranches(context));
1403
1486
  },
1404
1487
  getSuggestRuntimeNodes(state, path) {
1405
1488
  return getExclusiveSuggestRuntimeNodes(parsers, state, path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -200,7 +200,7 @@
200
200
  "fast-check": "^4.7.0",
201
201
  "tsdown": "^0.13.0",
202
202
  "typescript": "^5.8.3",
203
- "@optique/env": "1.1.2"
203
+ "@optique/env": "1.1.3"
204
204
  },
205
205
  "scripts": {
206
206
  "build": "tsdown",